diff options
Diffstat (limited to 'vcl/source/gdi')
54 files changed, 54012 insertions, 0 deletions
diff --git a/vcl/source/gdi/alpha.cxx b/vcl/source/gdi/alpha.cxx new file mode 100644 index 000000000000..9e00d0044787 --- /dev/null +++ b/vcl/source/gdi/alpha.cxx @@ -0,0 +1,353 @@ +/************************************************************************* + * + * $RCSfile: alpha.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_ALPHA_CXX + +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _SV_BMPACC_HXX +#include <bmpacc.hxx> +#endif +#ifndef _SV_COLOR_HXX +#include <color.hxx> +#endif +#ifndef _SV_ALPHA_HXX +#include <alpha.hxx> +#endif + +// ------------- +// - AlphaMask - +// ------------- + +AlphaMask::AlphaMask() +{ +} + +// ----------------------------------------------------------------------------- + +AlphaMask::AlphaMask( const Bitmap& rBitmap ) : + Bitmap( rBitmap ) +{ + if( !!rBitmap ) + Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS ); +} + +// ----------------------------------------------------------------------------- + +AlphaMask::AlphaMask( const AlphaMask& rAlphaMask ) : + Bitmap( rAlphaMask ) +{ +} + +// ----------------------------------------------------------------------------- + +AlphaMask::AlphaMask( const Size& rSizePixel, BYTE* pEraseTransparency ) : + Bitmap( rSizePixel, 8, &Bitmap::GetGreyPalette( 256 ) ) +{ + if( pEraseTransparency ) + Bitmap::Erase( Color( *pEraseTransparency, *pEraseTransparency, *pEraseTransparency ) ); +} + +// ----------------------------------------------------------------------------- + +AlphaMask::~AlphaMask() +{ +} + +// ----------------------------------------------------------------------------- + +AlphaMask& AlphaMask::operator=( const Bitmap& rBitmap ) +{ + *(Bitmap*) this = rBitmap; + + if( !!rBitmap ) + Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS ); + + return *this; +} + +// ----------------------------------------------------------------------------- + +const Bitmap& AlphaMask::ImplGetBitmap() const +{ + return( (const Bitmap&) *this ); +} + +// ----------------------------------------------------------------------------- + +void AlphaMask::ImplSetBitmap( const Bitmap& rBitmap ) +{ + *(Bitmap*) this = rBitmap; +} + +// ----------------------------------------------------------------------------- + +BOOL AlphaMask::Crop( const Rectangle& rRectPixel ) +{ + return Bitmap::Crop( rRectPixel ); +} + +// ----------------------------------------------------------------------------- + +BOOL AlphaMask::Expand( ULONG nDX, ULONG nDY, BYTE* pInitTransparency ) +{ + Color aColor; + + if( pInitTransparency ) + aColor = Color( *pInitTransparency, *pInitTransparency, *pInitTransparency ); + + return Bitmap::Expand( nDX, nDY, pInitTransparency ? &aColor : NULL ); +} + +// ----------------------------------------------------------------------------- + +BOOL AlphaMask::Erase( BYTE cTransparency ) +{ + return Bitmap::Erase( Color( cTransparency, cTransparency, cTransparency ) ); +} + +// ----------------------------------------------------------------------------- + +BOOL AlphaMask::Invert() +{ + BitmapWriteAccess* pAcc = AcquireWriteAccess(); + BOOL bRet = FALSE; + + if( pAcc && pAcc->GetBitCount() == 8 ) + { + BitmapColor aCol( 0 ); + const long nWidth = pAcc->Width(), nHeight = pAcc->Height(); + BYTE* pMap = new BYTE[ 256 ]; + + for( long i = 0; i < 256; i++ ) + pMap[ i ] = ~(BYTE) i; + + for( long nY = 0L; nY < nHeight; nY++ ) + { + for( long nX = 0L; nX < nWidth; nX++ ) + { + aCol.SetIndex( pMap[ pAcc->GetPixel( nY, nX ).GetIndex() ] ); + pAcc->SetPixel( nY, nX, aCol ); + } + } + + delete[] pMap; + bRet = TRUE; + } + + if( pAcc ) + ReleaseAccess( pAcc ); + + return bRet; +} + +// ----------------------------------------------------------------------------- + +BOOL AlphaMask::Mirror( ULONG nMirrorFlags ) +{ + return Bitmap::Mirror( nMirrorFlags ); +} + +// ----------------------------------------------------------------------------- + +BOOL AlphaMask::Scale( const Size& rNewSize, ULONG nScaleFlag ) +{ + BOOL bRet = Bitmap::Scale( rNewSize, nScaleFlag ); + + if( bRet && ( nScaleFlag == BMP_SCALE_INTERPOLATE ) ) + Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS ); + + return bRet; +} + +// ----------------------------------------------------------------------------- + +BOOL AlphaMask::Scale( const double& rScaleX, const double& rScaleY, ULONG nScaleFlag ) +{ + BOOL bRet = Bitmap::Scale( rScaleX, rScaleY, nScaleFlag ); + + if( bRet && ( nScaleFlag == BMP_SCALE_INTERPOLATE ) ) + Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS ); + + return bRet; +} + +// ----------------------------------------------------------------------------- + +BOOL AlphaMask::Rotate( long nAngle10, BYTE cFillTransparency ) +{ + return Bitmap::Rotate( nAngle10, Color( cFillTransparency, cFillTransparency, cFillTransparency ) ); +} + +// ----------------------------------------------------------------------------- + +BOOL AlphaMask::Replace( const Bitmap& rMask, BYTE cReplaceTransparency ) +{ + BitmapReadAccess* pMaskAcc = ( (Bitmap&) rMask ).AcquireReadAccess(); + BitmapWriteAccess* pAcc = AcquireWriteAccess(); + BOOL bRet = FALSE; + + if( pMaskAcc && pAcc ) + { + const BitmapColor aReplace( cReplaceTransparency ); + const long nWidth = Min( pMaskAcc->Width(), pAcc->Width() ); + const long nHeight = Min( pMaskAcc->Height(), pAcc->Height() ); + const BitmapColor aMaskWhite( pMaskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); + + for( long nY = 0L; nY < nHeight; nY++ ) + for( long nX = 0L; nX < nWidth; nX++ ) + if( pMaskAcc->GetPixel( nY, nX ) == aMaskWhite ) + pAcc->SetPixel( nY, nX, aReplace ); + } + + ( (Bitmap&) rMask ).ReleaseAccess( pMaskAcc ); + ReleaseAccess( pAcc ); + + return bRet; +} + +// ----------------------------------------------------------------------------- + +BOOL AlphaMask::Replace( BYTE cSearchTransparency, BYTE cReplaceTransparency, ULONG nTol ) +{ + BitmapWriteAccess* pAcc = AcquireWriteAccess(); + BOOL bRet = FALSE; + + DBG_ASSERT( !nTol, "AlphaMask::Replace: nTol not used yet" ); + + if( pAcc && pAcc->GetBitCount() == 8 ) + { + const long nWidth = pAcc->Width(), nHeight = pAcc->Height(); + + if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) + { + for( long nY = 0L; nY < nHeight; nY++ ) + { + Scanline pScan = pAcc->GetScanline( nY ); + + for( long nX = 0L; nX < nWidth; nX++, pScan++ ) + { + if( *pScan == cSearchTransparency ) + *pScan = cReplaceTransparency; + } + } + } + else + { + BitmapColor aReplace( cReplaceTransparency ); + + for( long nY = 0L; nY < nHeight; nY++ ) + { + for( long nX = 0L; nX < nWidth; nX++ ) + { + if( pAcc->GetPixel( nY, nX ).GetIndex() == cSearchTransparency ) + pAcc->SetPixel( nY, nX, aReplace ); + } + } + } + + bRet = TRUE; + } + + if( pAcc ) + ReleaseAccess( pAcc ); + + return bRet; +} + +// ----------------------------------------------------------------------------- + +BOOL AlphaMask::Replace( BYTE* pSearchTransparencies, BYTE* pReplaceTransparencies, + ULONG nColorCount, ULONG* pTols ) +{ + Color* pSearchColors = new Color[ nColorCount ]; + Color* pReplaceColors = new Color[ nColorCount ]; + BOOL bRet; + + for( ULONG i = 0; i < nColorCount; i++ ) + { + const BYTE cSearchTransparency = pSearchTransparencies[ i ]; + const BYTE cReplaceTransparency = pReplaceTransparencies[ i ]; + + pSearchColors[ i ] = Color( cSearchTransparency, cSearchTransparency, cSearchTransparency ); + pReplaceColors[ i ] = Color( cReplaceTransparency, cReplaceTransparency, cReplaceTransparency ); + } + + bRet = Bitmap::Replace( pSearchColors, pReplaceColors, nColorCount, pTols ) && + Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS ); + + delete[] pSearchColors; + delete[] pReplaceColors; + + return bRet; +} + +// ----------------------------------------------------------------------------- + +void AlphaMask::ReleaseAccess( BitmapReadAccess* pAccess ) +{ + if( pAccess ) + { + Bitmap::ReleaseAccess( pAccess ); + Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS ); + } +} diff --git a/vcl/source/gdi/animate.cxx b/vcl/source/gdi/animate.cxx new file mode 100644 index 000000000000..2a1c7e26ad2b --- /dev/null +++ b/vcl/source/gdi/animate.cxx @@ -0,0 +1,992 @@ +/************************************************************************* + * + * $RCSfile: animate.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_ANIMATE_CXX +#define ENABLE_BYTESTRING_STREAM_OPERATORS + +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif +#ifndef _RTL_CRC_H_ +#include <rtl/crc.h> +#endif +#ifndef _SV_VIRDEV_HXX +#include <virdev.hxx> +#endif +#ifndef _SV_WINDOW_HXX +#include <window.hxx> +#endif +#ifndef _SV_IMPANMVW_HXX +#include <impanmvw.hxx> +#endif +#ifndef _SV_ANIMATE_HXX +#include <animate.hxx> +#endif + +DBG_NAME( Animation ); + +// ----------- +// - Defines - +// ----------- + +#define MIN_TIMEOUT 2L +#define INC_TIMEOUT 0L + +// ----------- +// - statics - +// ----------- + +ULONG Animation::mnAnimCount = 0UL; + +// ------------------- +// - AnimationBitmap - +// ------------------- + +ULONG AnimationBitmap::GetChecksum() const +{ + sal_uInt32 nCrc = aBmpEx.GetChecksum(); + SVBT32 aBT32; + + LongToSVBT32( aPosPix.X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( aPosPix.Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( aSizePix.Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( aSizePix.Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( (long) nWait, aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( (long) eDisposal, aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( (long) bUserInput, aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + return nCrc; +} + +// ------------- +// - Animation - +// ------------- + +Animation::Animation() : + mbIsInAnimation ( FALSE ), + meCycleMode ( CYCLE_NORMAL ), + mnLoopCount ( 0 ), + mnLoops ( 0 ), + mnPos ( 0 ), + mbLoopTerminated ( FALSE ), + mbIsWaiting ( FALSE ) +{ + DBG_CTOR( Animation, NULL ); + maTimer.SetTimeoutHdl( LINK( this, Animation, ImplTimeoutHdl ) ); + mpViewList = new List; +} + +// ----------------------------------------------------------------------- + +Animation::Animation( const Animation& rAnimation ) : + maGlobalSize ( rAnimation.maGlobalSize ), + maBitmapEx ( rAnimation.maBitmapEx ), + meCycleMode ( rAnimation.meCycleMode ), + mbIsInAnimation ( FALSE ), + mnLoopCount ( rAnimation.mnLoopCount ), + mnPos ( rAnimation.mnPos ), + mbLoopTerminated ( rAnimation.mbLoopTerminated ), + mbIsWaiting ( rAnimation.mbIsWaiting ) +{ + DBG_CTOR( Animation, NULL ); + + for( long i = 0, nCount = rAnimation.maList.Count(); i < nCount; i++ ) + maList.Insert( new AnimationBitmap( *(AnimationBitmap*) rAnimation.maList.GetObject( i ) ), LIST_APPEND ); + + maTimer.SetTimeoutHdl( LINK( this, Animation, ImplTimeoutHdl ) ); + mpViewList = new List; + mnLoops = mbLoopTerminated ? 0 : mnLoopCount; +} + +// ----------------------------------------------------------------------- + +Animation::~Animation() +{ + DBG_DTOR( Animation, NULL ); + + if( mbIsInAnimation ) + Stop(); + + for( void* pStepBmp = maList.First(); pStepBmp; pStepBmp = maList.Next() ) + delete (AnimationBitmap*) pStepBmp; + + for( void* pView = mpViewList->First(); pView; pView = mpViewList->Next() ) + delete (ImplAnimView*) pView; + + delete mpViewList; +} + +// ----------------------------------------------------------------------- + +Animation& Animation::operator=( const Animation& rAnimation ) +{ + Clear(); + + for( long i = 0, nCount = rAnimation.maList.Count(); i < nCount; i++ ) + maList.Insert( new AnimationBitmap( *(AnimationBitmap*) rAnimation.maList.GetObject( i ) ), LIST_APPEND ); + + maGlobalSize = rAnimation.maGlobalSize; + maBitmapEx = rAnimation.maBitmapEx; + meCycleMode = rAnimation.meCycleMode; + mnLoopCount = rAnimation.mnLoopCount; + mnPos = rAnimation.mnPos; + mbLoopTerminated = rAnimation.mbLoopTerminated; + mbIsWaiting = rAnimation.mbIsWaiting; + mnLoops = mbLoopTerminated ? 0 : mnLoopCount; + + return *this; +} + +// ----------------------------------------------------------------------- + +BOOL Animation::operator==( const Animation& rAnimation ) const +{ + const ULONG nCount = maList.Count(); + BOOL bRet = FALSE; + + if( rAnimation.maList.Count() == nCount && + rAnimation.maBitmapEx == maBitmapEx && + rAnimation.maGlobalSize == maGlobalSize && + rAnimation.meCycleMode == meCycleMode ) + { + bRet = TRUE; + + for( ULONG n = 0; n < nCount; n++ ) + { + if( ( *(AnimationBitmap*) maList.GetObject( n ) ) != + ( *(AnimationBitmap*) rAnimation.maList.GetObject( n ) ) ) + { + bRet = FALSE; + break; + } + } + } + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL Animation::IsEqual( const Animation& rAnimation ) const +{ + const ULONG nCount = maList.Count(); + BOOL bRet = FALSE; + + if( rAnimation.maList.Count() == nCount && + rAnimation.maBitmapEx.IsEqual( maBitmapEx ) && + rAnimation.maGlobalSize == maGlobalSize && + rAnimation.meCycleMode == meCycleMode ) + { + for( ULONG n = 0; ( n < nCount ) && !bRet; n++ ) + if( ( (AnimationBitmap*) maList.GetObject( n ) )->IsEqual( *(AnimationBitmap*) rAnimation.maList.GetObject( n ) ) ) + bRet = TRUE; + } + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL Animation::IsEmpty() const +{ + return( maBitmapEx.IsEmpty() && !maList.Count() ); +} + +// ------------------------------------------------------------------ + +void Animation::SetEmpty() +{ + maTimer.Stop(); + mbIsInAnimation = FALSE; + maGlobalSize = Size(); + maBitmapEx.SetEmpty(); + + for( void* pStepBmp = maList.First(); pStepBmp; pStepBmp = maList.Next() ) + delete (AnimationBitmap*) pStepBmp; + maList.Clear(); + + for( void* pView = mpViewList->First(); pView; pView = mpViewList->Next() ) + delete (ImplAnimView*) pView; + mpViewList->Clear(); +} + +// ----------------------------------------------------------------------- + +void Animation::Clear() +{ + SetEmpty(); +} + +// ----------------------------------------------------------------------- + +BOOL Animation::IsTransparent() const +{ + Point aPoint; + Rectangle aRect( aPoint, maGlobalSize ); + BOOL bRet = FALSE; + + // Falls irgendein 'kleines' Bildchen durch den Hintergrund + // ersetzt werden soll, muessen wir 'transparent' sein, um + // richtig dargestellt zu werden, da die Appl. aus Optimierungsgruenden + // kein Invalidate auf nicht-transp. Grafiken ausfuehren + for( long i = 0, nCount = maList.Count(); i < nCount; i++ ) + { + const AnimationBitmap* pAnimBmp = (AnimationBitmap*) maList.GetObject( i ); + + if( DISPOSE_BACK == pAnimBmp->eDisposal && Rectangle( pAnimBmp->aPosPix, pAnimBmp->aSizePix ) != aRect ) + { + bRet = TRUE; + break; + } + } + + if( !bRet ) + bRet = maBitmapEx.IsTransparent(); + + return bRet; +} + +// ----------------------------------------------------------------------- + +ULONG Animation::GetSizeBytes() const +{ + ULONG nSizeBytes = GetBitmapEx().GetSizeBytes(); + + for( long i = 0, nCount = maList.Count(); i < nCount; i++ ) + { + const AnimationBitmap* pAnimBmp = (AnimationBitmap*) maList.GetObject( i ); + nSizeBytes += pAnimBmp->aBmpEx.GetSizeBytes(); + } + + return nSizeBytes; +} + +// ----------------------------------------------------------------------- + +ULONG Animation::GetChecksum() const +{ + SVBT32 aBT32; + sal_uInt32 nCrc = GetBitmapEx().GetChecksum(); + + LongToSVBT32( maList.Count(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( maGlobalSize.Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( maGlobalSize.Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( (long) meCycleMode, aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + for( long i = 0, nCount = maList.Count(); i < nCount; i++ ) + { + LongToSVBT32( ( (AnimationBitmap*) maList.GetObject( i ) )->GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + + return nCrc; +} + +// ----------------------------------------------------------------------- + +BOOL Animation::Start( OutputDevice* pOut, const Point& rDestPt, long nExtraData, + OutputDevice* pFirstFrameOutDev ) +{ + return Start( pOut, rDestPt, pOut->PixelToLogic( maGlobalSize ), nExtraData, pFirstFrameOutDev ); +} + +// ----------------------------------------------------------------------- + +BOOL Animation::Start( OutputDevice* pOut, const Point& rDestPt, const Size& rDestSz, long nExtraData, + OutputDevice* pFirstFrameOutDev ) +{ + BOOL bRet = FALSE; + + if( maList.Count() ) + { + if( ( pOut->GetOutDevType() == OUTDEV_WINDOW ) && !mbLoopTerminated && + ( ANIMATION_TIMEOUT_ON_CLICK != ( (AnimationBitmap*) maList.GetObject( mnPos ) )->nWait ) ) + { + ImplAnimView* pView; + ImplAnimView* pMatch = NULL; + + for( pView = (ImplAnimView*) mpViewList->First(); pView; pView = (ImplAnimView*) mpViewList->Next() ) + { + if( pView->ImplMatches( pOut, nExtraData ) ) + { + if( pView->ImplGetOutPos() == rDestPt && + pView->ImplGetOutSizePix() == pOut->LogicToPixel( rDestSz ) ) + { + pView->ImplRepaint(); + pMatch = pView; + } + else + { + delete (ImplAnimView*) mpViewList->Remove( pView ); + pView = NULL; + } + + break; + } + } + + if( !mpViewList->Count() ) + { + maTimer.Stop(); + mbIsInAnimation = FALSE; + mnPos = 0UL; + } + + if( !pMatch ) + mpViewList->Insert( new ImplAnimView( this, pOut, rDestPt, rDestSz, nExtraData, pFirstFrameOutDev ), LIST_APPEND ); + + if( !mbIsInAnimation ) + { + ImplRestartTimer( ( (AnimationBitmap*) maList.GetObject( mnPos ) )->nWait ); + mbIsInAnimation = TRUE; + } + } + else + Draw( pOut, rDestPt, rDestSz ); + + bRet = TRUE; + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +void Animation::Stop( OutputDevice* pOut, long nExtraData ) +{ + ImplAnimView* pView = (ImplAnimView*) mpViewList->First(); + + while( pView ) + { + if( pView->ImplMatches( pOut, nExtraData ) ) + { + delete (ImplAnimView*) mpViewList->Remove( pView ); + pView = (ImplAnimView*) mpViewList->GetCurObject(); + } + else + pView = (ImplAnimView*) mpViewList->Next(); + } + + if( !mpViewList->Count() ) + { + maTimer.Stop(); + mbIsInAnimation = FALSE; + } +} + +// ----------------------------------------------------------------------- + +void Animation::Draw( OutputDevice* pOut, const Point& rDestPt ) const +{ + Draw( pOut, rDestPt, pOut->PixelToLogic( maGlobalSize ) ); +} + +// ----------------------------------------------------------------------- + +void Animation::Draw( OutputDevice* pOut, const Point& rDestPt, const Size& rDestSz ) const +{ + const ULONG nCount = maList.Count(); + + if( nCount ) + { + AnimationBitmap* pObj = (AnimationBitmap*) maList.GetObject( Min( mnPos, (long) nCount - 1L ) ); + + if( pOut->GetConnectMetaFile() || ( pOut->GetOutDevType() == OUTDEV_PRINTER ) ) + ( (AnimationBitmap*) maList.GetObject( 0 ) )->aBmpEx.Draw( pOut, rDestPt, rDestSz ); + else if( ANIMATION_TIMEOUT_ON_CLICK == pObj->nWait ) + pObj->aBmpEx.Draw( pOut, rDestPt, rDestSz ); + else + { + const ULONG nOldPos = mnPos; + ( (Animation*) this )->mnPos = mbLoopTerminated ? ( nCount - 1UL ) : mnPos; + delete new ImplAnimView( (Animation*) this, pOut, rDestPt, rDestSz, 0 ); + ( (Animation*) this )->mnPos = nOldPos; + } + } +} + +// ----------------------------------------------------------------------- + +void Animation::ImplRestartTimer( ULONG nTimeout ) +{ +#ifdef REMOTE_APPSERVER + nTimeout = nTimeout > 40 ? nTimeout : 40; +#endif + maTimer.SetTimeout( Max( nTimeout, MIN_TIMEOUT + ( mnAnimCount - 1 ) * INC_TIMEOUT ) * 10L ); + maTimer.Start(); +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( Animation, ImplTimeoutHdl, Timer*, pTimer ) +{ + const ULONG nAnimCount = maList.Count(); + + if( nAnimCount ) + { + ImplAnimView* pView; + BOOL bGlobalPause = TRUE; + + if( maNotifyLink.IsSet() ) + { + AInfo* pAInfo; + + // create AInfo-List + for( pView = (ImplAnimView*) mpViewList->First(); pView; pView = (ImplAnimView*) mpViewList->Next() ) + maAInfoList.Insert( pView->ImplCreateAInfo() ); + + maNotifyLink.Call( this ); + + // set view state from AInfo structure + for( pAInfo = (AInfo*) maAInfoList.First(); pAInfo; pAInfo = (AInfo*) maAInfoList.Next() ) + { + if( !pAInfo->pViewData ) + { + pView = new ImplAnimView( this, pAInfo->pOutDev, + pAInfo->aStartOrg, pAInfo->aStartSize, pAInfo->nExtraData ); + + mpViewList->Insert( pView, LIST_APPEND ); + } + else + pView = (ImplAnimView*) pAInfo->pViewData; + + pView->ImplPause( pAInfo->bPause ); + pView->ImplSetMarked( TRUE ); + } + + // delete AInfo structures + for( pAInfo = (AInfo*) maAInfoList.First(); pAInfo; pAInfo = (AInfo*) maAInfoList.Next() ) + delete (AInfo*) pAInfo; + maAInfoList.Clear(); + + // delete all unmarked views and reset marked state + pView = (ImplAnimView*) mpViewList->First(); + while( pView ) + { + if( !pView->ImplIsMarked() ) + { + delete (ImplAnimView*) mpViewList->Remove( pView ); + pView = (ImplAnimView*) mpViewList->GetCurObject(); + } + else + { + if( !pView->ImplIsPause() ) + bGlobalPause = FALSE; + + pView->ImplSetMarked( FALSE ); + pView = (ImplAnimView*) mpViewList->Next(); + } + } + } + else + bGlobalPause = FALSE; + + if( !mpViewList->Count() ) + Stop(); + else if( bGlobalPause ) + ImplRestartTimer( 10 ); + else + { + AnimationBitmap* pStepBmp = (AnimationBitmap*) maList.GetObject( ++mnPos ); + + if( !pStepBmp ) + { + if( mnLoops == 1 ) + { + Stop(); + mbLoopTerminated = TRUE; + mnPos = nAnimCount - 1UL; + maBitmapEx = ( (AnimationBitmap*) maList.GetObject( mnPos ) )->aBmpEx; + return 0L; + } + else + { + if( mnLoops ) + mnLoops--; + + mnPos = 0; + pStepBmp = (AnimationBitmap*) maList.GetObject( mnPos ); + } + } + + // Paint all views; after painting check, if view is + // marked; in this case remove view, because area of output + // lies out of display area of window; mark state is + // set from view itself + pView = (ImplAnimView*) mpViewList->First(); + while( pView ) + { + pView->ImplDraw( mnPos ); + + if( pView->ImplIsMarked() ) + { + delete (ImplAnimView*) mpViewList->Remove( pView ); + pView = (ImplAnimView*) mpViewList->GetCurObject(); + } + else + pView = (ImplAnimView*) mpViewList->Next(); + } + + // stop or restart timer + if( !mpViewList->Count() ) + Stop(); + else + ImplRestartTimer( pStepBmp->nWait ); + } + } + else + Stop(); + + return 0L; +} + +// ----------------------------------------------------------------------- + +BOOL Animation::Insert( const AnimationBitmap& rStepBmp ) +{ + BOOL bRet = FALSE; + + if( !IsInAnimation() ) + { + Point aPoint; + Rectangle aGlobalRect( aPoint, maGlobalSize ); + + maGlobalSize = aGlobalRect.Union( Rectangle( rStepBmp.aPosPix, rStepBmp.aSizePix ) ).GetSize(); + maList.Insert( new AnimationBitmap( rStepBmp ), LIST_APPEND ); + + // zunaechst nehmen wir die erste BitmapEx als Ersatz-BitmapEx + if( maList.Count() == 1 ) + maBitmapEx = rStepBmp.aBmpEx; + + bRet = TRUE; + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +const AnimationBitmap& Animation::Get( USHORT nAnimation ) const +{ + DBG_ASSERT( ( nAnimation < maList.Count() ), "No object at this position" ); + return *(AnimationBitmap*) maList.GetObject( nAnimation ); +} + +// ----------------------------------------------------------------------- + +void Animation::Replace( const AnimationBitmap& rNewAnimationBitmap, USHORT nAnimation ) +{ + DBG_ASSERT( ( nAnimation < maList.Count() ), "No object at this position" ); + + delete (AnimationBitmap*) maList.Replace( new AnimationBitmap( rNewAnimationBitmap ), nAnimation ); + + // Falls wir an erster Stelle einfuegen, + // muessen wir natuerlich auch, + // auch die Ersatzdarstellungs-BitmapEx + // aktualisieren; + if ( ( !nAnimation && ( !mbLoopTerminated || ( maList.Count() == 1 ) ) ) || + ( ( nAnimation == maList.Count() - 1 ) && mbLoopTerminated ) ) + { + maBitmapEx = rNewAnimationBitmap.aBmpEx; + } +} + +// ----------------------------------------------------------------------- + +void Animation::SetLoopCount( const ULONG nLoopCount ) +{ + mnLoopCount = nLoopCount; + ResetLoopCount(); +} + +// ----------------------------------------------------------------------- + +void Animation::ResetLoopCount() +{ + mnLoops = mnLoopCount; + mbLoopTerminated = FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL Animation::Convert( BmpConversion eConversion ) +{ + DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" ); + + BOOL bRet; + + if( !IsInAnimation() && maList.Count() ) + { + bRet = TRUE; + + for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() ) + bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.Convert( eConversion ); + + maBitmapEx.Convert( eConversion ); + } + else + bRet = FALSE; + + return bRet; +} + +// ----------------------------------------------------------------------- + +BOOL Animation::ReduceColors( USHORT nNewColorCount, BmpReduce eReduce ) +{ + DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" ); + + BOOL bRet; + + if( !IsInAnimation() && maList.Count() ) + { + bRet = TRUE; + + for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() ) + bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.ReduceColors( nNewColorCount, eReduce ); + + maBitmapEx.ReduceColors( nNewColorCount, eReduce ); + } + else + bRet = FALSE; + + return bRet; +} + +// ----------------------------------------------------------------------- + +BOOL Animation::Invert() +{ + DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" ); + + BOOL bRet; + + if( !IsInAnimation() && maList.Count() ) + { + bRet = TRUE; + + for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() ) + bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.Invert(); + + maBitmapEx.Invert(); + } + else + bRet = FALSE; + + return bRet; +} + +// ----------------------------------------------------------------------- + +BOOL Animation::Mirror( ULONG nMirrorFlags ) +{ + DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" ); + + BOOL bRet; + + if( !IsInAnimation() && maList.Count() ) + { + bRet = TRUE; + + if( nMirrorFlags ) + { + for( AnimationBitmap* pStepBmp = (AnimationBitmap*) maList.First(); + pStepBmp && bRet; + pStepBmp = (AnimationBitmap*) maList.Next() ) + { + if( ( bRet = pStepBmp->aBmpEx.Mirror( nMirrorFlags ) ) == TRUE ) + { + if( nMirrorFlags & BMP_MIRROR_HORZ ) + pStepBmp->aPosPix.X() = maGlobalSize.Width() - pStepBmp->aPosPix.X() - pStepBmp->aSizePix.Width(); + + if( nMirrorFlags & BMP_MIRROR_VERT ) + pStepBmp->aPosPix.Y() = maGlobalSize.Height() - pStepBmp->aPosPix.Y() - pStepBmp->aSizePix.Height(); + } + } + + maBitmapEx.Mirror( nMirrorFlags ); + } + } + else + bRet = FALSE; + + return bRet; +} + +// ----------------------------------------------------------------------- + +BOOL Animation::Dither( ULONG nDitherFlags, const BitmapPalette* pDitherPal ) +{ + DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" ); + + BOOL bRet; + + if( !IsInAnimation() && maList.Count() ) + { + bRet = TRUE; + + for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() ) + bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.Dither( nDitherFlags, pDitherPal ); + + maBitmapEx.Dither( nDitherFlags, pDitherPal ); + } + else + bRet = FALSE; + + return bRet; +} + +// ----------------------------------------------------------------------- + +BOOL Animation::Adjust( short nLuminancePercent, short nContrastPercent, + short nChannelRPercent, short nChannelGPercent, short nChannelBPercent, + double fGamma, BOOL bInvert ) +{ + DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" ); + + BOOL bRet; + + if( !IsInAnimation() && maList.Count() ) + { + bRet = TRUE; + + for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() ) + { + bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.Adjust( nLuminancePercent, nContrastPercent, + nChannelRPercent, nChannelGPercent, nChannelBPercent, + fGamma, bInvert ); + } + + maBitmapEx.Adjust( nLuminancePercent, nContrastPercent, + nChannelRPercent, nChannelGPercent, nChannelBPercent, + fGamma, bInvert ); + } + else + bRet = FALSE; + + return bRet; +} + +// ----------------------------------------------------------------------- + +BOOL Animation::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress ) +{ + DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" ); + + BOOL bRet; + + if( !IsInAnimation() && maList.Count() ) + { + bRet = TRUE; + + for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() ) + bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.Filter( eFilter, pFilterParam, pProgress ); + + maBitmapEx.Filter( eFilter, pFilterParam, pProgress ); + } + else + bRet = FALSE; + + return bRet; +} + +// ----------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rOStm, const Animation& rAnimation ) +{ + const USHORT nCount = rAnimation.Count(); + + if( nCount ) + { + const ByteString aDummyStr; + const UINT32 nDummy32 = 0UL; + + // Falls keine BitmapEx gesetzt wurde, schreiben wir + // einfach die erste Bitmap der Animation + if( !rAnimation.GetBitmapEx().GetBitmap() ) + rOStm << rAnimation.Get( 0 ).aBmpEx; + else + rOStm << rAnimation.GetBitmapEx(); + + // Kennung schreiben ( SDANIMA1 ) + rOStm << (UINT32) 0x5344414e << (UINT32) 0x494d4931; + + for( USHORT i = 0; i < nCount; i++ ) + { + const AnimationBitmap& rAnimBmp = rAnimation.Get( i ); + const UINT16 nRest = nCount - i - 1; + + // AnimationBitmap schreiben + rOStm << rAnimBmp.aBmpEx; + rOStm << rAnimBmp.aPosPix; + rOStm << rAnimBmp.aSizePix; + rOStm << rAnimation.maGlobalSize; + rOStm << (UINT16) ( ( ANIMATION_TIMEOUT_ON_CLICK == rAnimBmp.nWait ) ? 65535 : rAnimBmp.nWait ); + rOStm << (UINT16) rAnimBmp.eDisposal; + rOStm << (BYTE) rAnimBmp.bUserInput; + rOStm << (UINT32) rAnimation.mnLoopCount; + rOStm << nDummy32; // unbenutzt + rOStm << nDummy32; // unbenutzt + rOStm << nDummy32; // unbenutzt + rOStm << aDummyStr; // unbenutzt + rOStm << nRest; // Anzahl der Strukturen, die noch _folgen_ + } + } + + return rOStm; +} + +// ----------------------------------------------------------------------- + +SvStream& operator>>( SvStream& rIStm, Animation& rAnimation ) +{ + Bitmap aBmp; + ULONG nStmPos = rIStm.Tell(); + UINT32 nAnimMagic1, nAnimMagic2; + USHORT nOldFormat = rIStm.GetNumberFormatInt(); + BOOL bReadAnimations = FALSE; + + rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + nStmPos = rIStm.Tell(); + rIStm >> nAnimMagic1 >> nAnimMagic2; + + rAnimation.Clear(); + + // Wenn die BitmapEx am Anfang schon gelesen + // wurde ( von Graphic ), koennen wir direkt die Animationsbitmaps einlesen + if( ( nAnimMagic1 == 0x5344414e ) && ( nAnimMagic2 == 0x494d4931 ) && !rIStm.GetError() ) + bReadAnimations = TRUE; + // ansonsten versuchen wir erstmal die Bitmap(-Ex) zu lesen + else + { + rIStm.Seek( nStmPos ); + rIStm >> rAnimation.maBitmapEx; + nStmPos = rIStm.Tell(); + rIStm >> nAnimMagic1 >> nAnimMagic2; + + if( ( nAnimMagic1 == 0x5344414e ) && ( nAnimMagic2 == 0x494d4931 ) && !rIStm.GetError() ) + bReadAnimations = TRUE; + else + rIStm.Seek( nStmPos ); + } + + // ggf. Animationsbitmaps lesen + if( bReadAnimations ) + { + AnimationBitmap aAnimBmp; + BitmapEx aBmpEx; + ByteString aDummyStr; + Point aPoint; + Size aSize; + UINT32 nTmp32; + UINT16 nTmp16; + BYTE cTmp; + + do + { + rIStm >> aAnimBmp.aBmpEx; + rIStm >> aAnimBmp.aPosPix; + rIStm >> aAnimBmp.aSizePix; + rIStm >> rAnimation.maGlobalSize; + rIStm >> nTmp16; aAnimBmp.nWait = ( ( 65535 == nTmp16 ) ? ANIMATION_TIMEOUT_ON_CLICK : nTmp16 ); + rIStm >> nTmp16; aAnimBmp.eDisposal = ( Disposal) nTmp16; + rIStm >> cTmp; aAnimBmp.bUserInput = (BOOL) cTmp; + rIStm >> nTmp32; rAnimation.mnLoopCount = (USHORT) nTmp32; + rIStm >> nTmp32; // unbenutzt + rIStm >> nTmp32; // unbenutzt + rIStm >> nTmp32; // unbenutzt + rIStm >> aDummyStr; // unbenutzt + rIStm >> nTmp16; // Rest zu lesen + + rAnimation.Insert( aAnimBmp ); + } + while( nTmp16 && !rIStm.GetError() ); + + rAnimation.ResetLoopCount(); + } + + rIStm.SetNumberFormatInt( nOldFormat ); + + return rIStm; +} diff --git a/vcl/source/gdi/bitmap.cxx b/vcl/source/gdi/bitmap.cxx new file mode 100644 index 000000000000..d5016647cfca --- /dev/null +++ b/vcl/source/gdi/bitmap.cxx @@ -0,0 +1,1980 @@ +/************************************************************************* + * + * $RCSfile: bitmap.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_BITMAP_CXX + +#ifndef _RTL_CRC_H_ +#include <rtl/crc.h> +#endif +#ifndef _SV_SALBTYPE_HXX +#include <salbtype.hxx> +#endif +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif +#ifndef _SV_BMPACC_HXX +#include <bmpacc.hxx> +#endif +#ifndef _SV_POLY_HXX +#include <poly.hxx> +#endif +#ifndef _SV_OUTDEV_HXX +#include <outdev.hxx> +#endif +#ifndef _SV_IMPBMP_HXX +#include <impbmp.hxx> +#endif +#ifndef _SV_RC_H +#include <rc.h> +#endif +#ifndef _SV_BITMAP_HXX +#include <bitmap.hxx> +#endif +#ifndef _SV_ALPHA_HXX +#include <alpha.hxx> +#endif +#ifndef _SV_SVAPP_HXX +#include <svapp.hxx> +#endif + +// ------------------------------------------------------------------ + +Bitmap::Bitmap() : + mpImpBmp( NULL ) +{ +} + +// ------------------------------------------------------------------ + +Bitmap::Bitmap( const ResId& rResId ) : + mpImpBmp( NULL ) +{ + ResMgr * pResMgr = NULL; + + ResMgr::GetResourceSkipHeader( rResId.SetRT( RSC_BITMAP ), &pResMgr ); + + USHORT nBitmapType; + USHORT nBitmapId; + nBitmapType = pResMgr->ReadShort(); + nBitmapId = pResMgr->ReadShort(); + + SvStream* pBmpStream = pResMgr->pImpRes->GetBitmapStream( nBitmapId ); + if( pBmpStream ) + *pBmpStream >> *this; + // pop filename + String aDummy = pResMgr->ReadString(); +} + +// ------------------------------------------------------------------ + +Bitmap::Bitmap( const Bitmap& rBitmap ) : + maPrefMapMode ( rBitmap.maPrefMapMode ), + maPrefSize ( rBitmap.maPrefSize ) +{ + mpImpBmp = rBitmap.mpImpBmp; + + if ( mpImpBmp ) + mpImpBmp->ImplIncRefCount(); +} + +// ------------------------------------------------------------------ + +Bitmap::Bitmap( const Size& rSizePixel, USHORT nBitCount, const BitmapPalette* pPal ) +{ + if( rSizePixel.Width() && rSizePixel.Height() ) + { + BitmapPalette aPal; + BitmapPalette* pRealPal = NULL; + + if( nBitCount <= 8 ) + { + if( !pPal ) + { + if( 1 == nBitCount ) + { + aPal.SetEntryCount( 2 ); + aPal[ 0 ] = Color( COL_BLACK ); + aPal[ 1 ] = Color( COL_WHITE ); + } + else if( ( 4 == nBitCount ) || ( 8 == nBitCount ) ) + { + aPal.SetEntryCount( 1 << nBitCount ); + aPal[ 0 ] = Color( COL_BLACK ); + aPal[ 1 ] = Color( COL_BLUE ); + aPal[ 2 ] = Color( COL_GREEN ); + aPal[ 3 ] = Color( COL_CYAN ); + aPal[ 4 ] = Color( COL_RED ); + aPal[ 5 ] = Color( COL_MAGENTA ); + aPal[ 6 ] = Color( COL_BROWN ); + aPal[ 7 ] = Color( COL_GRAY ); + aPal[ 8 ] = Color( COL_LIGHTGRAY ); + aPal[ 9 ] = Color( COL_LIGHTBLUE ); + aPal[ 10 ] = Color( COL_LIGHTGREEN ); + aPal[ 11 ] = Color( COL_LIGHTCYAN ); + aPal[ 12 ] = Color( COL_LIGHTRED ); + aPal[ 13 ] = Color( COL_LIGHTMAGENTA ); + aPal[ 14 ] = Color( COL_YELLOW ); + aPal[ 15 ] = Color( COL_WHITE ); + + // Dither-Palette erzeugen + if( 8 == nBitCount ) + { + USHORT nActCol = 16; + + for( USHORT nB = 0; nB < 256; nB += 51 ) + for( USHORT nG = 0; nG < 256; nG += 51 ) + for( USHORT nR = 0; nR < 256; nR += 51 ) + aPal[ nActCol++ ] = BitmapColor( (BYTE) nR, (BYTE) nG, (BYTE) nB ); + + // Standard-Office-Farbe setzen + aPal[ nActCol++ ] = BitmapColor( 0, 184, 255 ); + } + } + } + else + pRealPal = (BitmapPalette*) pPal; + } + + mpImpBmp = new ImpBitmap; + mpImpBmp->ImplCreate( rSizePixel, nBitCount, pRealPal ? *pRealPal : aPal ); + } + else + mpImpBmp = NULL; +} + +// ------------------------------------------------------------------ + +Bitmap::~Bitmap() +{ + ImplReleaseRef(); +} + +// ------------------------------------------------------------------ + +const BitmapPalette& Bitmap::GetGreyPalette( USHORT nEntries ) +{ + static BitmapPalette aGreyPalette2; + static BitmapPalette aGreyPalette4; + static BitmapPalette aGreyPalette16; + static BitmapPalette aGreyPalette256; + + // create greyscale palette with 2, 4, 16 or 256 entries + if( 2 == nEntries || 4 == nEntries || 16 == nEntries || 256 == nEntries ) + { + if( 2 == nEntries ) + { + if( !aGreyPalette2.GetEntryCount() ) + { + aGreyPalette2.SetEntryCount( 2 ); + aGreyPalette2[ 0 ] = BitmapColor( 0, 0, 0 ); + aGreyPalette2[ 1 ] = BitmapColor( 255, 255, 255 ); + } + + return aGreyPalette2; + } + else if( 4 == nEntries ) + { + if( !aGreyPalette4.GetEntryCount() ) + { + aGreyPalette4.SetEntryCount( 4 ); + aGreyPalette4[ 0 ] = BitmapColor( 0, 0, 0 ); + aGreyPalette4[ 1 ] = BitmapColor( 85, 85, 85 ); + aGreyPalette4[ 2 ] = BitmapColor( 170, 170, 170 ); + aGreyPalette4[ 3 ] = BitmapColor( 255, 255, 255 ); + } + + return aGreyPalette4; + } + else if( 16 == nEntries ) + { + if( !aGreyPalette16.GetEntryCount() ) + { + BYTE cGrey = 0, cGreyInc = 17; + + aGreyPalette16.SetEntryCount( 16 ); + + for( USHORT i = 0; i < 16; i++, cGrey += cGreyInc ) + aGreyPalette16[ i ] = BitmapColor( cGrey, cGrey, cGrey ); + } + + return aGreyPalette16; + } + else + { + if( !aGreyPalette256.GetEntryCount() ) + { + aGreyPalette256.SetEntryCount( 256 ); + + for( USHORT i = 0; i < 256; i++ ) + aGreyPalette256[ i ] = BitmapColor( (BYTE) i, (BYTE) i, (BYTE) i ); + } + + return aGreyPalette256; + } + } + else + { + DBG_ERROR( "Bitmap::GetGreyPalette: invalid entry count (2/4/16/256 allowed)" ); + return aGreyPalette2; + } +} + +// ------------------------------------------------------------------ + +Bitmap& Bitmap::operator=( const Bitmap& rBitmap ) +{ + maPrefSize = rBitmap.maPrefSize; + maPrefMapMode = rBitmap.maPrefMapMode; + + if ( rBitmap.mpImpBmp ) + rBitmap.mpImpBmp->ImplIncRefCount(); + + ImplReleaseRef(); + mpImpBmp = rBitmap.mpImpBmp; + + return *this; +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::IsEqual( const Bitmap& rBmp ) const +{ + return( IsSameInstance( rBmp ) || + ( rBmp.GetSizePixel() == GetSizePixel() && + rBmp.GetBitCount() == GetBitCount() && + rBmp.GetChecksum() == GetChecksum() ) ); +} + +// ------------------------------------------------------------------ + +void Bitmap::SetEmpty() +{ + maPrefMapMode = MapMode(); + maPrefSize = Size(); + + ImplReleaseRef(); + mpImpBmp = NULL; +} + +// ------------------------------------------------------------------ + +Size Bitmap::GetSizePixel() const +{ + return( mpImpBmp ? mpImpBmp->ImplGetSize() : Size() ); +} + +// ------------------------------------------------------------------ + +void Bitmap::SetSizePixel( const Size& rNewSize ) +{ + Scale( rNewSize ); +} + +// ------------------------------------------------------------------ + +USHORT Bitmap::GetBitCount() const +{ + return( mpImpBmp ? mpImpBmp->ImplGetBitCount() : 0 ); +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::HasGreyPalette() const +{ + const USHORT nBitCount = GetBitCount(); + BOOL bRet = FALSE; + + if( 1 == nBitCount ) + bRet = TRUE; + else if( 4 == nBitCount || 8 == nBitCount ) + { + BitmapReadAccess* pRAcc = ( (Bitmap*) this )->AcquireReadAccess(); + + if( pRAcc ) + { + if( pRAcc->HasPalette() && ( (BitmapPalette&) pRAcc->GetPalette() == GetGreyPalette( 1 << nBitCount ) ) ) + bRet = TRUE; + + ( (Bitmap*) this )->ReleaseAccess( pRAcc ); + } + } + + return bRet; +} + +// ------------------------------------------------------------------ + +ULONG Bitmap::GetChecksum() const +{ + ULONG nRet = 0UL; + + if( mpImpBmp ) + { + nRet = mpImpBmp->ImplGetChecksum(); + + if( !nRet ) + { + BitmapReadAccess* pRAcc = ( (Bitmap*) this )->AcquireReadAccess(); + + if( pRAcc && pRAcc->Width() && pRAcc->Height() ) + { + sal_uInt32 nCrc = 0; + SVBT32 aBT32; + + pRAcc->ImplZeroInitUnusedBits(); + + LongToSVBT32( pRAcc->Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pRAcc->Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pRAcc->GetBitCount(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pRAcc->GetColorMask().GetRedMask(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pRAcc->GetColorMask().GetGreenMask(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pRAcc->GetColorMask().GetBlueMask(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + if( pRAcc->HasPalette() ) + { + nCrc = rtl_crc32( nCrc, pRAcc->GetPalette().ImplGetColorBuffer(), + pRAcc->GetPaletteEntryCount() * sizeof( BitmapColor ) ); + } + + nCrc = rtl_crc32( nCrc, pRAcc->GetBuffer(), pRAcc->GetScanlineSize() * pRAcc->Height() ); + + ( (Bitmap*) this )->ReleaseAccess( pRAcc ); + + mpImpBmp->ImplSetChecksum( nRet = nCrc ); + } + } + } + + return nRet; +} + +// ------------------------------------------------------------------ + +void Bitmap::ImplReleaseRef() +{ + if( mpImpBmp ) + { + if( mpImpBmp->ImplGetRefCount() > 1UL ) + mpImpBmp->ImplDecRefCount(); + else + { + delete mpImpBmp; + mpImpBmp = NULL; + } + } +} + +// ------------------------------------------------------------------ + +void Bitmap::ImplMakeUnique() +{ + if( mpImpBmp && mpImpBmp->ImplGetRefCount() > 1UL ) + { + ImpBitmap* pOldImpBmp = mpImpBmp; + + pOldImpBmp->ImplDecRefCount(); + + mpImpBmp = new ImpBitmap; + mpImpBmp->ImplCreate( *pOldImpBmp ); + } +} + +// ------------------------------------------------------------------ + +void Bitmap::ImplAssignWithSize( const Bitmap& rBitmap ) +{ + const Size aOldSizePix( GetSizePixel() ); + const Size aNewSizePix( rBitmap.GetSizePixel() ); + const MapMode aOldMapMode( maPrefMapMode ); + Size aNewPrefSize; + + if( ( aOldSizePix != aNewSizePix ) && aOldSizePix.Width() && aOldSizePix.Height() ) + { + aNewPrefSize.Width() = FRound( maPrefSize.Width() * aNewSizePix.Width() / aOldSizePix.Width() ); + aNewPrefSize.Height() = FRound( maPrefSize.Height() * aNewSizePix.Height() / aOldSizePix.Height() ); + } + else + aNewPrefSize = maPrefSize; + + *this = rBitmap; + + maPrefSize = aNewPrefSize; + maPrefMapMode = aOldMapMode; +} + +// ------------------------------------------------------------------ + +ImpBitmap* Bitmap::ImplGetImpBitmap() const +{ + return mpImpBmp; +} + +// ------------------------------------------------------------------ + +void Bitmap::ImplSetImpBitmap( ImpBitmap* pImpBmp ) +{ + if( pImpBmp != mpImpBmp ) + { + ImplReleaseRef(); + mpImpBmp = pImpBmp; + } +} + +// ------------------------------------------------------------------ + +BitmapReadAccess* Bitmap::AcquireReadAccess() +{ +#ifdef REMOTE_APPSERVER + BOOL bGottenFromServer = FALSE; + if( mpImpBmp && mpImpBmp->ImplIsGetPrepared() ) + mpImpBmp->ImplResolveGet(), bGottenFromServer = TRUE; +#endif + + BitmapReadAccess* pReadAccess = new BitmapReadAccess( *this ); + + if( !*pReadAccess ) + { + delete pReadAccess; + pReadAccess = NULL; + } + +#ifdef REMOTE_APPSERVER + if( pReadAccess && mpImpBmp && bGottenFromServer ) + mpImpBmp->ImplReleaseRemoteBmp(); +#endif + + return pReadAccess; +} + +// ------------------------------------------------------------------ + +BitmapWriteAccess* Bitmap::AcquireWriteAccess() +{ +#ifdef REMOTE_APPSERVER + if( mpImpBmp && mpImpBmp->ImplIsGetPrepared() ) + mpImpBmp->ImplResolveGet(); +#endif + + BitmapWriteAccess* pWriteAccess = new BitmapWriteAccess( *this ); + + if( !*pWriteAccess ) + { + delete pWriteAccess; + pWriteAccess = NULL; + } + +#ifdef REMOTE_APPSERVER + if( pWriteAccess && mpImpBmp ) + mpImpBmp->ImplReleaseRemoteBmp(); +#endif + + return pWriteAccess; +} + +// ------------------------------------------------------------------ + +void Bitmap::ReleaseAccess( BitmapReadAccess* pBitmapAccess ) +{ + delete pBitmapAccess; +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::Erase( const Color& rFillColor ) +{ + BitmapWriteAccess* pWriteAcc = AcquireWriteAccess(); + BOOL bRet = FALSE; + + if( pWriteAcc ) + { + const ULONG nFormat = pWriteAcc->GetScanlineFormat(); + BYTE cIndex; + BOOL bFast; + + switch( nFormat ) + { + case( BMP_FORMAT_1BIT_MSB_PAL ): + case( BMP_FORMAT_1BIT_LSB_PAL ): + { + cIndex = (BYTE) pWriteAcc->GetBestPaletteIndex( rFillColor ); + cIndex = ( cIndex ? 255 : 0 ); + bFast = TRUE; + } + break; + + case( BMP_FORMAT_4BIT_MSN_PAL ): + case( BMP_FORMAT_4BIT_LSN_PAL ): + { + cIndex = (BYTE) pWriteAcc->GetBestPaletteIndex( rFillColor ); + cIndex = cIndex | ( cIndex << 4 ); + bFast = TRUE; + } + break; + + case( BMP_FORMAT_8BIT_PAL ): + { + cIndex = (BYTE) pWriteAcc->GetBestPaletteIndex( rFillColor ); + bFast = TRUE; + } + break; + + case( BMP_FORMAT_24BIT_TC_BGR ): + case( BMP_FORMAT_24BIT_TC_RGB ): + { + if( ( rFillColor.GetRed() == rFillColor.GetGreen() ) && + ( rFillColor.GetRed() == rFillColor.GetBlue() ) ) + { + cIndex = rFillColor.GetRed(); + bFast = TRUE; + } + else + bFast = FALSE; + } + break; + + default: + bFast = FALSE; + break; + } + + if( bFast ) + { + const ULONG nBufSize = pWriteAcc->GetScanlineSize() * pWriteAcc->Height(); + HMEMSET( pWriteAcc->GetBuffer(), cIndex, nBufSize ); + } + else + { + Point aTmpPoint; + const Rectangle aRect( aTmpPoint, Size( pWriteAcc->Width(), pWriteAcc->Height() ) ); + pWriteAcc->SetFillColor( rFillColor ); + pWriteAcc->FillRect( aRect ); + } + + ReleaseAccess( pWriteAcc ); + bRet = TRUE; + } + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::Invert() +{ + BitmapWriteAccess* pAcc = AcquireWriteAccess(); + BOOL bRet = FALSE; + + if( pAcc ) + { + if( pAcc->HasPalette() ) + { + BitmapPalette aBmpPal( pAcc->GetPalette() ); + const USHORT nCount = aBmpPal.GetEntryCount(); + + for( USHORT i = 0; i < nCount; i++ ) + aBmpPal[ i ].Invert(); + + pAcc->SetPalette( aBmpPal ); + } + else + { + const long nWidth = pAcc->Width(); + const long nHeight = pAcc->Height(); + + for( long nX = 0L; nX < nWidth; nX++ ) + for( long nY = 0L; nY < nHeight; nY++ ) + pAcc->SetPixel( nY, nX, pAcc->GetPixel( nY, nX ).Invert() ); + } + + ReleaseAccess( pAcc ); + bRet = TRUE; + } + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::Mirror( ULONG nMirrorFlags ) +{ + BOOL bHorz = ( ( nMirrorFlags & BMP_MIRROR_HORZ ) == BMP_MIRROR_HORZ ); + BOOL bVert = ( ( nMirrorFlags & BMP_MIRROR_VERT ) == BMP_MIRROR_VERT ); + BOOL bRet = FALSE; + + if( bHorz && !bVert ) + { + BitmapWriteAccess* pAcc = AcquireWriteAccess(); + + if( pAcc ) + { + const long nWidth = pAcc->Width(); + const long nHeight = pAcc->Height(); + const long nWidth1 = nWidth - 1L; + const long nWidth_2 = nWidth >> 1L; + + for( long nY = 0L; nY < nHeight; nY++ ) + { + for( long nX = 0L, nOther = nWidth1; nX < nWidth_2; nX++, nOther-- ) + { + const BitmapColor aTemp( pAcc->GetPixel( nY, nX ) ); + + pAcc->SetPixel( nY, nX, pAcc->GetPixel( nY, nOther ) ); + pAcc->SetPixel( nY, nOther, aTemp ); + } + } + + ReleaseAccess( pAcc ); + bRet = TRUE; + } + } + else if( bVert && !bHorz ) + { + BitmapWriteAccess* pAcc = AcquireWriteAccess(); + + if( pAcc ) + { + const long nScanSize = pAcc->GetScanlineSize(); + BYTE* pBuffer = new BYTE[ nScanSize ]; + const long nHeight = pAcc->Height(); + const long nHeight1 = nHeight - 1L; + const long nHeight_2 = nHeight >> 1L; + + for( long nY = 0L, nOther = nHeight1; nY < nHeight_2; nY++, nOther-- ) + { + HMEMCPY( pBuffer, pAcc->GetScanline( nY ), nScanSize ); + HMEMCPY( pAcc->GetScanline( nY ), pAcc->GetScanline( nOther ), nScanSize ); + HMEMCPY( pAcc->GetScanline( nOther ), pBuffer, nScanSize ); + } + + delete[] pBuffer; + ReleaseAccess( pAcc ); + bRet = TRUE; + } + } + else if( bHorz && bVert ) + { + BitmapWriteAccess* pAcc = AcquireWriteAccess(); + + if( pAcc ) + { + const long nWidth = pAcc->Width(); + const long nWidth1 = nWidth - 1L; + const long nHeight = pAcc->Height(); + long nHeight_2 = nHeight >> 1; + + for( long nY = 0L, nOtherY = nHeight - 1L; nY < nHeight_2; nY++, nOtherY-- ) + { + for( long nX = 0L, nOtherX = nWidth1; nX < nWidth; nX++, nOtherX-- ) + { + const BitmapColor aTemp( pAcc->GetPixel( nY, nX ) ); + + pAcc->SetPixel( nY, nX, pAcc->GetPixel( nOtherY, nOtherX ) ); + pAcc->SetPixel( nOtherY, nOtherX, aTemp ); + } + } + + // ggf. noch mittlere Zeile horizontal spiegeln + if( nHeight & 1 ) + { + for( long nX = 0L, nOtherX = nWidth1, nWidth_2 = nWidth >> 1; nX < nWidth_2; nX++, nOtherX-- ) + { + const BitmapColor aTemp( pAcc->GetPixel( nHeight_2, nX ) ); + pAcc->SetPixel( nHeight_2, nX, pAcc->GetPixel( nHeight_2, nOtherX ) ); + pAcc->SetPixel( nHeight_2, nOtherX, aTemp ); + } + } + + ReleaseAccess( pAcc ); + bRet = TRUE; + } + } + else + bRet = TRUE; + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::Rotate( long nAngle10, const Color& rFillColor ) +{ + BOOL bRet = FALSE; + + nAngle10 %= 3600L; + nAngle10 = ( nAngle10 < 0L ) ? ( 3599L + nAngle10 ) : nAngle10; + + if( !nAngle10 ) + bRet = TRUE; + else if( 1800L == nAngle10 ) + bRet = Mirror( BMP_MIRROR_HORZ | BMP_MIRROR_VERT ); + else + { + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + Bitmap aRotatedBmp; + + if( pReadAcc ) + { + const Size aSizePix( GetSizePixel() ); + + if( ( 900L == nAngle10 ) || ( 2700L == nAngle10 ) ) + { + const Size aNewSizePix( aSizePix.Height(), aSizePix.Width() ); + Bitmap aNewBmp( aNewSizePix, GetBitCount(), &pReadAcc->GetPalette() ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + + if( pWriteAcc ) + { + const long nWidth = aSizePix.Width(); + const long nWidth1 = nWidth - 1L; + const long nHeight = aSizePix.Height(); + const long nHeight1 = nHeight - 1L; + const long nNewWidth = aNewSizePix.Width(); + const long nNewHeight = aNewSizePix.Height(); + + if( 900L == nAngle10 ) + { + for( long nY = 0L, nOtherX = nWidth1; nY < nNewHeight; nY++, nOtherX-- ) + for( long nX = 0L, nOtherY = 0L; nX < nNewWidth; nX++ ) + pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nOtherY++, nOtherX ) ); + } + else if( 2700L == nAngle10 ) + { + for( long nY = 0L, nOtherX = 0L; nY < nNewHeight; nY++, nOtherX++ ) + for( long nX = 0L, nOtherY = nHeight1; nX < nNewWidth; nX++ ) + pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nOtherY--, nOtherX ) ); + } + + aNewBmp.ReleaseAccess( pWriteAcc ); + } + + aRotatedBmp = aNewBmp; + } + else + { + Point aTmpPoint; + Rectangle aTmpRectangle( aTmpPoint, aSizePix ); + Polygon aPoly( aTmpRectangle ); + aPoly.Rotate( aTmpPoint, (USHORT) nAngle10 ); + + Rectangle aNewBound( aPoly.GetBoundRect() ); + const Size aNewSizePix( aNewBound.GetSize() ); + Bitmap aNewBmp( aNewSizePix, GetBitCount(), &pReadAcc->GetPalette() ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + + if( pWriteAcc ) + { + const BitmapColor aFillColor( pWriteAcc->GetBestMatchingColor( rFillColor ) ); + const double fCosAngle = cos( nAngle10 * F_PI1800 ); + const double fSinAngle = sin( nAngle10 * F_PI1800 ); + const double fXMin = aNewBound.Left(); + const double fYMin = aNewBound.Top(); + const long nWidth = aSizePix.Width(); + const long nHeight = aSizePix.Height(); + const long nNewWidth = aNewSizePix.Width(); + const long nNewHeight = aNewSizePix.Height(); + long nX; + long nY; + long nRotX; + long nRotY; + long nSinY; + long nCosY; + long* pCosX = new long[ nNewWidth ]; + long* pSinX = new long[ nNewWidth ]; + long* pCosY = new long[ nNewHeight ]; + long* pSinY = new long[ nNewHeight ]; + + for ( nX = 0; nX < nNewWidth; nX++ ) + { + const double fTmp = ( fXMin + nX ) * 64.; + + pCosX[ nX ] = FRound( fCosAngle * fTmp ); + pSinX[ nX ] = FRound( fSinAngle * fTmp ); + } + + for ( nY = 0; nY < nNewHeight; nY++ ) + { + const double fTmp = ( fYMin + nY ) * 64.; + + pCosY[ nY ] = FRound( fCosAngle * fTmp ); + pSinY[ nY ] = FRound( fSinAngle * fTmp ); + } + + for( nY = 0L; nY < nNewHeight; nY++ ) + { + nSinY = pSinY[ nY ]; + nCosY = pCosY[ nY ]; + + for( nX = 0L; nX < nNewWidth; nX++ ) + { + nRotX = ( pCosX[ nX ] - nSinY ) >> 6; + nRotY = ( pSinX[ nX ] + nCosY ) >> 6; + + if ( ( nRotX > -1L ) && ( nRotX < nWidth ) && ( nRotY > -1L ) && ( nRotY < nHeight ) ) + pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nRotY, nRotX ) ); + else + pWriteAcc->SetPixel( nY, nX, aFillColor ); + } + } + + delete[] pSinX; + delete[] pCosX; + delete[] pSinY; + delete[] pCosY; + + aNewBmp.ReleaseAccess( pWriteAcc ); + } + + aRotatedBmp = aNewBmp; + } + + ReleaseAccess( pReadAcc ); + } + + if( ( bRet = !!aRotatedBmp ) == TRUE ) + ImplAssignWithSize( aRotatedBmp ); + } + + return bRet; +}; + +// ------------------------------------------------------------------ + +BOOL Bitmap::Crop( const Rectangle& rRectPixel ) +{ + const Size aSizePix( GetSizePixel() ); + Rectangle aRect( rRectPixel ); + BOOL bRet = FALSE; + + aRect.Intersection( Rectangle( Point(), aSizePix ) ); + + if( !aRect.IsEmpty() ) + { + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + + if( pReadAcc ) + { + Point aTmpPoint; + const Rectangle aNewRect( aTmpPoint, aRect.GetSize() ); + Bitmap aNewBmp( aNewRect.GetSize(), GetBitCount(), &pReadAcc->GetPalette() ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + + if( pWriteAcc ) + { + const long nOldX = aRect.Left(); + const long nOldY = aRect.Top(); + const long nNewWidth = aNewRect.GetWidth(); + const long nNewHeight = aNewRect.GetHeight(); + + for( long nY = 0, nY2 = nOldY; nY < nNewHeight; nY++, nY2++ ) + for( long nX = 0, nX2 = nOldX; nX < nNewWidth; nX++, nX2++ ) + pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY2, nX2 ) ); + + aNewBmp.ReleaseAccess( pWriteAcc ); + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + + if( bRet ) + ImplAssignWithSize( aNewBmp ); + } + } + + return bRet; +}; + +// ------------------------------------------------------------------ + +BOOL Bitmap::CopyPixel( const Rectangle& rRectDst, + const Rectangle& rRectSrc, const Bitmap* pBmpSrc ) +{ + const Size aSizePix( GetSizePixel() ); + Rectangle aRectDst( rRectDst ); + BOOL bRet = FALSE; + + aRectDst.Intersection( Rectangle( Point(), aSizePix ) ); + + if( !aRectDst.IsEmpty() ) + { + if( pBmpSrc && ( *pBmpSrc != *this ) ) + { + Bitmap* pSrc = (Bitmap*) pBmpSrc; + const Size aCopySizePix( pSrc->GetSizePixel() ); + Rectangle aRectSrc( rRectSrc ); + const USHORT nSrcBitCount = pBmpSrc->GetBitCount(); + const USHORT nDstBitCount = GetBitCount(); + + if( nSrcBitCount > nDstBitCount ) + { + long nNextIndex = 0L; + + if( ( nSrcBitCount == 24 ) && ( nDstBitCount < 24 ) ) + Convert( BMP_CONVERSION_24BIT ); + else if( ( nSrcBitCount == 8 ) && ( nDstBitCount < 8 ) ) + { + Convert( BMP_CONVERSION_8BIT_COLORS ); + nNextIndex = 16; + } + else if( ( nSrcBitCount == 4 ) && ( nDstBitCount < 4 ) ) + { + Convert( BMP_CONVERSION_4BIT_COLORS ); + nNextIndex = 2; + } + + if( nNextIndex ) + { + BitmapReadAccess* pSrcAcc = pSrc->AcquireReadAccess(); + BitmapWriteAccess* pDstAcc = AcquireWriteAccess(); + + if( pSrcAcc && pDstAcc ) + { + const long nSrcCount = pDstAcc->GetPaletteEntryCount(); + const long nDstCount = 1 << nDstBitCount; + BOOL bFound; + + for( long i = 0L; ( i < nSrcCount ) && ( nNextIndex < nSrcCount ); i++ ) + { + const BitmapColor& rSrcCol = pSrcAcc->GetPaletteColor( (USHORT) i ); + + bFound = FALSE; + + for( long j = 0L; j < nDstCount; j++ ) + { + if( rSrcCol == pDstAcc->GetPaletteColor( (USHORT) j ) ) + { + bFound = TRUE; + break; + } + } + + if( !bFound ) + pDstAcc->SetPaletteColor( (USHORT) nNextIndex++, rSrcCol ); + } + } + + if( pSrcAcc ) + pSrc->ReleaseAccess( pSrcAcc ); + + if( pDstAcc ) + ReleaseAccess( pDstAcc ); + } + } + + aRectSrc.Intersection( Rectangle( Point(), aCopySizePix ) ); + + if( !aRectSrc.IsEmpty() ) + { + BitmapReadAccess* pReadAcc = pSrc->AcquireReadAccess(); + + if( pReadAcc ) + { + BitmapWriteAccess* pWriteAcc = AcquireWriteAccess(); + + if( pWriteAcc ) + { + const long nWidth = Min( aRectSrc.GetWidth(), aRectDst.GetWidth() ); + const long nHeight = Min( aRectSrc.GetHeight(), aRectDst.GetHeight() ); + const long nSrcEndX = aRectSrc.Left() + nWidth; + const long nSrcEndY = aRectSrc.Top() + nHeight; + long nDstY = aRectDst.Top(); + + if( pReadAcc->HasPalette() && pWriteAcc->HasPalette() ) + { + const USHORT nCount = pReadAcc->GetPaletteEntryCount(); + BYTE* pMap = new BYTE[ nCount ]; + + // Index-Map fuer Farbtabelle + // aufbauen, da das Bild ja (relativ) farbgenau + // kopiert werden soll + for( USHORT i = 0; i < nCount; i++ ) + pMap[ i ] = (BYTE) pWriteAcc->GetBestPaletteIndex( pReadAcc->GetPaletteColor( i ) ); + + for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ ) + for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ ) + pWriteAcc->SetPixel( nDstY, nDstX, pMap[ pReadAcc->GetPixel( nSrcY, nSrcX ).GetIndex() ] ); + + delete[] pMap; + } + else if( pReadAcc->HasPalette() ) + { + } + else + for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ ) + for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ ) + pWriteAcc->SetPixel( nDstY, nDstX, pReadAcc->GetPixel( nSrcY, nSrcX ) ); + + ReleaseAccess( pWriteAcc ); + bRet = ( nWidth > 0L ) && ( nHeight > 0L ); + } + + pSrc->ReleaseAccess( pReadAcc ); + } + } + } + else + { + Rectangle aRectSrc( rRectSrc ); + + aRectSrc.Intersection( Rectangle( Point(), aSizePix ) ); + + if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) ) + { + BitmapWriteAccess* pWriteAcc = AcquireWriteAccess(); + + if( pWriteAcc ) + { + const long nWidth = Min( aRectSrc.GetWidth(), aRectDst.GetWidth() ); + const long nHeight = Min( aRectSrc.GetHeight(), aRectDst.GetHeight() ); + const long nSrcX = aRectSrc.Left(); + const long nSrcY = aRectSrc.Top(); + const long nSrcEndX1 = nSrcX + nWidth - 1L; + const long nSrcEndY1 = nSrcY + nHeight - 1L; + const long nDstX = aRectDst.Left(); + const long nDstY = aRectDst.Top(); + const long nDstEndX1 = nDstX + nWidth - 1L; + const long nDstEndY1 = nDstY + nHeight - 1L; + + if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) ) + { + for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ ) + for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ ) + pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) ); + } + else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) ) + { + for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- ) + for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ ) + pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) ); + } + else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) ) + { + for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ ) + for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- ) + pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) ); + } + else + { + for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- ) + for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- ) + pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) ); + } + + ReleaseAccess( pWriteAcc ); + bRet = TRUE; + } + } + } + } + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::Expand( ULONG nDX, ULONG nDY, const Color* pInitColor ) +{ + BOOL bRet = FALSE; + + if( nDX || nDY ) + { + const Size aSizePixel( GetSizePixel() ); + const long nWidth = aSizePixel.Width(); + const long nHeight = aSizePixel.Height(); + const Size aNewSize( nWidth + nDX, nHeight + nDY ); + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + + if( pReadAcc ) + { +// Was soll den das ? +// BitmapPalette aBmpPal( pReadAcc ? pReadAcc->GetPalette() : BitmapPalette() ); + BitmapPalette aBmpPal( pReadAcc->GetPalette() ); + Bitmap aNewBmp( aNewSize, GetBitCount(), &aBmpPal ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + + if( pWriteAcc ) + { + BitmapColor aColor; + const ULONG nScanlineSize = pReadAcc->GetScanlineSize(); + const long nNewX = nWidth; + const long nNewY = nHeight; + const long nNewWidth = pWriteAcc->Width(); + const long nNewHeight = pWriteAcc->Height(); + long nX; + long nY; + + if( pInitColor ) + aColor = pWriteAcc->GetBestMatchingColor( *pInitColor ); + + for( nY = 0L; nY < nHeight; nY++ ) + { + pWriteAcc->CopyScanline( nY, *pReadAcc ); + + if( pInitColor && nDX ) + for( nX = nNewX; nX < nNewWidth; nX++ ) + pWriteAcc->SetPixel( nY, nX, aColor ); + } + + if( pInitColor && nDY ) + for( nY = nNewY; nY < nNewHeight; nY++ ) + for( nX = nNewX; nX < nNewWidth; nX++ ) + pWriteAcc->SetPixel( nY, nX, aColor ); + + aNewBmp.ReleaseAccess( pWriteAcc ); + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + + if( bRet ) + ImplAssignWithSize( aNewBmp ); + } + } + + return bRet; +} + +// ------------------------------------------------------------------ + +Bitmap Bitmap::CreateMask( const Color& rTransColor, ULONG nTol ) const +{ + Bitmap aNewBmp( GetSizePixel(), 1 ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + BOOL bRet = FALSE; + + if( pWriteAcc ) + { + BitmapReadAccess* pReadAcc = ( (Bitmap*) this )->AcquireReadAccess(); + + if( pReadAcc ) + { + const long nWidth = pReadAcc->Width(); + const long nHeight = pReadAcc->Height(); + const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) ); + const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); + + if( !nTol ) + { + const BitmapColor aTest( pReadAcc->GetBestMatchingColor( rTransColor ) ); + long nX, nY, nShift; + + if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_MSN_PAL || + pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_LSN_PAL ) + { + // optimized for 4Bit-MSN/LSN source palette + const BYTE cTest = aTest.GetIndex(); + const long nShiftInit = ( ( pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_MSN_PAL ) ? 4 : 0 ); + + if( pWriteAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL && + aWhite.GetIndex() == 1 ) + { + // optimized for 1Bit-MSB destination palette + for( nY = 0L; nY < nHeight; nY++ ) + { + Scanline pSrc = pReadAcc->GetScanline( nY ); + Scanline pDst = pWriteAcc->GetScanline( nY ); + for( nX = 0L, nShift = nShiftInit; nX < nWidth; nX++, nShift ^= 4 ) + { + if( cTest == ( ( pSrc[ nX >> 1 ] >> nShift ) & 0x0f ) ) + pDst[ nX >> 3 ] |= 1 << ( 7 - ( nX & 7 ) ); + else + pDst[ nX >> 3 ] &= ~( 1 << ( 7 - ( nX & 7 ) ) ); + } + } + } + else + { + for( nY = 0L; nY < nHeight; nY++ ) + { + Scanline pSrc = pReadAcc->GetScanline( nY ); + for( nX = 0L, nShift = nShiftInit; nX < nWidth; nX++, nShift ^= 4 ) + { + if( cTest == ( ( pSrc[ nX >> 1 ] >> nShift ) & 0x0f ) ) + pWriteAcc->SetPixel( nY, nX, aWhite ); + else + pWriteAcc->SetPixel( nY, nX, aBlack ); + } + } + } + } + else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) + { + // optimized for 8Bit source palette + const BYTE cTest = aTest.GetIndex(); + + if( pWriteAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL && + aWhite.GetIndex() == 1 ) + { + // optimized for 1Bit-MSB destination palette + for( nY = 0L; nY < nHeight; nY++ ) + { + Scanline pSrc = pReadAcc->GetScanline( nY ); + Scanline pDst = pWriteAcc->GetScanline( nY ); + for( nX = 0L; nX < nWidth; nX++ ) + { + if( cTest == pSrc[ nX ] ) + pDst[ nX >> 3 ] |= 1 << ( 7 - ( nX & 7 ) ); + else + pDst[ nX >> 3 ] &= ~( 1 << ( 7 - ( nX & 7 ) ) ); + } + } + } + else + { + for( nY = 0L; nY < nHeight; nY++ ) + { + Scanline pSrc = pReadAcc->GetScanline( nY ); + for( nX = 0L; nX < nWidth; nX++ ) + { + if( cTest == pSrc[ nX ] ) + pWriteAcc->SetPixel( nY, nX, aWhite ); + else + pWriteAcc->SetPixel( nY, nX, aBlack ); + } + } + } + } + else + { + // not optimized + for( nY = 0L; nY < nHeight; nY++ ) + { + for( nX = 0L; nX < nWidth; nX++ ) + { + if( aTest == pReadAcc->GetPixel( nY, nX ) ) + pWriteAcc->SetPixel( nY, nX, aWhite ); + else + pWriteAcc->SetPixel( nY, nX, aBlack ); + } + } + } + } + else + { + BitmapColor aCol; + long nR, nG, nB; + const long nMinR = MinMax( (long) rTransColor.GetRed() - nTol, 0, 255 ); + const long nMaxR = MinMax( (long) rTransColor.GetRed() + nTol, 0, 255 ); + const long nMinG = MinMax( (long) rTransColor.GetGreen() - nTol, 0, 255 ); + const long nMaxG = MinMax( (long) rTransColor.GetGreen() + nTol, 0, 255 ); + const long nMinB = MinMax( (long) rTransColor.GetBlue() - nTol, 0, 255 ); + const long nMaxB = MinMax( (long) rTransColor.GetBlue() + nTol, 0, 255 ); + + if( pReadAcc->HasPalette() ) + { + for( long nY = 0L; nY < nHeight; nY++ ) + { + for( long nX = 0L; nX < nWidth; nX++ ) + { + aCol = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ); + nR = aCol.GetRed(); + nG = aCol.GetGreen(); + nB = aCol.GetBlue(); + + if( nMinR <= nR && nMaxR >= nR && + nMinG <= nG && nMaxG >= nG && + nMinB <= nB && nMaxB >= nB ) + { + pWriteAcc->SetPixel( nY, nX, aWhite ); + } + else + pWriteAcc->SetPixel( nY, nX, aBlack ); + } + } + } + else + { + for( long nY = 0L; nY < nHeight; nY++ ) + { + for( long nX = 0L; nX < nWidth; nX++ ) + { + aCol = pReadAcc->GetPixel( nY, nX ); + nR = aCol.GetRed(); + nG = aCol.GetGreen(); + nB = aCol.GetBlue(); + + if( nMinR <= nR && nMaxR >= nR && + nMinG <= nG && nMaxG >= nG && + nMinB <= nB && nMaxB >= nB ) + { + pWriteAcc->SetPixel( nY, nX, aWhite ); + } + else + pWriteAcc->SetPixel( nY, nX, aBlack ); + } + } + } + } + + ( (Bitmap*) this )->ReleaseAccess( pReadAcc ); + bRet = TRUE; + } + + aNewBmp.ReleaseAccess( pWriteAcc ); + } + + if( bRet ) + { + aNewBmp.maPrefSize = maPrefSize; + aNewBmp.maPrefMapMode = maPrefMapMode; + } + else + aNewBmp = Bitmap(); + + return aNewBmp; +} + +// ------------------------------------------------------------------ + +Region Bitmap::CreateRegion( const Color& rColor, const Rectangle& rRect ) const +{ + Region aRegion; + Rectangle aRect( rRect ); + BitmapReadAccess* pReadAcc = ( (Bitmap*) this )->AcquireReadAccess(); + + aRect.Intersection( Rectangle( Point(), GetSizePixel() ) ); + aRect.Justify(); + + if( pReadAcc ) + { + Rectangle aSubRect; + const long nLeft = aRect.Left(); + const long nTop = aRect.Top(); + const long nRight = aRect.Right(); + const long nBottom = aRect.Bottom(); + const BitmapColor aMatch( pReadAcc->GetBestMatchingColor( rColor ) ); + + aRegion.ImplBeginAddRect(); + + for( long nY = nTop; nY <= nBottom; nY++ ) + { + aSubRect.Top() = aSubRect.Bottom() = nY; + + for( long nX = nLeft; nX <= nRight; ) + { + while( ( nX <= nRight ) && ( aMatch != pReadAcc->GetPixel( nY, nX ) ) ) + nX++; + + if( nX <= nRight ) + { + aSubRect.Left() = nX; + + while( ( nX <= nRight ) && ( aMatch == pReadAcc->GetPixel( nY, nX ) ) ) + nX++; + + aSubRect.Right() = nX - 1L; + aRegion.ImplAddRect( aSubRect ); + } + } + } + + aRegion.ImplEndAddRect(); + ( (Bitmap*) this )->ReleaseAccess( pReadAcc ); + } + else + aRegion = aRect; + + return aRegion; +} + +//fuer WIN16 Borland +#ifdef WIN +#pragma codeseg BITMAP_SEG1 +#endif + +// ------------------------------------------------------------------ + +BOOL Bitmap::Replace( const Bitmap& rMask, const Color& rReplaceColor ) +{ + BitmapReadAccess* pMaskAcc = ( (Bitmap&) rMask ).AcquireReadAccess(); + BitmapWriteAccess* pAcc = AcquireWriteAccess(); + BOOL bRet = FALSE; + + if( pMaskAcc && pAcc ) + { + const long nWidth = Min( pMaskAcc->Width(), pAcc->Width() ); + const long nHeight = Min( pMaskAcc->Height(), pAcc->Height() ); + const BitmapColor aMaskWhite( pMaskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); + BitmapColor aReplace; + + if( pAcc->HasPalette() ) + { + const USHORT nActColors = pAcc->GetPaletteEntryCount(); + const USHORT nMaxColors = 1 << pAcc->GetBitCount(); + + // erst einmal naechste Farbe nehmen + aReplace = pAcc->GetBestMatchingColor( rReplaceColor ); + + // falls Palettenbild, und die zu setzende Farbe ist nicht + // in der Palette, suchen wir nach freien Eintraegen (teuer) + if( pAcc->GetPaletteColor( (BYTE) aReplace ) != BitmapColor( rReplaceColor ) ) + { + // erst einmal nachsehen, ob wir unsere ReplaceColor + // nicht auf einen freien Platz am Ende der Palette + // setzen koennen + if( nActColors < nMaxColors ) + { + pAcc->SetPaletteEntryCount( nActColors + 1 ); + pAcc->SetPaletteColor( nActColors, rReplaceColor ); + aReplace = BitmapColor( (BYTE) nActColors ); + } + else + { + BOOL* pFlags = new BOOL[ nMaxColors ]; + + // alle Eintraege auf 0 setzen + memset( pFlags, 0, nMaxColors ); + + for( long nY = 0L; nY < nHeight; nY++ ) + for( long nX = 0L; nX < nWidth; nX++ ) + pFlags[ (BYTE) pAcc->GetPixel( nY, nX ) ] = TRUE; + + for( USHORT i = 0UL; i < nMaxColors; i++ ) + { + // Hurra, wir haben einen unbenutzten Eintrag + if( !pFlags[ i ] ) + { + pAcc->SetPaletteColor( (USHORT) i, rReplaceColor ); + aReplace = BitmapColor( (BYTE) i ); + } + } + + delete[] pFlags; + } + } + } + else + aReplace = rReplaceColor; + + for( long nY = 0L; nY < nHeight; nY++ ) + for( long nX = 0L; nX < nWidth; nX++ ) + if( pMaskAcc->GetPixel( nY, nX ) == aMaskWhite ) + pAcc->SetPixel( nY, nX, aReplace ); + } + + ( (Bitmap&) rMask ).ReleaseAccess( pMaskAcc ); + ReleaseAccess( pAcc ); + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::Replace( const AlphaMask& rAlpha, const Color& rMergeColor ) +{ + Bitmap aNewBmp( GetSizePixel(), 24 ); + BitmapReadAccess* pAcc = AcquireReadAccess(); + BitmapReadAccess* pAlphaAcc = ( (AlphaMask&) rAlpha ).AcquireReadAccess(); + BitmapWriteAccess* pNewAcc = aNewBmp.AcquireWriteAccess(); + BOOL bRet = FALSE; + + if( pAcc && pAlphaAcc && pNewAcc ) + { + BitmapColor aCol; + const long nWidth = Min( pAlphaAcc->Width(), pAcc->Width() ); + const long nHeight = Min( pAlphaAcc->Height(), pAcc->Height() ); + + for( long nY = 0L; nY < nHeight; nY++ ) + { + for( long nX = 0L; nX < nWidth; nX++ ) + { + aCol = pAcc->GetColor( nY, nX ); + pNewAcc->SetPixel( nY, nX, aCol.Merge( rMergeColor, 255 - (BYTE) pAlphaAcc->GetPixel( nY, nX ) ) ); + } + } + + bRet = TRUE; + } + + ReleaseAccess( pAcc ); + ( (AlphaMask&) rAlpha ).ReleaseAccess( pAlphaAcc ); + aNewBmp.ReleaseAccess( pNewAcc ); + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + + maPrefMapMode = aMap; + maPrefSize = aSize; + } + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::Replace( const Color& rSearchColor, const Color& rReplaceColor, ULONG nTol ) +{ + // Bitmaps with 1 bit color depth can cause problems + // if they have other entries than black/white in their palette + if( 1 == GetBitCount() ) + Convert( BMP_CONVERSION_4BIT_COLORS ); + + BitmapWriteAccess* pAcc = AcquireWriteAccess(); + BOOL bRet = FALSE; + + if( pAcc ) + { + const long nMinR = MinMax( (long) rSearchColor.GetRed() - nTol, 0, 255 ); + const long nMaxR = MinMax( (long) rSearchColor.GetRed() + nTol, 0, 255 ); + const long nMinG = MinMax( (long) rSearchColor.GetGreen() - nTol, 0, 255 ); + const long nMaxG = MinMax( (long) rSearchColor.GetGreen() + nTol, 0, 255 ); + const long nMinB = MinMax( (long) rSearchColor.GetBlue() - nTol, 0, 255 ); + const long nMaxB = MinMax( (long) rSearchColor.GetBlue() + nTol, 0, 255 ); + + if( pAcc->HasPalette() ) + { + for( USHORT i = 0, nPalCount = pAcc->GetPaletteEntryCount(); i < nPalCount; i++ ) + { + const BitmapColor& rCol = pAcc->GetPaletteColor( i ); + + if( nMinR <= rCol.GetRed() && nMaxR >= rCol.GetRed() && + nMinG <= rCol.GetGreen() && nMaxG >= rCol.GetGreen() && + nMinB <= rCol.GetBlue() && nMaxB >= rCol.GetBlue() ) + { + pAcc->SetPaletteColor( i, rReplaceColor ); + } + } + } + else + { + BitmapColor aCol; + const BitmapColor aReplace( pAcc->GetBestMatchingColor( rReplaceColor ) ); + + for( long nY = 0L, nHeight = pAcc->Height(); nY < nHeight; nY++ ) + { + for( long nX = 0L, nWidth = pAcc->Width(); nX < nWidth; nX++ ) + { + aCol = pAcc->GetPixel( nY, nX ); + + if( nMinR <= aCol.GetRed() && nMaxR >= aCol.GetRed() && + nMinG <= aCol.GetGreen() && nMaxG >= aCol.GetGreen() && + nMinB <= aCol.GetBlue() && nMaxB >= aCol.GetBlue() ) + { + pAcc->SetPixel( nY, nX, aReplace ); + } + } + } + } + + ReleaseAccess( pAcc ); + bRet = TRUE; + } + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::Replace( const Color* pSearchColors, const Color* pReplaceColors, + ULONG nColorCount, ULONG* _pTols ) +{ + // Bitmaps with 1 bit color depth can cause problems + // if they have other entries than black/white in their palette + if( 1 == GetBitCount() ) + Convert( BMP_CONVERSION_4BIT_COLORS ); + + BitmapWriteAccess* pAcc = AcquireWriteAccess(); + BOOL bRet = FALSE; + + if( pAcc ) + { + long* pMinR = new long[ nColorCount ]; + long* pMaxR = new long[ nColorCount ]; + long* pMinG = new long[ nColorCount ]; + long* pMaxG = new long[ nColorCount ]; + long* pMinB = new long[ nColorCount ]; + long* pMaxB = new long[ nColorCount ]; + long* pTols; + ULONG i; + + if( !_pTols ) + { + pTols = new long[ nColorCount ]; + memset( pTols, 0, nColorCount * sizeof( long ) ); + } + else + pTols = (long*) _pTols; + + for( i = 0UL; i < nColorCount; i++ ) + { + const Color& rCol = pSearchColors[ i ]; + const long nTol = pTols[ i ]; + + pMinR[ i ] = MinMax( (long) rCol.GetRed() - nTol, 0, 255 ); + pMaxR[ i ] = MinMax( (long) rCol.GetRed() + nTol, 0, 255 ); + pMinG[ i ] = MinMax( (long) rCol.GetGreen() - nTol, 0, 255 ); + pMaxG[ i ] = MinMax( (long) rCol.GetGreen() + nTol, 0, 255 ); + pMinB[ i ] = MinMax( (long) rCol.GetBlue() - nTol, 0, 255 ); + pMaxB[ i ] = MinMax( (long) rCol.GetBlue() + nTol, 0, 255 ); + } + + if( pAcc->HasPalette() ) + { + for( USHORT nEntry = 0, nPalCount = pAcc->GetPaletteEntryCount(); nEntry < nPalCount; nEntry++ ) + { + const BitmapColor& rCol = pAcc->GetPaletteColor( nEntry ); + + for( i = 0UL; i < nColorCount; i++ ) + { + if( pMinR[ i ] <= rCol.GetRed() && pMaxR[ i ] >= rCol.GetRed() && + pMinG[ i ] <= rCol.GetGreen() && pMaxG[ i ] >= rCol.GetGreen() && + pMinB[ i ] <= rCol.GetBlue() && pMaxB[ i ] >= rCol.GetBlue() ) + { + pAcc->SetPaletteColor( (USHORT)nEntry, pReplaceColors[ i ] ); + break; + } + } + } + } + else + { + BitmapColor aCol; + BitmapColor* pReplaces = new BitmapColor[ nColorCount ]; + + for( i = 0UL; i < nColorCount; i++ ) + pReplaces[ i ] = pAcc->GetBestMatchingColor( pReplaceColors[ i ] ); + + for( long nY = 0L, nHeight = pAcc->Height(); nY < nHeight; nY++ ) + { + for( long nX = 0L, nWidth = pAcc->Width(); nX < nWidth; nX++ ) + { + aCol = pAcc->GetPixel( nY, nX ); + + for( i = 0UL; i < nColorCount; i++ ) + { + if( pMinR[ i ] <= aCol.GetRed() && pMaxR[ i ] >= aCol.GetRed() && + pMinG[ i ] <= aCol.GetGreen() && pMaxG[ i ] >= aCol.GetGreen() && + pMinB[ i ] <= aCol.GetBlue() && pMaxB[ i ] >= aCol.GetBlue() ) + { + pAcc->SetPixel( nY, nX, pReplaces[ i ] ); + break; + } + } + } + } + + delete[] pReplaces; + } + + if( !_pTols ) + delete[] pTols; + + delete[] pMinR; + delete[] pMaxR; + delete[] pMinG; + delete[] pMaxG; + delete[] pMinB; + delete[] pMaxB; + ReleaseAccess( pAcc ); + bRet = TRUE; + } + + return bRet; +} + +// ------------------------------------------------------------------ + +Bitmap Bitmap::CreateDisplayBitmap( OutputDevice* pDisplay ) +{ + Bitmap aDispBmp( *this ); + +#ifndef REMOTE_APPSERVER + if( mpImpBmp && ( pDisplay->mpGraphics || pDisplay->ImplGetGraphics() ) ) + { + ImpBitmap* pImpDispBmp = new ImpBitmap; + + if( pImpDispBmp->ImplCreate( *mpImpBmp, pDisplay->mpGraphics ) ) + aDispBmp.ImplSetImpBitmap( pImpDispBmp ); + else + delete pImpDispBmp; + } +#endif + + return aDispBmp; +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::CombineSimple( const Bitmap& rMask, BmpCombine eCombine ) +{ + BitmapReadAccess* pMaskAcc = ( (Bitmap&) rMask ).AcquireReadAccess(); + BitmapWriteAccess* pAcc = AcquireWriteAccess(); + BOOL bRet = FALSE; + + if( pMaskAcc && pAcc ) + { + const long nWidth = Min( pMaskAcc->Width(), pAcc->Width() ); + const long nHeight = Min( pMaskAcc->Height(), pAcc->Height() ); + const Color aColBlack( COL_BLACK ); + BitmapColor aPixel; + BitmapColor aMaskPixel; + const BitmapColor aWhite( pAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); + const BitmapColor aBlack( pAcc->GetBestMatchingColor( aColBlack ) ); + const BitmapColor aMaskBlack( pMaskAcc->GetBestMatchingColor( aColBlack ) ); + + switch( eCombine ) + { + case( BMP_COMBINE_COPY ): + { + for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) + { + if( pMaskAcc->GetPixel( nY, nX ) == aMaskBlack ) + pAcc->SetPixel( nY, nX, aBlack ); + else + pAcc->SetPixel( nY, nX, aWhite ); + } + } + break; + + case( BMP_COMBINE_INVERT ): + { + for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) + { + if( pAcc->GetPixel( nY, nX ) == aBlack ) + pAcc->SetPixel( nY, nX, aWhite ); + else + pAcc->SetPixel( nY, nX, aBlack ); + } + } + break; + + case( BMP_COMBINE_AND ): + { + for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) + { + if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack && pAcc->GetPixel( nY, nX ) != aBlack ) + pAcc->SetPixel( nY, nX, aWhite ); + else + pAcc->SetPixel( nY, nX, aBlack ); + } + } + break; + + case( BMP_COMBINE_NAND ): + { + for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) + { + if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack && pAcc->GetPixel( nY, nX ) != aBlack ) + pAcc->SetPixel( nY, nX, aBlack ); + else + pAcc->SetPixel( nY, nX, aWhite ); + } + } + break; + + case( BMP_COMBINE_OR ): + { + for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) + { + if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack || pAcc->GetPixel( nY, nX ) != aBlack ) + pAcc->SetPixel( nY, nX, aWhite ); + else + pAcc->SetPixel( nY, nX, aBlack ); + } + } + break; + + case( BMP_COMBINE_NOR ): + { + for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) + { + if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack || pAcc->GetPixel( nY, nX ) != aBlack ) + pAcc->SetPixel( nY, nX, aBlack ); + else + pAcc->SetPixel( nY, nX, aWhite ); + } + } + break; + + case( BMP_COMBINE_XOR ): + { + for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) + { + aPixel = pAcc->GetPixel( nY, nX ); + aMaskPixel = pMaskAcc->GetPixel( nY, nX ); + + if( ( aMaskPixel != aMaskBlack && aPixel == aBlack ) || + ( aMaskPixel == aMaskBlack && aPixel != aBlack ) ) + { + pAcc->SetPixel( nY, nX, aWhite ); + } + else + pAcc->SetPixel( nY, nX, aBlack ); + } + } + break; + + case( BMP_COMBINE_NXOR ): + { + for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) + { + aPixel = pAcc->GetPixel( nY, nX ); + aMaskPixel = pMaskAcc->GetPixel( nY, nX ); + + if( ( aMaskPixel != aMaskBlack && aPixel == aBlack ) || + ( aMaskPixel == aMaskBlack && aPixel != aBlack ) ) + { + pAcc->SetPixel( nY, nX, aBlack ); + } + else + pAcc->SetPixel( nY, nX, aWhite ); + } + } + break; + } + } + + ( (Bitmap&) rMask ).ReleaseAccess( pMaskAcc ); + ReleaseAccess( pAcc ); + + return bRet; +} + +// ------------------------------------------------------------------ + +#ifdef REMOTE_APPSERVER + +void Bitmap::ImplDrawRemote( OutputDevice* pOut, + const Point& rSrcPt, const Size& rSrcSz, + const Point& rDestPt, const Size& rDestSz ) const +{ + if( mpImpBmp ) + { + if( !mpImpBmp->ImplGetRemoteBmp() ) + mpImpBmp->ImplCreateRemoteBmp( *this ); + + mpImpBmp->ImplDrawRemoteBmp( pOut, rSrcPt, rSrcSz, rDestPt, rDestSz ); + } +} + +// ------------------------------------------------------------------ + +void Bitmap::ImplDrawRemoteEx( OutputDevice* pOut, + const Point& rSrcPt, const Size& rSrcSz, + const Point& rDestPt, const Size& rDestSz, + const Bitmap& rMask ) const +{ + if( mpImpBmp ) + { + if( !mpImpBmp->ImplGetRemoteBmp() ) + mpImpBmp->ImplCreateRemoteBmp( *this ); + + mpImpBmp->ImplDrawRemoteBmpEx( pOut, rSrcPt, rSrcSz, rDestPt, rDestSz, rMask ); + } +} + +// ------------------------------------------------------------------ + +void Bitmap::ImplDrawRemoteAlpha( OutputDevice* pOut, + const Point& rSrcPt, const Size& rSrcSz, + const Point& rDestPt, const Size& rDestSz, + const AlphaMask& rAlpha ) const +{ + if( mpImpBmp ) + { + if( !mpImpBmp->ImplGetRemoteBmp() ) + mpImpBmp->ImplCreateRemoteBmp( *this ); + + mpImpBmp->ImplDrawRemoteBmpAlpha( pOut, rSrcPt, rSrcSz, rDestPt, rDestSz, rAlpha ); + } +} + +// ------------------------------------------------------------------ + +void Bitmap::ImplDrawRemoteMask( OutputDevice* pOut, + const Point& rSrcPt, const Size& rSrcSz, + const Point& rDestPt, const Size& rDestSz, + const Color& rColor ) const +{ + if( mpImpBmp ) + { + if( !mpImpBmp->ImplGetRemoteBmp() ) + mpImpBmp->ImplCreateRemoteBmp( *this ); + + mpImpBmp->ImplDrawRemoteBmpMask( pOut, rSrcPt, rSrcSz, rDestPt, rDestSz, rColor ); + } +} + +// ------------------------------------------------------------------ + +void Bitmap::ImplGetRemoteBmp( OutputDevice* pOut, const Point& rPt, const Size& rSz ) +{ + DBG_ASSERT( !mpImpBmp, "Bitmap::ImplGetRemoteBmp???" ); + + mpImpBmp = new ImpBitmap; + mpImpBmp->ImplCreateRemoteBmp( *this, pOut, rPt, rSz ); +} + +#endif diff --git a/vcl/source/gdi/bitmap2.cxx b/vcl/source/gdi/bitmap2.cxx new file mode 100644 index 000000000000..e4e4c407fc18 --- /dev/null +++ b/vcl/source/gdi/bitmap2.cxx @@ -0,0 +1,1269 @@ +/************************************************************************* + * + * $RCSfile: bitmap2.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifdef WIN +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#endif + +#define _SV_BITMAP_CXX + +#include <tools/zcodec.hxx> +#ifndef _TOOLS_NEW_HXX +#include <tools/new.hxx> +#endif +#ifndef _TOOLS_STREAM_HXX +#include <tools/stream.hxx> +#endif +#ifndef _SV_SALBTYPE_HXX +#include <salbtype.hxx> +#endif +#ifndef _SV_BMPACC_HXX +#include <bmpacc.hxx> +#endif +#ifndef _SV_OUTDEV_HXX +#include <outdev.hxx> +#endif +#ifndef _SV_BITMAP_HXX +#include <bitmap.hxx> +#endif + +#define USE_ZCODEC + +// ----------- +// - Defines - +// ----------- + +#define DIBCOREHEADERSIZE ( 12UL ) +#define DIBINFOHEADERSIZE ( sizeof( DIBInfoHeader ) ) +#define SETPIXEL4( pBuf, nX, cChar )( (pBuf)[ (nX) >> 1 ] |= ( (nX) & 1 ) ? ( cChar ): (cChar) << 4 ); + +// ---------------------- +// - Compression defines +// ---------------------- + +#define COMPRESS_OWN ('S'|('D'<<8UL)) +#define COMPRESS_NONE ( 0UL ) +#define RLE_8 ( 1UL ) +#define RLE_4 ( 2UL ) +#define BITFIELDS ( 3UL ) +#define ZCOMPRESS ( COMPRESS_OWN | 0x01000000UL ) /* == 'SD01' (binary) */ + +// ----------------- +// - DIBInfoHeader - +// ----------------- + +struct DIBInfoHeader +{ + UINT32 nSize; + UINT32 nWidth; + UINT32 nHeight; + UINT16 nPlanes; + UINT16 nBitCount; + UINT32 nCompression; + UINT32 nSizeImage; + UINT32 nXPelsPerMeter; + UINT32 nYPelsPerMeter; + UINT32 nColsUsed; + UINT32 nColsImportant; + + DIBInfoHeader() : + nSize( 0UL ), + nWidth( 0UL ), + nHeight( 0UL ), + nPlanes( 0 ), + nBitCount( 0 ), + nCompression( 0UL ), + nSizeImage( 0UL ), + nXPelsPerMeter( 0UL ), + nYPelsPerMeter( 0UL ), + nColsUsed( 0UL ), + nColsImportant( 0UL ) {} + + ~DIBInfoHeader() {} +}; + +// ---------- +// - Bitmap - +// ---------- + +SvStream& operator>>( SvStream& rIStm, Bitmap& rBitmap ) +{ + rBitmap.Read( rIStm, TRUE ); + return rIStm; +} + +// ------------------------------------------------------------------ + +SvStream& operator<<( SvStream& rOStm, const Bitmap& rBitmap ) +{ + rBitmap.Write( rOStm, FALSE, TRUE ); + return rOStm; +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::Read( SvStream& rIStm, BOOL bFileHeader ) +{ + const USHORT nOldFormat = rIStm.GetNumberFormatInt(); + const ULONG nOldPos = rIStm.Tell(); + ULONG nOffset = 0UL; + BOOL bRet = FALSE; + + rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + + if( bFileHeader ) + { + if( ImplReadDIBFileHeader( rIStm, nOffset ) ) + bRet = ImplReadDIB( rIStm, *this, nOffset ); + } + else + bRet = ImplReadDIB( rIStm, *this, nOffset ); + + if( !bRet ) + { + if( !rIStm.GetError() ) + rIStm.SetError( SVSTREAM_GENERALERROR ); + + rIStm.Seek( nOldPos ); + } + + rIStm.SetNumberFormatInt( nOldFormat ); + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::ImplReadDIB( SvStream& rIStm, Bitmap& rBmp, ULONG nOffset ) +{ + DIBInfoHeader aHeader; + const ULONG nStmPos = rIStm.Tell(); + BitmapPalette* pPalette = NULL; + BOOL bHeaderRead = FALSE; + BOOL bRet = FALSE; + + if( ImplReadDIBInfoHeader( rIStm, aHeader ) && aHeader.nWidth && aHeader.nHeight && aHeader.nBitCount ) + { + USHORT nBitCount = ( aHeader.nBitCount <= 1 ) ? 1 : + ( aHeader.nBitCount <= 4 ) ? 4 : + ( aHeader.nBitCount <= 8 ) ? 8 : 24; + + const Size aSizePixel( aHeader.nWidth, aHeader.nHeight ); + BitmapPalette aDummyPal; + Bitmap aNewBmp( aSizePixel, nBitCount, &aDummyPal ); + BitmapWriteAccess* pAcc = aNewBmp.AcquireWriteAccess(); + + if( pAcc ) + { + USHORT nColors; + SvStream* pIStm; + SvMemoryStream* pMemStm = NULL; + BYTE* pData = NULL; + + if( nBitCount <= 8 ) + { + if( aHeader.nColsUsed ) + nColors = (USHORT) aHeader.nColsUsed; + else + nColors = ( 1 << aHeader.nBitCount ); + } + else + nColors = 0; + +#ifdef USE_ZCODEC + if( ZCOMPRESS == aHeader.nCompression ) + { + ZCodec aCodec; + ULONG nCodedSize, nUncodedSize; + ULONG nCodedPos; + + // read coding information + rIStm >> nCodedSize >> nUncodedSize >> aHeader.nCompression; + pData = (BYTE*) SvMemAlloc( nUncodedSize ); + + // decode buffer + nCodedPos = rIStm.Tell(); + aCodec.BeginCompression(); + aCodec.Read( rIStm, pData, nUncodedSize ); + aCodec.EndCompression(); + + // skip unread bytes from coded buffer + rIStm.SeekRel( nCodedSize - ( rIStm.Tell() - nCodedPos ) ); + + // set decoded bytes to memory stream, + // from which we will read the bitmap data + pIStm = pMemStm = new SvMemoryStream; + pMemStm->SetBuffer( (char*) pData, nUncodedSize, FALSE, nUncodedSize ); + nOffset = 0; + } + else +#endif // USE_ZCODEC + pIStm = &rIStm; + + // read palette + if( nColors ) + { + pAcc->SetPaletteEntryCount( nColors ); + ImplReadDIBPalette( *pIStm, *pAcc, aHeader.nSize != DIBCOREHEADERSIZE ); + } + + // read bits + if( !pIStm->GetError() ) + { + if( nOffset ) + pIStm->SeekRel( nOffset - ( pIStm->Tell() - nStmPos ) ); + + bRet = ImplReadDIBBits( *pIStm, aHeader, *pAcc ); + + if( bRet && aHeader.nXPelsPerMeter && aHeader.nYPelsPerMeter ) + { + MapMode aMapMode( MAP_MM, Point(), + Fraction( 1000, aHeader.nXPelsPerMeter ), + Fraction( 1000, aHeader.nYPelsPerMeter ) ); + + aNewBmp.SetPrefMapMode( aMapMode ); + aNewBmp.SetPrefSize( Size( aHeader.nWidth, aHeader.nHeight ) ); + } + } + + if( pData ) + SvMemFree( pData ); + + delete pMemStm; + aNewBmp.ReleaseAccess( pAcc ); + + if( bRet ) + rBmp = aNewBmp; + } + } + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::ImplReadDIBFileHeader( SvStream& rIStm, ULONG& rOffset ) +{ + UINT32 nTmp32; + UINT16 nTmp16; + BOOL bRet = FALSE; + + rIStm >> nTmp16; + + if ( ( 0x4D42 == nTmp16 ) || ( 0x4142 == nTmp16 ) ) + { + if ( 0x4142 == nTmp16 ) + { + rIStm.SeekRel( 12L ); + rIStm >> nTmp16; + rIStm.SeekRel( 8L ); + rIStm >> nTmp32; + rOffset = nTmp32 - 28UL;; + bRet = ( 0x4D42 == nTmp16 ); + } + else + { + rIStm.SeekRel( 8L ); + rIStm >> nTmp32; + rOffset = nTmp32 - 14UL; + bRet = ( rIStm.GetError() == 0UL ); + } + } + else + rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR ); + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::ImplReadDIBInfoHeader( SvStream& rIStm, DIBInfoHeader& rHeader ) +{ + // BITMAPINFOHEADER or BITMAPCOREHEADER + rIStm >> rHeader.nSize; + + // BITMAPCOREHEADER + if ( rHeader.nSize == DIBCOREHEADERSIZE ) + { + UINT16 nTmp16; + + rIStm >> nTmp16; rHeader.nWidth = nTmp16; + rIStm >> nTmp16; rHeader.nHeight = nTmp16; + rIStm >> nTmp16; rHeader.nPlanes = nTmp16; + rIStm >> nTmp16; rHeader.nBitCount = nTmp16; + } + else + { + // unknown Header + if( rHeader.nSize < DIBINFOHEADERSIZE ) + { + ULONG nUnknownSize = sizeof( rHeader.nSize ); + + rIStm >> rHeader.nWidth; nUnknownSize += sizeof( rHeader.nWidth ); + rIStm >> rHeader.nHeight; nUnknownSize += sizeof( rHeader.nHeight ); + rIStm >> rHeader.nPlanes; nUnknownSize += sizeof( rHeader.nPlanes ); + rIStm >> rHeader.nBitCount; nUnknownSize += sizeof( rHeader.nBitCount ); + + if( nUnknownSize < rHeader.nSize ) + { + rIStm >> rHeader.nCompression; + nUnknownSize += sizeof( rHeader.nCompression ); + + if( nUnknownSize < rHeader.nSize ) + { + rIStm >> rHeader.nSizeImage; + nUnknownSize += sizeof( rHeader.nSizeImage ); + + if( nUnknownSize < rHeader.nSize ) + { + rIStm >> rHeader.nXPelsPerMeter; + nUnknownSize += sizeof( rHeader.nXPelsPerMeter ); + + if( nUnknownSize < rHeader.nSize ) + { + rIStm >> rHeader.nYPelsPerMeter; + nUnknownSize += sizeof( rHeader.nYPelsPerMeter ); + } + + if( nUnknownSize < rHeader.nSize ) + { + rIStm >> rHeader.nColsUsed; + nUnknownSize += sizeof( rHeader.nColsUsed ); + + if( nUnknownSize < rHeader.nSize ) + { + rIStm >> rHeader.nColsImportant; + nUnknownSize += sizeof( rHeader.nColsImportant ); + } + } + } + } + } + } + else + { + rIStm >> rHeader.nWidth; + rIStm >> rHeader.nHeight; + rIStm >> rHeader.nPlanes; + rIStm >> rHeader.nBitCount; + rIStm >> rHeader.nCompression; + rIStm >> rHeader.nSizeImage; + rIStm >> rHeader.nXPelsPerMeter; + rIStm >> rHeader.nYPelsPerMeter; + rIStm >> rHeader.nColsUsed; + rIStm >> rHeader.nColsImportant; + } + + // Eventuell bis zur Palette ueberlesen + if ( rHeader.nSize > DIBINFOHEADERSIZE ) + rIStm.SeekRel( rHeader.nSize - DIBINFOHEADERSIZE ); + } + + return( ( rHeader.nPlanes == 1 ) && ( rIStm.GetError() == 0UL ) ); +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::ImplReadDIBPalette( SvStream& rIStm, BitmapWriteAccess& rAcc, BOOL bQuad ) +{ + const USHORT nColors = rAcc.GetPaletteEntryCount(); + const ULONG nPalSize = nColors * ( bQuad ? 4UL : 3UL ); + BitmapColor aPalColor; + + BYTE* pEntries = new BYTE[ nPalSize ]; + rIStm.Read( pEntries, nPalSize ); + + BYTE* pTmpEntry = pEntries; + for( USHORT i = 0; i < nColors; i++ ) + { + aPalColor.SetBlue( *pTmpEntry++ ); + aPalColor.SetGreen( *pTmpEntry++ ); + aPalColor.SetRed( *pTmpEntry++ ); + + if( bQuad ) + pTmpEntry++; + + rAcc.SetPaletteColor( i, aPalColor ); + } + + delete[] pEntries; + + return( rIStm.GetError() == 0UL ); +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::ImplReadDIBBits( SvStream& rIStm, DIBInfoHeader& rHeader, BitmapWriteAccess& rAcc ) +{ + const ULONG nAlignedWidth = AlignedWidth4Bytes( rHeader.nWidth * rHeader.nBitCount ); + UINT32 nRMask; + UINT32 nGMask; + UINT32 nBMask; + BOOL bNative; + BOOL bTCMask = ( rHeader.nBitCount == 16 ) || ( rHeader.nBitCount == 32 ); + BOOL bRLE = ( RLE_8 == rHeader.nCompression && rHeader.nBitCount == 8 ) || + ( RLE_4 == rHeader.nCompression && rHeader.nBitCount == 4 ); + + // Is native format? + switch( rAcc.GetScanlineFormat() ) + { + case( BMP_FORMAT_1BIT_MSB_PAL ): + case( BMP_FORMAT_4BIT_MSN_PAL ): + case( BMP_FORMAT_8BIT_PAL ): + case( BMP_FORMAT_24BIT_TC_BGR ): + bNative = ( rAcc.IsBottomUp() && !bRLE && !bTCMask && ( rAcc.GetScanlineSize() == nAlignedWidth ) ); + break; + + default: + bNative = FALSE; + break; + } + + // Read data + if( bNative ) + { + // true color DIB's can have a (optimization) palette + if( rHeader.nColsUsed && rHeader.nBitCount > 8 ) + rIStm.SeekRel( rHeader.nColsUsed * ( ( rHeader.nSize != DIBCOREHEADERSIZE ) ? 4 : 3 ) ); + + rIStm.Read( rAcc.GetBuffer(), rHeader.nHeight * nAlignedWidth ); + } + else + { + // Read color mask + if( bTCMask ) + { + if( rHeader.nCompression == BITFIELDS ) + { + rIStm.SeekRel( -12L ); + rIStm >> nRMask; + rIStm >> nGMask; + rIStm >> nBMask; + } + else + { + nRMask = ( rHeader.nBitCount == 16 ) ? 0x00007c00UL : 0x00ff0000UL; + nGMask = ( rHeader.nBitCount == 16 ) ? 0x000003e0UL : 0x0000ff00UL; + nBMask = ( rHeader.nBitCount == 16 ) ? 0x0000001fUL : 0x000000ffUL; + } + } + + if( bRLE ) + { + if ( !rHeader.nSizeImage ) + { + const ULONG nOldPos = rIStm.Tell(); + + rIStm.Seek( STREAM_SEEK_TO_END ); + rHeader.nSizeImage = rIStm.Tell() - nOldPos; + rIStm.Seek( nOldPos ); + } + + BYTE* pBuffer = (BYTE*) SvMemAlloc( rHeader.nSizeImage ); + + rIStm.Read( (char*) pBuffer, rHeader.nSizeImage ); + ImplDecodeRLE( pBuffer, rHeader, rAcc, RLE_4 == rHeader.nCompression ); + + SvMemFree( pBuffer ); + } + else + { + const long nWidth = rHeader.nWidth; + const long nHeight = rHeader.nHeight; + BYTE* pBuf = new BYTE[ nAlignedWidth ]; + + // true color DIB's can have a (optimization) palette + if( rHeader.nColsUsed && rHeader.nBitCount > 8 ) + rIStm.SeekRel( rHeader.nColsUsed * ( ( rHeader.nSize != DIBCOREHEADERSIZE ) ? 4 : 3 ) ); + + switch( rHeader.nBitCount ) + { + case( 1 ): + { + BYTE* pTmp; + BYTE cTmp; + + for( long nY = nHeight - 1; nY >= 0L; nY-- ) + { + rIStm.Read( pTmp = pBuf, nAlignedWidth ); + cTmp = *pTmp++; + + for( long nX = 0L, nShift = 8L; nX < nWidth; nX++ ) + { + if( !nShift ) + { + nShift = 8L, + cTmp = *pTmp++; + } + + rAcc.SetPixel( nY, nX, ( cTmp >> --nShift ) & 1 ); + } + } + } + break; + + case( 4 ): + { + BYTE* pTmp; + BYTE cTmp; + + for( long nY = nHeight - 1; nY >= 0L; nY-- ) + { + rIStm.Read( pTmp = pBuf, nAlignedWidth ); + cTmp = *pTmp++; + + for( long nX = 0L, nShift = 2L; nX < nWidth; nX++ ) + { + if( !nShift ) + { + nShift = 2UL, + cTmp = *pTmp++; + } + + rAcc.SetPixel( nY, nX, ( cTmp >> ( --nShift << 2UL ) ) & 0x0f ); + } + } + } + break; + + case( 8 ): + { + BYTE* pTmp; + + for( long nY = nHeight - 1; nY >= 0L; nY-- ) + { + rIStm.Read( pTmp = pBuf, nAlignedWidth ); + + for( long nX = 0L; nX < nWidth; nX++ ) + rAcc.SetPixel( nY, nX, *pTmp++ ); + } + } + break; + + case( 16 ): + { + ColorMask aMask( nRMask, nGMask, nBMask ); + BitmapColor aColor; + UINT16* pTmp16; + + for( long nY = rHeader.nHeight - 1L; nY >= 0L; nY-- ) + { + rIStm.Read( (char*)( pTmp16 = (UINT16*) pBuf ), nAlignedWidth ); + + for( long nX = 0L; nX < nWidth; nX++ ) + { + aMask.GetColorFor16Bit( aColor, (BYTE*) pTmp16++ ); + rAcc.SetPixel( nY, nX, aColor ); + } + } + } + break; + + case( 24 ): + { + BitmapColor aPixelColor; + BYTE* pTmp; + + for( long nY = nHeight - 1; nY >= 0L; nY-- ) + { + rIStm.Read( pTmp = pBuf, nAlignedWidth ); + + for( long nX = 0L; nX < nWidth; nX++ ) + { + aPixelColor.SetBlue( *pTmp++ ); + aPixelColor.SetGreen( *pTmp++ ); + aPixelColor.SetRed( *pTmp++ ); + rAcc.SetPixel( nY, nX, aPixelColor ); + } + } + } + break; + + case( 32 ): + { + ColorMask aMask( nRMask, nGMask, nBMask ); + BitmapColor aColor; + UINT32* pTmp32; + + for( long nY = rHeader.nHeight - 1L; nY >= 0L; nY-- ) + { + rIStm.Read( (char*)( pTmp32 = (UINT32*) pBuf ), nAlignedWidth ); + + for( long nX = 0L; nX < nWidth; nX++ ) + { + aMask.GetColorFor32Bit( aColor, (BYTE*) pTmp32++ ); + rAcc.SetPixel( nY, nX, aColor ); + } + } + } + } + + delete[] pBuf; + } + } + + return( rIStm.GetError() == 0UL ); +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::Write( SvStream& rOStm, BOOL bCompressed, BOOL bFileHeader ) const +{ + BMP_ASSERT( mpImpBmp, "Empty Bitmaps can't be saved" ); + + const Size aSizePix( GetSizePixel() ); + BOOL bRet = FALSE; + + if( mpImpBmp && aSizePix.Width() && aSizePix.Height() ) + { + BitmapReadAccess* pAcc = ( (Bitmap*) this)->AcquireReadAccess(); + const USHORT nOldFormat = rOStm.GetNumberFormatInt(); + const ULONG nOldPos = rOStm.Tell(); + + rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + + if( pAcc ) + { + if( bFileHeader ) + { + if( ImplWriteDIBFileHeader( rOStm, *pAcc ) ) + bRet = ImplWriteDIB( rOStm, *pAcc, bCompressed ); + } + else + bRet = ImplWriteDIB( rOStm, *pAcc, bCompressed ); + + ( (Bitmap*) this)->ReleaseAccess( pAcc ); + } + + if( !bRet ) + { + rOStm.SetError( SVSTREAM_GENERALERROR ); + rOStm.Seek( nOldPos ); + } + + rOStm.SetNumberFormatInt( nOldFormat ); + } + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::ImplWriteDIB( SvStream& rOStm, BitmapReadAccess& rAcc, BOOL bCompressed ) const +{ + DIBInfoHeader aHeader; + ULONG nImageSizePos; + ULONG nEndPos; + ULONG nCompression = 0UL; + BOOL bRet = FALSE; + + aHeader.nSize = DIBINFOHEADERSIZE; + aHeader.nWidth = rAcc.Width(); + aHeader.nHeight = rAcc.Height(); + aHeader.nPlanes = 1; + + switch( rAcc.GetScanlineFormat() ) + { + case( BMP_FORMAT_16BIT_TC_MASK ): + case( BMP_FORMAT_32BIT_TC_MASK ): + { + aHeader.nBitCount = ( rAcc.GetScanlineFormat() == BMP_FORMAT_16BIT_TC_MASK ) ? 16 : 32; + nCompression = BITFIELDS; + } + break; + + default: + { + aHeader.nBitCount = rAcc.GetBitCount(); + + if( bCompressed ) + { + if( 4 == aHeader.nBitCount ) + nCompression = RLE_4; + else if( 8 == aHeader.nBitCount ) + nCompression = RLE_8; + } + else + nCompression = COMPRESS_NONE; + } + break; + } + +#ifdef USE_ZCODEC + if( ( rOStm.GetCompressMode() & COMPRESSMODE_ZBITMAP ) && + ( rOStm.GetVersion() >= SOFFICE_FILEFORMAT_40 ) ) + { + aHeader.nCompression = ZCOMPRESS; + } + else +#endif // USE_ZCODEC + aHeader.nCompression = nCompression; + + aHeader.nSizeImage = rAcc.Height() * rAcc.GetScanlineSize(); + + if( maPrefSize.Width() && maPrefSize.Height() ) + { + const Size aSize100( OutputDevice::LogicToLogic( maPrefSize, maPrefMapMode, MAP_100TH_MM ) ); + + if( aSize100.Width() && aSize100.Height() ) + { + aHeader.nXPelsPerMeter = ( rAcc.Width() * 100000UL ) / aSize100.Width(); + aHeader.nYPelsPerMeter = ( rAcc.Height() * 100000UL ) / aSize100.Height(); + } + } + + aHeader.nColsUsed = ( ( aHeader.nBitCount <= 8 ) ? rAcc.GetPaletteEntryCount() : 0 ); + aHeader.nColsImportant = 0; + + rOStm << aHeader.nSize; + rOStm << aHeader.nWidth; + rOStm << aHeader.nHeight; + rOStm << aHeader.nPlanes; + rOStm << aHeader.nBitCount; + rOStm << aHeader.nCompression; + + nImageSizePos = rOStm.Tell(); + rOStm.SeekRel( sizeof( aHeader.nSizeImage ) ); + + rOStm << aHeader.nXPelsPerMeter; + rOStm << aHeader.nYPelsPerMeter; + rOStm << aHeader.nColsUsed; + rOStm << aHeader.nColsImportant; + +#ifdef USE_ZCODEC + if( aHeader.nCompression == ZCOMPRESS ) + { + ZCodec aCodec; + SvMemoryStream aMemStm( aHeader.nSizeImage + 4096, 65535 ); + ULONG nCodedPos = rOStm.Tell(), nLastPos; + ULONG nCodedSize, nUncodedSize; + + // write uncoded data palette + if( aHeader.nColsUsed ) + ImplWriteDIBPalette( aMemStm, rAcc ); + + // write uncoded bits + bRet = ImplWriteDIBBits( aMemStm, rAcc, nCompression, aHeader.nSizeImage ); + + // get uncoded size + nUncodedSize = aMemStm.Tell(); + + // seek over compress info + rOStm.SeekRel( 12 ); + + // write compressed data + aCodec.BeginCompression( 3 ); + aCodec.Write( rOStm, (BYTE*) aMemStm.GetData(), nUncodedSize ); + aCodec.EndCompression(); + + // update compress info ( coded size, uncoded size, uncoded compression ) + nCodedSize = ( nLastPos = rOStm.Tell() ) - nCodedPos - 12; + rOStm.Seek( nCodedPos ); + rOStm << nCodedSize << nUncodedSize << nCompression; + rOStm.Seek( nLastPos ); + + if( bRet ) + bRet = ( rOStm.GetError() == ERRCODE_NONE ); + } + else +#endif // USE_ZCODEC + { + if( aHeader.nColsUsed ) + ImplWriteDIBPalette( rOStm, rAcc ); + + bRet = ImplWriteDIBBits( rOStm, rAcc, aHeader.nCompression, aHeader.nSizeImage ); + } + + nEndPos = rOStm.Tell(); + rOStm.Seek( nImageSizePos ); + rOStm << aHeader.nSizeImage; + rOStm.Seek( nEndPos ); + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::ImplWriteDIBFileHeader( SvStream& rOStm, BitmapReadAccess& rAcc ) +{ + UINT32 nPalCount = ( rAcc.HasPalette() ? rAcc.GetPaletteEntryCount() : rAcc.HasColorMask() ? 3UL : 0UL ); + UINT32 nOffset = 14 + DIBINFOHEADERSIZE + nPalCount * 4UL; + + rOStm << (UINT16) 0x4D42; + rOStm << (UINT32) ( nOffset + ( rAcc.Height() * rAcc.GetScanlineSize() ) ); + rOStm << (UINT16) 0; + rOStm << (UINT16) 0; + rOStm << nOffset; + + return( rOStm.GetError() == 0UL ); +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::ImplWriteDIBPalette( SvStream& rOStm, BitmapReadAccess& rAcc ) +{ + const USHORT nColors = rAcc.GetPaletteEntryCount(); + const ULONG nPalSize = nColors * 4UL; + BYTE* pEntries = new BYTE[ nPalSize ]; + BYTE* pTmpEntry = pEntries; + BitmapColor aPalColor; + + for( USHORT i = 0; i < nColors; i++ ) + { + const BitmapColor& rPalColor = rAcc.GetPaletteColor( i ); + + *pTmpEntry++ = rPalColor.GetBlue(); + *pTmpEntry++ = rPalColor.GetGreen(); + *pTmpEntry++ = rPalColor.GetRed(); + *pTmpEntry++ = 0; + } + + rOStm.Write( pEntries, nPalSize ); + delete[] pEntries; + + return( rOStm.GetError() == 0UL ); +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::ImplWriteDIBBits( SvStream& rOStm, BitmapReadAccess& rAcc, + ULONG nCompression, ULONG& rImageSize ) +{ + if( BITFIELDS == nCompression ) + { + const ColorMask& rMask = rAcc.GetColorMask(); + SVBT32 aVal32; + + LongToSVBT32( rMask.GetRedMask(), aVal32 ); + rOStm.Write( (BYTE*) aVal32, 4UL ); + + LongToSVBT32( rMask.GetGreenMask(), aVal32 ); + rOStm.Write( (BYTE*) aVal32, 4UL ); + + LongToSVBT32( rMask.GetBlueMask(), aVal32 ); + rOStm.Write( (BYTE*) aVal32, 4UL ); + + rImageSize = rOStm.Tell(); + + if( rAcc.IsBottomUp() ) + rOStm.Write( rAcc.GetBuffer(), rAcc.Height() * rAcc.GetScanlineSize() ); + else + { + for( long nY = rAcc.Height() - 1, nScanlineSize = rAcc.GetScanlineSize(); nY >= 0L; nY-- ) + rOStm.Write( rAcc.GetScanline( nY ), nScanlineSize ); + } + } + else if( ( RLE_4 == nCompression ) || ( RLE_8 == nCompression ) ) + { + rImageSize = rOStm.Tell(); + ImplWriteRLE( rOStm, rAcc, RLE_4 == nCompression ); + } + else if( !nCompression ) + { + const ULONG nAlignedWidth = AlignedWidth4Bytes( rAcc.Width() * rAcc.GetBitCount() ); + BOOL bNative = FALSE; + + switch( rAcc.GetScanlineFormat() ) + { + case( BMP_FORMAT_1BIT_MSB_PAL ): + case( BMP_FORMAT_4BIT_MSN_PAL ): + case( BMP_FORMAT_8BIT_PAL ): + case( BMP_FORMAT_24BIT_TC_BGR ): + { + if( rAcc.IsBottomUp() && ( rAcc.GetScanlineSize() == nAlignedWidth ) ) + bNative = TRUE; + } + break; + + default: + break; + } + + rImageSize = rOStm.Tell(); + + if( bNative ) + rOStm.Write( rAcc.GetBuffer(), nAlignedWidth * rAcc.Height() ); + else + { + const long nWidth = rAcc.Width(); + const long nHeight = rAcc.Height(); + BYTE* pBuf = new BYTE[ nAlignedWidth ]; + BYTE* pTmp; + BYTE cTmp; + + switch( rAcc.GetBitCount() ) + { + case( 1 ): + { + for( long nY = nHeight - 1; nY >= 0L; nY-- ) + { + pTmp = pBuf; + cTmp = 0; + + for( long nX = 0L, nShift = 8L; nX < nWidth; nX++ ) + { + if( !nShift ) + { + nShift = 8L; + *pTmp++ = cTmp; + cTmp = 0; + } + + cTmp |= ( (BYTE) rAcc.GetPixel( nY, nX ) << --nShift ); + } + + *pTmp = cTmp; + rOStm.Write( pBuf, nAlignedWidth ); + } + } + break; + + case( 4 ): + { + for( long nY = nHeight - 1; nY >= 0L; nY-- ) + { + pTmp = pBuf; + cTmp = 0; + + for( long nX = 0L, nShift = 2L; nX < nWidth; nX++ ) + { + if( !nShift ) + { + nShift = 2L; + *pTmp++ = cTmp; + cTmp = 0; + } + + cTmp |= ( (BYTE) rAcc.GetPixel( nY, nX ) << ( --nShift << 2L ) ); + } + *pTmp = cTmp; + rOStm.Write( pBuf, nAlignedWidth ); + } + } + break; + + case( 8 ): + { + for( long nY = nHeight - 1; nY >= 0L; nY-- ) + { + pTmp = pBuf; + + for( long nX = 0L; nX < nWidth; nX++ ) + *pTmp++ = rAcc.GetPixel( nY, nX ); + + rOStm.Write( pBuf, nAlignedWidth ); + } + } + break; + + default: + { + BitmapColor aPixelColor; + + for( long nY = nHeight - 1; nY >= 0L; nY-- ) + { + pTmp = pBuf; + + for( long nX = 0L; nX < nWidth; nX++ ) + { + aPixelColor = rAcc.GetPixel( nY, nX ); + *pTmp++ = aPixelColor.GetBlue(); + *pTmp++ = aPixelColor.GetGreen(); + *pTmp++ = aPixelColor.GetRed(); + } + + rOStm.Write( pBuf, nAlignedWidth ); + } + } + break; + } + + delete[] pBuf; + } + } + + rImageSize = rOStm.Tell() - rImageSize; + + return( rOStm.GetError() == 0UL ); +} + +// ------------------------------------------------------------------ + +void Bitmap::ImplDecodeRLE( BYTE* pBuffer, DIBInfoHeader& rHeader, + BitmapWriteAccess& rAcc, BOOL bRLE4 ) +{ + Scanline pRLE = pBuffer; + long nY = rHeader.nHeight - 1L; + const ULONG nWidth = rAcc.Width(); + ULONG nCountByte; + ULONG nRunByte; + ULONG nX = 0UL; + BYTE cTmp; + BOOL bEndDecoding = FALSE; + + do + { + if( !( nCountByte = *pRLE++ ) ) + { + nRunByte = *pRLE++; + + if( nRunByte > 2 ) + { + if( bRLE4 ) + { + nCountByte = nRunByte >> 1; + + for( ULONG i = 0UL; i < nCountByte; i++ ) + { + cTmp = *pRLE++; + + if( nX < nWidth ) + rAcc.SetPixel( nY, nX++, cTmp >> 4 ); + + if( nX < nWidth ) + rAcc.SetPixel( nY, nX++, cTmp & 0x0f ); + } + + if( nRunByte & 1 ) + { + if( nX < nWidth ) + rAcc.SetPixel( nY, nX++, *pRLE >> 4 ); + + pRLE++; + } + + if( ( ( nRunByte + 1 ) >> 1 ) & 1 ) + pRLE++; + } + else + { + for( ULONG i = 0UL; i < nRunByte; i++ ) + { + if( nX < nWidth ) + rAcc.SetPixel( nY, nX++, *pRLE ); + + pRLE++; + } + + if( nRunByte & 1 ) + pRLE++; + } + } + else if( !nRunByte ) + { + nY--; + nX = 0UL; + } + else if( nRunByte == 1 ) + bEndDecoding = TRUE; + else + { + nX += *pRLE++; + nY -= *pRLE++; + } + } + else + { + cTmp = *pRLE++; + + if( bRLE4 ) + { + nRunByte = nCountByte >> 1; + + for( ULONG i = 0UL; i < nRunByte; i++ ) + { + if( nX < nWidth ) + rAcc.SetPixel( nY, nX++, cTmp >> 4 ); + + if( nX < nWidth ) + rAcc.SetPixel( nY, nX++, cTmp & 0x0f ); + } + + if( ( nCountByte & 1 ) && ( nX < nWidth ) ) + rAcc.SetPixel( nY, nX++, cTmp >> 4 ); + } + else + { + for( ULONG i = 0UL; ( i < nCountByte ) && ( nX < nWidth ); i++ ) + rAcc.SetPixel( nY, nX++, cTmp ); + } + } + } + while ( !bEndDecoding && ( nY >= 0L ) ); +} + +// ------------------------------------------------------------------ + +BOOL Bitmap::ImplWriteRLE( SvStream& rOStm, BitmapReadAccess& rAcc, BOOL bRLE4 ) +{ + const ULONG nWidth = rAcc.Width(); + const ULONG nHeight = rAcc.Height(); + ULONG nX; + ULONG nSaveIndex; + ULONG nCount; + ULONG nBufCount; + BYTE* pBuf = new BYTE[ nWidth << 1 ]; + BYTE* pTmp; + BYTE cPix; + BYTE cLast; + BOOL bFound; + + for ( long nY = nHeight - 1L; nY >= 0L; nY-- ) + { + pTmp = pBuf; + nX = nBufCount = 0UL; + + while( nX < nWidth ) + { + nCount = 1L; + cPix = rAcc.GetPixel( nY, nX++ ); + + while( ( nX < nWidth ) && ( nCount < 255L ) && ( cPix == rAcc.GetPixel( nY, nX ) ) ) + { + nX++; + nCount++; + } + + if ( nCount > 1 ) + { + *pTmp++ = (BYTE) nCount; + *pTmp++ = ( bRLE4 ? ( ( cPix << 4 ) | cPix ) : cPix ); + nBufCount += 2; + } + else + { + cLast = cPix; + nSaveIndex = nX - 1UL; + bFound = FALSE; + + while( ( nX < nWidth ) && ( nCount < 256L ) && ( cPix = rAcc.GetPixel( nY, nX ) ) != cLast ) + { + nX++; nCount++; + cLast = cPix; + bFound = TRUE; + } + + if ( bFound ) + nX--; + + if ( nCount > 3 ) + { + *pTmp++ = 0; + *pTmp++ = (BYTE) --nCount; + + if( bRLE4 ) + { + for ( ULONG i = 0; i < nCount; i++, pTmp++ ) + { + *pTmp = (BYTE) rAcc.GetPixel( nY, nSaveIndex++ ) << 4; + + if ( ++i < nCount ) + *pTmp |= rAcc.GetPixel( nY, nSaveIndex++ ); + } + + nCount = ( nCount + 1 ) >> 1; + } + else + { + for( ULONG i = 0UL; i < nCount; i++ ) + *pTmp++ = rAcc.GetPixel( nY, nSaveIndex++ ); + } + + if ( nCount & 1 ) + { + *pTmp++ = 0; + nBufCount += ( nCount + 3 ); + } + else + nBufCount += ( nCount + 2 ); + } + else + { + *pTmp++ = 1; + *pTmp++ = (BYTE) rAcc.GetPixel( nY, nSaveIndex ) << ( bRLE4 ? 4 : 0 ); + + if ( nCount == 3 ) + { + *pTmp++ = 1; + *pTmp++ = (BYTE) rAcc.GetPixel( nY, ++nSaveIndex ) << ( bRLE4 ? 4 : 0 ); + nBufCount += 4; + } + else + nBufCount += 2; + } + } + } + + pBuf[ nBufCount++ ] = 0; + pBuf[ nBufCount++ ] = 0; + + rOStm.Write( pBuf, nBufCount ); + } + + rOStm << (BYTE) 0; + rOStm << (BYTE) 1; + + delete[] pBuf; + + return( rOStm.GetError() == 0UL ); +} diff --git a/vcl/source/gdi/bitmap3.cxx b/vcl/source/gdi/bitmap3.cxx new file mode 100644 index 000000000000..34776a8b00bf --- /dev/null +++ b/vcl/source/gdi/bitmap3.cxx @@ -0,0 +1,2248 @@ +/************************************************************************* + * + * $RCSfile: bitmap3.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <stdlib.h> +#define _SV_BITMAP_CXX + +#ifdef W31 +#include <tools/svwin.h> +#endif +#include <tools/new.hxx> +#ifndef _SV_BMPACC_HXX +#include <bmpacc.hxx> +#endif +#ifndef _SV_IMPOCT_HXX +#include <impoct.hxx> +#endif +#ifndef _SV_OCTREE_HXX +#include <octree.hxx> +#endif +#ifndef _SV_IMPVECT_HXX +#include <impvect.hxx> +#endif +#ifndef _SV_BITMAPEX_HXX +#include <bitmapex.hxx> +#endif +#ifndef _SV_BITMAP_HXX +#include <bitmap.hxx> +#endif + +// ----------- +// - Defines - +// ----------- + +#define RGB15( _def_cR, _def_cG, _def_cB ) (((ULONG)(_def_cR)<<10UL)|((ULONG)(_def_cG)<<5UL)|(ULONG)(_def_cB)) +#define GAMMA( _def_cVal, _def_InvGamma ) ((BYTE)MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0L,255L)) + +#define CALC_ERRORS \ + nTemp = p1T[nX++] >> 12; \ + nBErr = MinMax( nTemp, 0, 255 ); \ + nBErr = nBErr - FloydIndexMap[ nBC = FloydMap[nBErr] ]; \ + nTemp = p1T[nX++] >> 12; \ + nGErr = MinMax( nTemp, 0, 255 ); \ + nGErr = nGErr - FloydIndexMap[ nGC = FloydMap[nGErr] ]; \ + nTemp = p1T[nX] >> 12; \ + nRErr = MinMax( nTemp, 0, 255 ); \ + nRErr = nRErr - FloydIndexMap[ nRC = FloydMap[nRErr] ]; + +#define CALC_TABLES3 \ + p2T[nX++] += FloydError3[nBErr]; \ + p2T[nX++] += FloydError3[nGErr]; \ + p2T[nX++] += FloydError3[nRErr]; + +#define CALC_TABLES5 \ + p2T[nX++] += FloydError5[nBErr]; \ + p2T[nX++] += FloydError5[nGErr]; \ + p2T[nX++] += FloydError5[nRErr]; + +#define CALC_TABLES7 \ + p1T[++nX] += FloydError7[nBErr]; \ + p2T[nX++] += FloydError1[nBErr]; \ + p1T[nX] += FloydError7[nGErr]; \ + p2T[nX++] += FloydError1[nGErr]; \ + p1T[nX] += FloydError7[nRErr]; \ + p2T[nX] += FloydError1[nRErr]; + +// ----------- +// - Statics - +// ----------- + +ULONG nVCLRLut[ 6 ] = { 16, 17, 18, 19, 20, 21 }; +ULONG nVCLGLut[ 6 ] = { 0, 6, 12, 18, 24, 30 }; +ULONG nVCLBLut[ 6 ] = { 0, 36, 72, 108, 144, 180 }; + +// ------------------------------------------------------------------------ + +ULONG nVCLDitherLut[ 256 ] = +{ + 0, 49152, 12288, 61440, 3072, 52224, 15360, 64512, 768, 49920, 13056, + 62208, 3840, 52992, 16128, 65280, 32768, 16384, 45056, 28672, 35840, 19456, + 48128, 31744, 33536, 17152, 45824, 29440, 36608, 20224, 48896, 32512, 8192, + 57344, 4096, 53248, 11264, 60416, 7168, 56320, 8960, 58112, 4864, 54016, + 12032, 61184, 7936, 57088, 40960, 24576, 36864, 20480, 44032, 27648, 39936, + 23552, 41728, 25344, 37632, 21248, 44800, 28416, 40704, 24320, 2048, 51200, + 14336, 63488, 1024, 50176, 13312, 62464, 2816, 51968, 15104, 64256, 1792, + 50944, 14080, 63232, 34816, 18432, 47104, 30720, 33792, 17408, 46080, 29696, + 35584, 19200, 47872, 31488, 34560, 18176, 46848, 30464, 10240, 59392, 6144, + 55296, 9216, 58368, 5120, 54272, 11008, 60160, 6912, 56064, 9984, 59136, + 5888, 55040, 43008, 26624, 38912, 22528, 41984, 25600, 37888, 21504, 43776, + 27392, 39680, 23296, 42752, 26368, 38656, 22272, 512, 49664, 12800, 61952, + 3584, 52736, 15872, 65024, 256, 49408, 12544, 61696, 3328, 52480, 15616, + 64768, 33280, 16896, 45568, 29184, 36352, 19968, 48640, 32256, 33024, 16640, + 45312, 28928, 36096, 19712, 48384, 32000, 8704, 57856, 4608, 53760, 11776, + 60928, 7680, 56832, 8448, 57600, 4352, 53504, 11520, 60672, 7424, 56576, + 41472, 25088, 37376, 20992, 44544, 28160, 40448, 24064, 41216, 24832, 37120, + 20736, 44288, 27904, 40192, 23808, 2560, 51712, 14848, 64000, 1536, 50688, + 13824, 62976, 2304, 51456, 14592, 63744, 1280, 50432, 13568, 62720, 35328, + 18944, 47616, 31232, 34304, 17920, 46592, 30208, 35072, 18688, 47360, 30976, + 34048, 17664, 46336, 29952, 10752, 59904, 6656, 55808, 9728, 58880, 5632, + 54784, 10496, 59648, 6400, 55552, 9472, 58624, 5376, 54528, 43520, 27136, + 39424, 23040, 42496, 26112, 38400, 22016, 43264, 26880, 39168, 22784, 42240, + 25856, 38144, 21760 +}; + +// ------------------------------------------------------------------------ + +ULONG nVCLLut[ 256 ] = +{ + 0, 1286, 2572, 3858, 5144, 6430, 7716, 9002, + 10288, 11574, 12860, 14146, 15432, 16718, 18004, 19290, + 20576, 21862, 23148, 24434, 25720, 27006, 28292, 29578, + 30864, 32150, 33436, 34722, 36008, 37294, 38580, 39866, + 41152, 42438, 43724, 45010, 46296, 47582, 48868, 50154, + 51440, 52726, 54012, 55298, 56584, 57870, 59156, 60442, + 61728, 63014, 64300, 65586, 66872, 68158, 69444, 70730, + 72016, 73302, 74588, 75874, 77160, 78446, 79732, 81018, + 82304, 83590, 84876, 86162, 87448, 88734, 90020, 91306, + 92592, 93878, 95164, 96450, 97736, 99022,100308,101594, + 102880,104166,105452,106738,108024,109310,110596,111882, + 113168,114454,115740,117026,118312,119598,120884,122170, + 123456,124742,126028,127314,128600,129886,131172,132458, + 133744,135030,136316,137602,138888,140174,141460,142746, + 144032,145318,146604,147890,149176,150462,151748,153034, + 154320,155606,156892,158178,159464,160750,162036,163322, + 164608,165894,167180,168466,169752,171038,172324,173610, + 174896,176182,177468,178754,180040,181326,182612,183898, + 185184,186470,187756,189042,190328,191614,192900,194186, + 195472,196758,198044,199330,200616,201902,203188,204474, + 205760,207046,208332,209618,210904,212190,213476,214762, + 216048,217334,218620,219906,221192,222478,223764,225050, + 226336,227622,228908,230194,231480,232766,234052,235338, + 236624,237910,239196,240482,241768,243054,244340,245626, + 246912,248198,249484,250770,252056,253342,254628,255914, + 257200,258486,259772,261058,262344,263630,264916,266202, + 267488,268774,270060,271346,272632,273918,275204,276490, + 277776,279062,280348,281634,282920,284206,285492,286778, + 288064,289350,290636,291922,293208,294494,295780,297066, + 298352,299638,300924,302210,303496,304782,306068,307354, + 308640,309926,311212,312498,313784,315070,316356,317642, + 318928,320214,321500,322786,324072,325358,326644,327930 +}; + +// ------------------------------------------------------------------------ + +long FloydMap[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 +}; + +// ------------------------------------------------------------------------ + +long FloydError1[61] = +{ + -7680, -7424, -7168, -6912, -6656, -6400, -6144, + -5888, -5632, -5376, -5120, -4864, -4608, -4352, + -4096, -3840, -3584, -3328, -3072, -2816, -2560, + -2304, -2048, -1792, -1536, -1280, -1024, -768, + -512, -256, 0, 256, 512, 768, 1024, 1280, 1536, + 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584, + 3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632, + 5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680 +}; + +// ------------------------------------------------------------------------ + +long FloydError3[61] = +{ + -23040, -22272, -21504, -20736, -19968, -19200, + -18432, -17664, -16896, -16128, -15360, -14592, + -13824, -13056, -12288, -11520, -10752, -9984, + -9216, -8448, -7680, -6912, -6144, -5376, -4608, + -3840, -3072, -2304, -1536, -768, 0, 768, 1536, + 2304, 3072, 3840, 4608, 5376, 6144, 6912, 7680, + 8448, 9216, 9984, 10752, 11520, 12288, 13056, + 13824, 14592, 15360, 16128, 16896, 17664, 18432, + 19200, 19968, 20736, 21504, 22272, 23040 +}; + +// ------------------------------------------------------------------------ + +long FloydError5[61] = +{ + -38400, -37120, -35840, -34560, -33280, -32000, + -30720, -29440, -28160, -26880, -25600, -24320, + -23040, -21760, -20480, -19200, -17920, -16640, + -15360, -14080, -12800, -11520, -10240, -8960, + -7680, -6400, -5120, -3840, -2560, -1280, 0, + 1280, 2560, 3840, 5120, 6400, 7680, 8960, 10240, + 11520, 12800, 14080, 15360, 16640, 17920, 19200, + 20480, 21760, 23040, 24320, 25600, 26880, 28160, + 29440, 30720, 32000, 33280, 34560, 35840, 37120, + 38400 +}; + +// ------------------------------------------------------------------------ + +long FloydError7[61] = +{ + -53760, -51968, -50176, -48384, -46592, -44800, + -43008, -41216, -39424, -37632, -35840, -34048, + -32256, -30464, -28672, -26880, -25088, -23296, + -21504, -19712, -17920, -16128, -14336, -12544, + -10752, -8960, -7168, -5376, -3584, -1792, 0, + 1792, 3584, 5376, 7168, 8960, 10752, 12544, 14336, + 16128, 17920, 19712, 21504, 23296, 25088, 26880, + 28672, 30464, 32256, 34048, 35840, 37632, 39424, + 41216, 43008, 44800, 46592, 48384, 50176, 51968, + 53760 +}; + +// ------------------------------------------------------------------------ + +long FloydIndexMap[6] = +{ + -30, 21, 72, 123, 174, 225 +}; + +// -------------------------- +// - ImplCreateDitherMatrix - +// -------------------------- + +void ImplCreateDitherMatrix( BYTE (*pDitherMatrix)[16][16] ) +{ + double fVal = 3.125; + const double fVal16 = fVal / 16.; + long i, j, k, l; + USHORT pMtx[ 16 ][ 16 ]; + USHORT nMax = 0; + static BYTE pMagic[4][4] = { 0, 14, 3, 13, + 11, 5, 8, 6, + 12, 2, 15, 1, + 7, 9, 4, 10 }; + + // MagicSquare aufbauen + for ( i = 0; i < 4; i++ ) + for ( j = 0; j < 4; j++ ) + for ( k = 0; k < 4; k++ ) + for ( l = 0; l < 4; l++ ) + nMax = Max ( pMtx[ (k<<2) + i][(l<<2 ) + j] = + (USHORT) ( 0.5 + pMagic[i][j]*fVal + pMagic[k][l]*fVal16 ), nMax ); + + // auf Intervall [0;254] skalieren + for ( i = 0, fVal = 254. / nMax; i < 16; i++ ) + for( j = 0; j < 16; j++ ) + (*pDitherMatrix)[i][j] = (BYTE) ( fVal * pMtx[i][j] ); +} + +// ---------- +// - Bitmap - +// ---------- + +BOOL Bitmap::Convert( BmpConversion eConversion ) +{ + const USHORT nBitCount = GetBitCount(); + BOOL bRet = FALSE; + + switch( eConversion ) + { + case( BMP_CONVERSION_1BIT_THRESHOLD ): + bRet = ImplMakeMono( 128 ); + break; + + case( BMP_CONVERSION_1BIT_MATRIX ): + bRet = ImplMakeMonoDither(); + break; + + case( BMP_CONVERSION_4BIT_GREYS ): + bRet = ImplMakeGreyscales( 16 ); + break; + + case( BMP_CONVERSION_4BIT_COLORS ): + { + if( nBitCount < 4 ) + bRet = ImplConvertUp( 4, NULL ); + else if( nBitCount > 4 ) + bRet = ImplConvertDown( 4, NULL ); + else + bRet = TRUE; + } + break; + + case( BMP_CONVERSION_4BIT_TRANS ): + { + Color aTrans( BMP_COL_TRANS ); + + if( nBitCount < 4 ) + bRet = ImplConvertUp( 4, &aTrans ); + else + bRet = ImplConvertDown( 4, &aTrans ); + } + break; + + case( BMP_CONVERSION_8BIT_GREYS ): + bRet = ImplMakeGreyscales( 256 ); + break; + + case( BMP_CONVERSION_8BIT_COLORS ): + { + if( nBitCount < 8 ) + bRet = ImplConvertUp( 8 ); + else if( nBitCount > 8 ) + bRet = ImplConvertDown( 8 ); + else + bRet = TRUE; + } + break; + + case( BMP_CONVERSION_8BIT_TRANS ): + { + Color aTrans( BMP_COL_TRANS ); + + if( nBitCount < 8 ) + bRet = ImplConvertUp( 8, &aTrans ); + else + bRet = ImplConvertDown( 8, &aTrans ); + } + break; + + case( BMP_CONVERSION_24BIT ): + { + if( nBitCount < 24 ) + bRet = ImplConvertUp( 24, FALSE ); + else + bRet = TRUE; + } + break; + + case( BMP_CONVERSION_GHOSTED ): + bRet = ImplConvertGhosted(); + break; + + default: + DBG_ERROR( "Bitmap::Convert(): Unsupported conversion" ); + break; + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::ImplMakeMono( BYTE cThreshold ) +{ + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + BOOL bRet = FALSE; + + if( pReadAcc ) + { + Bitmap aNewBmp( GetSizePixel(), 1 ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + + if( pWriteAcc ) + { + const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) ); + const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); + const long nWidth = pWriteAcc->Width(); + const long nHeight = pWriteAcc->Height(); + + if( pReadAcc->HasPalette() ) + { + for( long nY = 0L; nY < nHeight; nY++ ) + { + for( long nX = 0L; nX < nWidth; nX++ ) + { + if( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >= + cThreshold ) + { + pWriteAcc->SetPixel( nY, nX, aWhite ); + } + else + pWriteAcc->SetPixel( nY, nX, aBlack ); + } + } + } + else + { + for( long nY = 0L; nY < nHeight; nY++ ) + { + for( long nX = 0L; nX < nWidth; nX++ ) + { + if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >= + cThreshold ) + { + pWriteAcc->SetPixel( nY, nX, aWhite ); + } + else + pWriteAcc->SetPixel( nY, nX, aBlack ); + } + } + } + + aNewBmp.ReleaseAccess( pWriteAcc ); + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + + maPrefMapMode = aMap; + maPrefSize = aSize; + } + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::ImplMakeMonoDither() +{ + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + BOOL bRet = FALSE; + + if( pReadAcc ) + { + Bitmap aNewBmp( GetSizePixel(), 1 ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + + if( pWriteAcc ) + { + const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) ); + const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); + const long nWidth = pWriteAcc->Width(); + const long nHeight = pWriteAcc->Height(); + BYTE pDitherMatrix[ 16 ][ 16 ]; + + ImplCreateDitherMatrix( &pDitherMatrix ); + + if( pReadAcc->HasPalette() ) + { + for( long nY = 0L; nY < nHeight; nY++ ) + { + for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ ) + { + if( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() > + pDitherMatrix[ nModY ][ nX % 16 ] ) + { + pWriteAcc->SetPixel( nY, nX, aWhite ); + } + else + pWriteAcc->SetPixel( nY, nX, aBlack ); + } + } + } + else + { + for( long nY = 0L; nY < nHeight; nY++ ) + { + for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ ) + { + if( pReadAcc->GetPixel( nY, nX ).GetLuminance() > + pDitherMatrix[ nModY ][ nX % 16 ] ) + { + pWriteAcc->SetPixel( nY, nX, aWhite ); + } + else + pWriteAcc->SetPixel( nY, nX, aBlack ); + } + } + } + + aNewBmp.ReleaseAccess( pWriteAcc ); + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + + maPrefMapMode = aMap; + maPrefSize = aSize; + } + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::ImplMakeGreyscales( USHORT nGreys ) +{ + DBG_ASSERT( nGreys == 16 || nGreys == 256, "Only 16 or 256 greyscales are supported!" ) + + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + BOOL bRet = FALSE; + + if( pReadAcc ) + { + const BitmapPalette& rPal = GetGreyPalette( nGreys ); + ULONG nShift = ( ( nGreys == 16 ) ? 4UL : 0UL ); + BOOL bPalDiffers = !pReadAcc->HasPalette() || ( rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount() ); + + if( !bPalDiffers ) + bPalDiffers = ( (BitmapPalette&) rPal != pReadAcc->GetPalette() ); + + if( bPalDiffers ) + { + Bitmap aNewBmp( GetSizePixel(), ( nGreys == 16 ) ? 4 : 8, &rPal ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + + if( pWriteAcc ) + { + const long nWidth = pWriteAcc->Width(); + const long nHeight = pWriteAcc->Height(); + + if( pReadAcc->HasPalette() ) + { + for( long nY = 0L; nY < nHeight; nY++ ) + { + for( long nX = 0L; nX < nWidth; nX++ ) + { + pWriteAcc->SetPixel( nY, nX, + (BYTE) ( pReadAcc->GetPaletteColor( + pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift ) ); + } + } + } + else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR && + pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) + { + nShift += 8; + + for( long nY = 0L; nY < nHeight; nY++ ) + { + Scanline pReadScan = pReadAcc->GetScanline( nY ); + Scanline pWriteScan = pWriteAcc->GetScanline( nY ); + + for( long nX = 0L; nX < nWidth; nX++ ) + { + const ULONG nB = *pReadScan++; + const ULONG nG = *pReadScan++; + const ULONG nR = *pReadScan++; + + *pWriteScan++ = (BYTE) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift ); + } + } + } + else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB && + pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) + { + nShift += 8; + + for( long nY = 0L; nY < nHeight; nY++ ) + { + Scanline pReadScan = pReadAcc->GetScanline( nY ); + Scanline pWriteScan = pWriteAcc->GetScanline( nY ); + + for( long nX = 0L; nX < nWidth; nX++ ) + { + const ULONG nR = *pReadScan++; + const ULONG nG = *pReadScan++; + const ULONG nB = *pReadScan++; + + *pWriteScan++ = (BYTE) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift ); + } + } + } + else + { + for( long nY = 0L; nY < nHeight; nY++ ) + for( long nX = 0L; nX < nWidth; nX++ ) + pWriteAcc->SetPixel( nY, nX, ( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift ); + } + + aNewBmp.ReleaseAccess( pWriteAcc ); + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + + maPrefMapMode = aMap; + maPrefSize = aSize; + } + } + else + { + ReleaseAccess( pReadAcc ); + bRet = TRUE; + } + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::ImplConvertUp( USHORT nBitCount, Color* pExtColor ) +{ + DBG_ASSERT( nBitCount > GetBitCount(), "New BitCount must be greater!" ); + + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + BOOL bRet = FALSE; + + if( pReadAcc ) + { + BitmapPalette aPal; + Bitmap aNewBmp( GetSizePixel(), nBitCount, &aPal ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + + if( pWriteAcc ) + { + const long nWidth = pWriteAcc->Width(); + const long nHeight = pWriteAcc->Height(); + + if( pWriteAcc->HasPalette() ) + { + const USHORT nOldCount = 1 << GetBitCount(); + const BitmapPalette& rOldPal = pReadAcc->GetPalette(); + + aPal.SetEntryCount( 1 << nBitCount ); + + for( USHORT i = 0; i < nOldCount; i++ ) + aPal[ i ] = rOldPal[ i ]; + + if( pExtColor ) + aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor; + + pWriteAcc->SetPalette( aPal ); + + for( long nY = 0L; nY < nHeight; nY++ ) + for( long nX = 0L; nX < nWidth; nX++ ) + pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) ); + } + else + { + if( pReadAcc->HasPalette() ) + { + for( long nY = 0L; nY < nHeight; nY++ ) + for( long nX = 0L; nX < nWidth; nX++ ) + pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ) ); + } + else + { + for( long nY = 0L; nY < nHeight; nY++ ) + for( long nX = 0L; nX < nWidth; nX++ ) + pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) ); + } + } + + aNewBmp.ReleaseAccess( pWriteAcc ); + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + + maPrefMapMode = aMap; + maPrefSize = aSize; + } + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::ImplConvertDown( USHORT nBitCount, Color* pExtColor ) +{ + DBG_ASSERT( nBitCount <= GetBitCount(), "New BitCount must be lower ( or equal when pExtColor is set )!" ); + + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + BOOL bRet = FALSE; + + if( pReadAcc ) + { + BitmapPalette aPal; + Bitmap aNewBmp( GetSizePixel(), nBitCount, &aPal ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + + if( pWriteAcc ) + { + const USHORT nCount = 1 << nBitCount; + const long nWidth = pWriteAcc->Width(); + const long nWidth1 = nWidth - 1L; + const long nHeight = pWriteAcc->Height(); + Octree aOctree( *pReadAcc, pExtColor ? ( nCount - 1 ) : nCount ); + InverseColorMap aColorMap( aPal = aOctree.GetPalette() ); + BitmapColor aColor; + ImpErrorQuad aErrQuad; + ImpErrorQuad* pErrQuad1 = new ImpErrorQuad[ nWidth ]; + ImpErrorQuad* pErrQuad2 = new ImpErrorQuad[ nWidth ]; + ImpErrorQuad* pQLine1 = pErrQuad1; + ImpErrorQuad* pQLine2; + long nX, nY; + long nYTmp = 0L; + BYTE cIndex; + BOOL bQ1 = TRUE; + + if( pExtColor ) + { + aPal.SetEntryCount( aPal.GetEntryCount() + 1 ); + aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor; + } + + // set Black/White always, if we have enough space + if( aPal.GetEntryCount() < ( nCount - 1 ) ) + { + aPal.SetEntryCount( aPal.GetEntryCount() + 2 ); + aPal[ aPal.GetEntryCount() - 2 ] = Color( COL_BLACK ); + aPal[ aPal.GetEntryCount() - 1 ] = Color( COL_WHITE ); + } + + pWriteAcc->SetPalette( aPal ); + + for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ ) + { + for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ ) + { + if( pReadAcc->HasPalette() ) + pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nYTmp, nX ) ); + else + pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); + } + } + + for( nY = 0L; nY < nHeight; nY++, nYTmp++ ) + { + // erstes ZeilenPixel + cIndex = (BYTE) aColorMap.GetBestPaletteIndex( pQLine1[ 0 ].ImplGetColor() ); + pWriteAcc->SetPixel( nY, 0, cIndex ); + + for( nX = 1L; nX < nWidth1; nX++ ) + { + cIndex = (BYTE) aColorMap.GetBestPaletteIndex( aColor = pQLine1[ nX ].ImplGetColor() ); + aErrQuad = ( ImpErrorQuad( aColor ) -= pWriteAcc->GetPaletteColor( cIndex ) ); + pQLine1[ ++nX ].ImplAddColorError7( aErrQuad ); + pQLine2[ nX-- ].ImplAddColorError1( aErrQuad ); + pQLine2[ nX-- ].ImplAddColorError5( aErrQuad ); + pQLine2[ nX++ ].ImplAddColorError3( aErrQuad ); + pWriteAcc->SetPixel( nY, nX, cIndex ); + } + + // letztes ZeilenPixel + cIndex = (BYTE) aColorMap.GetBestPaletteIndex( pQLine1[ nWidth1 ].ImplGetColor() ); + pWriteAcc->SetPixel( nY, nX, cIndex ); + + // Zeilenpuffer neu fuellen/kopieren + pQLine1 = pQLine2; + pQLine2 = ( bQ1 = !bQ1 ) ? pErrQuad2 : pErrQuad1; + + if( nYTmp < nHeight ) + { + for( nX = 0L; nX < nWidth; nX++ ) + { + if( pReadAcc->HasPalette() ) + pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nYTmp, nX ) ); + else + pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); + } + } + } + + // Zeilenpuffer zerstoeren + delete[] pErrQuad1; + delete[] pErrQuad2; + + aNewBmp.ReleaseAccess( pWriteAcc ); + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + + maPrefMapMode = aMap; + maPrefSize = aSize; + } + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::ImplConvertGhosted() +{ + Bitmap aNewBmp; + BitmapReadAccess* pR = AcquireReadAccess(); + BOOL bRet = FALSE; + + if( pR ) + { + if( pR->HasPalette() ) + { + BitmapPalette aNewPal( pR->GetPaletteEntryCount() ); + + for( long i = 0, nCount = aNewPal.GetEntryCount(); i < nCount; i++ ) + { + const BitmapColor& rOld = pR->GetPaletteColor( (USHORT) i ); + aNewPal[ (USHORT) i ] = BitmapColor( ( rOld.GetRed() >> 1 ) | 0x80, + ( rOld.GetGreen() >> 1 ) | 0x80, + ( rOld.GetBlue() >> 1 ) | 0x80 ); + } + + aNewBmp = Bitmap( GetSizePixel(), GetBitCount(), &aNewPal ); + BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess(); + + if( pW ) + { + pW->CopyBuffer( *pR ); + aNewBmp.ReleaseAccess( pW ); + bRet = TRUE; + } + } + else + { + aNewBmp = Bitmap( GetSizePixel(), 24 ); + + BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess(); + + if( pW ) + { + const long nWidth = pR->Width(), nHeight = pR->Height(); + + for( long nY = 0; nY < nHeight; nY++ ) + { + for( long nX = 0; nX < nWidth; nX++ ) + { + const BitmapColor aOld( pR->GetPixel( nY, nX ) ); + pW->SetPixel( nY, nX, BitmapColor( ( aOld.GetRed() >> 1 ) | 0x80, + ( aOld.GetGreen() >> 1 ) | 0x80, + ( aOld.GetBlue() >> 1 ) | 0x80 ) ); + + } + } + + aNewBmp.ReleaseAccess( pW ); + bRet = TRUE; + } + } + + ReleaseAccess( pR ); + } + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + + maPrefMapMode = aMap; + maPrefSize = aSize; + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::Scale( const double& rScaleX, const double& rScaleY, ULONG nScaleFlag ) +{ + BOOL bRet; + + if( ( rScaleX != 1.0 ) || ( rScaleY != 1.0 ) ) + { + if( BMP_SCALE_FAST == nScaleFlag ) + bRet = ImplScaleFast( rScaleX, rScaleY ); + else if( BMP_SCALE_INTERPOLATE == nScaleFlag ) + bRet = ImplScaleInterpolate( rScaleX, rScaleY ); + else + bRet = FALSE; + } + else + bRet = TRUE; + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::Scale( const Size& rNewSize, ULONG nScaleFlag ) +{ + const Size aSize( GetSizePixel() ); + BOOL bRet; + + if( aSize.Width() && aSize.Height() ) + { + bRet = Scale( (double) rNewSize.Width() / aSize.Width(), + (double) rNewSize.Height() / aSize.Height(), + nScaleFlag ); + } + else + bRet = TRUE; + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY ) +{ + const Size aSizePix( GetSizePixel() ); + const long nNewWidth = FRound( aSizePix.Width() * rScaleX ); + const long nNewHeight = FRound( aSizePix.Height() * rScaleY ); + BOOL bRet = FALSE; + + if( nNewWidth && nNewHeight ) + { + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + Bitmap aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + + if( pReadAcc && pWriteAcc ) + { + const long nScanlineSize = pWriteAcc->GetScanlineSize(); + const long nNewWidth1 = nNewWidth - 1L; + const long nNewHeight1 = nNewHeight - 1L; + const long nWidth1 = pReadAcc->Width() - 1L; + const long nHeight1 = pReadAcc->Height() - 1L; + long* pLutX = new long[ nNewWidth ]; + long* pLutY = new long[ nNewHeight ]; + long nX, nY, nMapY, nActY = 0L; + + if( nNewWidth1 && nNewHeight1 ) + { + for( nX = 0L; nX < nNewWidth; nX++ ) + pLutX[ nX ] = nX * nWidth1 / nNewWidth1; + + for( nY = 0L; nY < nNewHeight; nY++ ) + pLutY[ nY ] = nY * nHeight1 / nNewHeight1; + + while( nActY < nNewHeight ) + { + nMapY = pLutY[ nActY ]; + + for( nX = 0L; nX < nNewWidth; nX++ ) + pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) ); + + while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) ) + { + HMEMCPY( pWriteAcc->GetScanline( nActY + 1L ), + pWriteAcc->GetScanline( nActY ), nScanlineSize ); + nActY++; + } + + nActY++; + } + + bRet = TRUE; + } + + delete[] pLutX; + delete[] pLutY; + } + + ReleaseAccess( pReadAcc ); + aNewBmp.ReleaseAccess( pWriteAcc ); + + if( bRet ) + ImplAssignWithSize( aNewBmp ); + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY ) +{ + const Size aSizePix( GetSizePixel() ); + const long nNewWidth = FRound( aSizePix.Width() * rScaleX ); + const long nNewHeight = FRound( aSizePix.Height() * rScaleY ); + BOOL bRet = FALSE; + + if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) ) + { + BitmapColor aCol0; + BitmapColor aCol1; + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + long nWidth = pReadAcc->Width(); + long nHeight = pReadAcc->Height(); + Bitmap aNewBmp( Size( nNewWidth, nHeight ), 24 ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + long* pLutInt; + long* pLutFrac; + long nX, nY; + long lXB0, lXB1, lXG0, lXG1, lXR0, lXR1; + double fTemp; + long nTemp; + + if( pReadAcc && pWriteAcc ) + { + const long nNewWidth1 = nNewWidth - 1L; + const long nWidth1 = pReadAcc->Width() - 1L; + const double fRevScaleX = (double) nWidth1 / nNewWidth1; + + pLutInt = new long[ nNewWidth ]; + pLutFrac = new long[ nNewWidth ]; + + for( nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ ) + { + fTemp = nX * fRevScaleX; + pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp ); + fTemp -= pLutInt[ nX ]; + pLutFrac[ nX ] = (long) ( fTemp * 1024. ); + } + + if( pReadAcc->HasPalette() ) + { + for( nY = 0L; nY < nHeight; nY++ ) + { + if( 1 == nWidth ) + { + aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, 0 ) ); + + for( nX = 0L; nX < nNewWidth; nX++ ) + pWriteAcc->SetPixel( nY, nX, aCol0 ); + } + else + { + for( nX = 0L; nX < nNewWidth; nX++ ) + { + nTemp = pLutInt[ nX ]; + + aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp++ ) ); + aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp ) ); + + nTemp = pLutFrac[ nX ]; + + lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); + lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); + lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); + + aCol0.SetRed( (BYTE) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); + aCol0.SetGreen( (BYTE) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); + aCol0.SetBlue( (BYTE) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); + + pWriteAcc->SetPixel( nY, nX, aCol0 ); + } + } + } + } + else + { + for( nY = 0L; nY < nHeight; nY++ ) + { + if( 1 == nWidth ) + { + aCol0 = pReadAcc->GetPixel( nY, 0 ); + + for( nX = 0L; nX < nNewWidth; nX++ ) + pWriteAcc->SetPixel( nY, nX, aCol0 ); + } + else + { + for( nX = 0L; nX < nNewWidth; nX++ ) + { + nTemp = pLutInt[ nX ]; + + aCol0 = pReadAcc->GetPixel( nY, nTemp++ ); + aCol1 = pReadAcc->GetPixel( nY, nTemp ); + + nTemp = pLutFrac[ nX ]; + + lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); + lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); + lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); + + aCol0.SetRed( (BYTE) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); + aCol0.SetGreen( (BYTE) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); + aCol0.SetBlue( (BYTE) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); + + pWriteAcc->SetPixel( nY, nX, aCol0 ); + } + } + } + } + + delete[] pLutInt; + delete[] pLutFrac; + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + aNewBmp.ReleaseAccess( pWriteAcc ); + + if( bRet ) + { + bRet = FALSE; + ImplAssignWithSize( aNewBmp ); + pReadAcc = AcquireReadAccess(); + aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 ); + pWriteAcc = aNewBmp.AcquireWriteAccess(); + + if( pReadAcc && pWriteAcc ) + { + const long nNewHeight1 = nNewHeight - 1L; + const long nHeight1 = pReadAcc->Height() - 1L; + const double fRevScaleY = (double) nHeight1 / nNewHeight1; + + pLutInt = new long[ nNewHeight ]; + pLutFrac = new long[ nNewHeight ]; + + for( nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ ) + { + fTemp = nY * fRevScaleY; + pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp ); + fTemp -= pLutInt[ nY ]; + pLutFrac[ nY ] = (long) ( fTemp * 1024. ); + } + + if( pReadAcc->HasPalette() ) + { + for( nX = 0L; nX < nNewWidth; nX++ ) + { + if( 1 == nHeight ) + { + aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nX ) ); + + for( nY = 0L; nY < nNewHeight; nY++ ) + pWriteAcc->SetPixel( nY, nX, aCol0 ); + } + else + { + for( nY = 0L; nY < nNewHeight; nY++ ) + { + nTemp = pLutInt[ nY ]; + + aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp++, nX ) ); + aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp, nX ) ); + + nTemp = pLutFrac[ nY ]; + + lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); + lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); + lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); + + aCol0.SetRed( (BYTE) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); + aCol0.SetGreen( (BYTE) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); + aCol0.SetBlue( (BYTE) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); + + pWriteAcc->SetPixel( nY, nX, aCol0 ); + } + } + } + } + else + { + for( nX = 0L; nX < nNewWidth; nX++ ) + { + if( 1 == nHeight ) + { + aCol0 = pReadAcc->GetPixel( 0, nX ); + + for( nY = 0L; nY < nNewHeight; nY++ ) + pWriteAcc->SetPixel( nY, nX, aCol0 ); + } + else + { + for( nY = 0L; nY < nNewHeight; nY++ ) + { + nTemp = pLutInt[ nY ]; + + aCol0 = pReadAcc->GetPixel( nTemp++, nX ); + aCol1 = pReadAcc->GetPixel( nTemp, nX ); + + nTemp = pLutFrac[ nY ]; + + lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); + lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); + lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); + + aCol0.SetRed( (BYTE) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); + aCol0.SetGreen( (BYTE) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); + aCol0.SetBlue( (BYTE) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); + + pWriteAcc->SetPixel( nY, nX, aCol0 ); + } + } + } + } + + delete[] pLutInt; + delete[] pLutFrac; + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + aNewBmp.ReleaseAccess( pWriteAcc ); + + if( bRet ) + ImplAssignWithSize( aNewBmp ); + } + } + + if( !bRet ) + bRet = ImplScaleFast( rScaleX, rScaleY ); + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::Dither( ULONG nDitherFlags, const BitmapPalette* pDitherPal ) +{ + DBG_ASSERT( !pDitherPal, "Sorry, using owner defined palettes is not yet supportet..." ); + + BOOL bRet = FALSE; + + const Size aSizePix( GetSizePixel() ); + + if( aSizePix.Width() == 1 || aSizePix.Height() == 1 ) + bRet = TRUE; + else if( nDitherFlags & BMP_DITHER_MATRIX ) + bRet = ImplDitherMatrix( pDitherPal ); + else if( nDitherFlags & BMP_DITHER_FLOYD ) + bRet = ImplDitherFloyd( pDitherPal ); + else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) ) + bRet = ImplDitherFloyd16(); + + return bRet; +} + +//fuer WIN16 Borland +#ifdef WIN +#pragma codeseg BITMAP3_SEG1 +#endif + +// ------------------------------------------------------------------------ + +BOOL Bitmap::ImplDitherMatrix( const BitmapPalette* pDitherPal ) +{ + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + Bitmap aNewBmp( GetSizePixel(), 8 ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + BOOL bRet = FALSE; + + if( pReadAcc && pWriteAcc ) + { + const ULONG nWidth = pReadAcc->Width(); + const ULONG nHeight = pReadAcc->Height(); + BitmapColor aIndex( (BYTE) 0 ); + + if( pReadAcc->HasPalette() ) + { + for( ULONG nY = 0UL; nY < nHeight; nY++ ) + { + for( ULONG nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ ) + { + const BitmapColor aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ) ); + const ULONG nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ]; + const ULONG nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL; + const ULONG nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL; + const ULONG nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL; + + aIndex.SetIndex( (BYTE) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) ); + pWriteAcc->SetPixel( nY, nX, aIndex ); + } + } + } + else + { + for( ULONG nY = 0UL; nY < nHeight; nY++ ) + { + for( ULONG nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ ) + { + const BitmapColor aCol( pReadAcc->GetPixel( nY, nX ) ); + const ULONG nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ]; + const ULONG nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL; + const ULONG nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL; + const ULONG nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL; + + aIndex.SetIndex( (BYTE) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) ); + pWriteAcc->SetPixel( nY, nX, aIndex ); + } + } + } + + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + aNewBmp.ReleaseAccess( pWriteAcc ); + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + + maPrefMapMode = aMap; + maPrefSize = aSize; + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::ImplDitherFloyd( const BitmapPalette* pDitherPal ) +{ + const Size aSize( GetSizePixel() ); + BOOL bRet = FALSE; + + if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) ) + { + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + Bitmap aNewBmp( GetSizePixel(), 8 ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + + if( pReadAcc && pWriteAcc ) + { + BitmapColor aColor; + long nWidth = pReadAcc->Width(); + long nWidth1 = nWidth - 1L; + long nHeight = pReadAcc->Height(); + long nX; + long nW = nWidth * 3L; + long nW2 = nW - 3L; + long nWLen = nW << 2; + long nRErr, nGErr, nBErr; + long nRC, nGC, nBC; + long nTemp; + long nZ; + long* p1 = new long[ nW ]; + long* p2 = new long[ nW ]; + long* p1T = p1; + long* p2T = p2; + long* pTmp; + BOOL bPal = pReadAcc->HasPalette(); + + pTmp = p2T; + + if( bPal ) + { + for( nZ = 0; nZ < nWidth; nZ++ ) + { + aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nZ ) ); + + *pTmp++ = (long) aColor.GetBlue() << 12; + *pTmp++ = (long) aColor.GetGreen() << 12; + *pTmp++ = (long) aColor.GetRed() << 12; + } + } + else + { + for( nZ = 0; nZ < nWidth; nZ++ ) + { + aColor = pReadAcc->GetPixel( 0, nZ ); + + *pTmp++ = (long) aColor.GetBlue() << 12; + *pTmp++ = (long) aColor.GetGreen() << 12; + *pTmp++ = (long) aColor.GetRed() << 12; + } + } + + for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ ) + { + pTmp = p1T; + p1T = p2T; + p2T = pTmp; + + if( nY < nHeight ) + { + if( bPal ) + { + for( nZ = 0; nZ < nWidth; nZ++ ) + { + aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nZ ) ); + + *pTmp++ = (long) aColor.GetBlue() << 12; + *pTmp++ = (long) aColor.GetGreen() << 12; + *pTmp++ = (long) aColor.GetRed() << 12; + } + } + else + { + for( nZ = 0; nZ < nWidth; nZ++ ) + { + aColor = pReadAcc->GetPixel( nY, nZ ); + + *pTmp++ = (long) aColor.GetBlue() << 12; + *pTmp++ = (long) aColor.GetGreen() << 12; + *pTmp++ = (long) aColor.GetRed() << 12; + } + } + } + + // erstes Pixel gesondert betrachten + nX = 0; + CALC_ERRORS; + CALC_TABLES7; + nX -= 5; + CALC_TABLES5; + pWriteAcc->SetPixel( nYAcc, 0, BitmapColor( (BYTE) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) ); + + // mittlere Pixel ueber Schleife + for ( long nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ ) + { + CALC_ERRORS; + CALC_TABLES7; + nX -= 8; + CALC_TABLES3; + CALC_TABLES5; + pWriteAcc->SetPixel( nYAcc, nXAcc, BitmapColor( (BYTE) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) ); + } + + // letztes Pixel gesondert betrachten + CALC_ERRORS; + nX -= 5; + CALC_TABLES3; + CALC_TABLES5; + pWriteAcc->SetPixel( nYAcc, nWidth1, BitmapColor( (BYTE) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) ); + } + + delete[] p1; + delete[] p2; + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + aNewBmp.ReleaseAccess( pWriteAcc ); + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + + maPrefMapMode = aMap; + maPrefSize = aSize; + } + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::ImplDitherFloyd16() +{ + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + Bitmap aNewBmp( GetSizePixel(), 24 ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + BOOL bRet = FALSE; + + if( pReadAcc && pWriteAcc ) + { + const long nWidth = pWriteAcc->Width(); + const long nWidth1 = nWidth - 1L; + const long nHeight = pWriteAcc->Height(); + BitmapColor aColor; + BitmapColor aBestCol; + ImpErrorQuad aErrQuad; + ImpErrorQuad* pErrQuad1 = new ImpErrorQuad[ nWidth ]; + ImpErrorQuad* pErrQuad2 = new ImpErrorQuad[ nWidth ]; + ImpErrorQuad* pQLine1 = pErrQuad1; + ImpErrorQuad* pQLine2; + long nX, nY; + long nYTmp = 0L; + BOOL bQ1 = TRUE; + + for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ ) + for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ ) + pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); + + for( nY = 0L; nY < nHeight; nY++, nYTmp++ ) + { + // erstes ZeilenPixel + aBestCol = pQLine1[ 0 ].ImplGetColor(); + aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 ); + aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 ); + aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 ); + pWriteAcc->SetPixel( nY, 0, aBestCol ); + + for( nX = 1L; nX < nWidth1; nX++ ) + { + aColor = pQLine1[ nX ].ImplGetColor(); + aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 ); + aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 ); + aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 ); + aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol ); + pQLine1[ ++nX ].ImplAddColorError7( aErrQuad ); + pQLine2[ nX-- ].ImplAddColorError1( aErrQuad ); + pQLine2[ nX-- ].ImplAddColorError5( aErrQuad ); + pQLine2[ nX++ ].ImplAddColorError3( aErrQuad ); + pWriteAcc->SetPixel( nY, nX, aBestCol ); + } + + // letztes ZeilenPixel + aBestCol = pQLine1[ nWidth1 ].ImplGetColor(); + aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 ); + aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 ); + aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 ); + pWriteAcc->SetPixel( nY, nX, aBestCol ); + + // Zeilenpuffer neu fuellen/kopieren + pQLine1 = pQLine2; + pQLine2 = ( bQ1 = !bQ1 ) ? pErrQuad2 : pErrQuad1; + + if( nYTmp < nHeight ) + for( nX = 0L; nX < nWidth; nX++ ) + pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); + } + + // Zeilenpuffer zerstoeren + delete[] pErrQuad1; + delete[] pErrQuad2; + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + aNewBmp.ReleaseAccess( pWriteAcc ); + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + + maPrefMapMode = aMap; + maPrefSize = aSize; + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::ReduceColors( USHORT nColorCount, BmpReduce eReduce ) +{ + BOOL bRet; + + if( GetColorCount() <= (ULONG) nColorCount ) + bRet = TRUE; + else if( nColorCount ) + { + if( BMP_REDUCE_SIMPLE == eReduce ) + bRet = ImplReduceSimple( nColorCount ); + else if( BMP_REDUCE_POPULAR == eReduce ) + bRet = ImplReducePopular( nColorCount ); + else + bRet = ImplReduceMedian( nColorCount ); + } + else + bRet = FALSE; + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::ImplReduceSimple( USHORT nColorCount ) +{ + Bitmap aNewBmp; + BitmapReadAccess* pRAcc = AcquireReadAccess(); + const USHORT nColCount = Min( nColorCount, (USHORT) 256 ); + USHORT nBitCount; + BOOL bRet = FALSE; + + if( nColCount <= 2 ) + nBitCount = 1; + else if( nColCount <= 16 ) + nBitCount = 4; + else + nBitCount = 8; + + if( pRAcc ) + { + Octree aOct( *pRAcc, nColCount ); + const BitmapPalette& rPal = aOct.GetPalette(); + BitmapWriteAccess* pWAcc; + + aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal ); + pWAcc = aNewBmp.AcquireWriteAccess(); + + if( pWAcc ) + { + const long nWidth = pRAcc->Width(); + const long nHeight = pRAcc->Height(); + + if( pRAcc->HasPalette() ) + { + for( long nY = 0L; nY < nHeight; nY++ ) + for( long nX =0L; nX < nWidth; nX++ ) + pWAcc->SetPixel( nY, nX, (BYTE) aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ) ) ); + } + else + { + for( long nY = 0L; nY < nHeight; nY++ ) + for( long nX =0L; nX < nWidth; nX++ ) + pWAcc->SetPixel( nY, nX, (BYTE) aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) ) ); + } + + aNewBmp.ReleaseAccess( pWAcc ); + bRet = TRUE; + } + + ReleaseAccess( pRAcc ); + } + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + maPrefMapMode = aMap; + maPrefSize = aSize; + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +struct PopularColorCount +{ + sal_uInt32 mnIndex; + sal_uInt32 mnCount; +}; + +// ------------------------------------------------------------------------ + +extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 ) +{ + int nRet; + + if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount ) + nRet = 1; + else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount ) + nRet = 0; + else + nRet = -1; + + return nRet; +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::ImplReducePopular( USHORT nColCount ) +{ + BitmapReadAccess* pRAcc = AcquireReadAccess(); + USHORT nBitCount; + BOOL bRet = FALSE; + + if( nColCount > 256 ) + nColCount = 256; + + if( nColCount < 17 ) + nBitCount = 4; + else + nBitCount = 8; + + if( pRAcc ) + { + const sal_uInt32 nValidBits = 4; + const sal_uInt32 nRightShiftBits = 8 - nValidBits; + const sal_uInt32 nLeftShiftBits1 = nValidBits; + const sal_uInt32 nLeftShiftBits2 = nValidBits << 1; + const sal_uInt32 nColorsPerComponent = 1 << nValidBits; + const sal_uInt32 nColorOffset = 256 / nColorsPerComponent; + const sal_uInt32 nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent; + const long nWidth = pRAcc->Width(); + const long nHeight = pRAcc->Height(); + PopularColorCount* pCountTable = new PopularColorCount[ nTotalColors ]; + long nX, nY, nR, nG, nB, nIndex; + + rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) ); + + for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset ) + for( nG = 0; nG < 256; nG += nColorOffset ) + for( nB = 0; nB < 256; nB += nColorOffset ) + pCountTable[ nIndex ].mnIndex = nIndex++; + + if( pRAcc->HasPalette() ) + { + for( nY = 0L; nY < nHeight; nY++ ) + { + for( nX = 0L; nX < nWidth; nX++ ) + { + const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ); + pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | + ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | + ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++; + } + } + } + else + { + for( nY = 0L; nY < nHeight; nY++ ) + { + for( nX = 0L; nX < nWidth; nX++ ) + { + const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); + pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | + ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | + ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++; + } + } + } + + BitmapPalette aNewPal( nColCount ); + + qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc ); + + for( USHORT n = 0; n < nColCount; n++ ) + { + const PopularColorCount& rPop = pCountTable[ n ]; + aNewPal[ n ] = BitmapColor( (BYTE) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ), + (BYTE) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ), + (BYTE) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) ); + } + + Bitmap aNewBmp( GetSizePixel(), nBitCount, &aNewPal ); + BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess(); + + if( pWAcc ) + { + BitmapColor aDstCol( (BYTE) 0 ); + BYTE* pIndexMap = new BYTE[ nTotalColors ]; + + for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset ) + for( nG = 0; nG < 256; nG += nColorOffset ) + for( nB = 0; nB < 256; nB += nColorOffset ) + pIndexMap[ nIndex++ ] = aNewPal.GetBestIndex( BitmapColor( (BYTE) nR, (BYTE) nG, (BYTE) nB ) ); + + if( pRAcc->HasPalette() ) + { + for( nY = 0L; nY < nHeight; nY++ ) + { + for( nX = 0L; nX < nWidth; nX++ ) + { + const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ); + aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | + ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | + ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] ); + pWAcc->SetPixel( nY, nX, aDstCol ); + } + } + } + else + { + for( nY = 0L; nY < nHeight; nY++ ) + { + for( nX = 0L; nX < nWidth; nX++ ) + { + const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); + aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | + ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | + ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] ); + pWAcc->SetPixel( nY, nX, aDstCol ); + } + } + } + + delete[] pIndexMap; + aNewBmp.ReleaseAccess( pWAcc ); + bRet = TRUE; + } + + delete[] pCountTable; + ReleaseAccess( pRAcc ); + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + maPrefMapMode = aMap; + maPrefSize = aSize; + } + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::ImplReduceMedian( USHORT nColCount ) +{ + BitmapReadAccess* pRAcc = AcquireReadAccess(); + USHORT nBitCount; + BOOL bRet = FALSE; + + if( nColCount < 17 ) + nBitCount = 4; + else if( nColCount < 257 ) + nBitCount = 8; + else + { + DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" ); + nBitCount = 8; + nColCount = 256; + } + + if( pRAcc ) + { + Bitmap aNewBmp( GetSizePixel(), nBitCount ); + BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess(); + + if( pWAcc ) + { + const ULONG nSize = 32768UL * sizeof( ULONG ); + HPULONG pColBuf = (HPULONG) SvMemAlloc( nSize ); + const long nWidth = pWAcc->Width(); + const long nHeight = pWAcc->Height(); + long nIndex = 0L; + + HMEMSET( (HPBYTE) pColBuf, 0, nSize ); + + // create Buffer + if( pRAcc->HasPalette() ) + { + for( long nY = 0L; nY < nHeight; nY++ ) + { + for( long nX = 0L; nX < nWidth; nX++ ) + { + const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ); + pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++; + } + } + } + else + { + for( long nY = 0L; nY < nHeight; nY++ ) + { + for( long nX = 0L; nX < nWidth; nX++ ) + { + const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); + pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++; + } + } + } + + // create palette via median cut + BitmapPalette aPal( pWAcc->GetPaletteEntryCount() ); + ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31, + nColCount, nWidth * nHeight, nIndex ); + + // do mapping of colors to palette + InverseColorMap aMap( aPal ); + pWAcc->SetPalette( aPal ); + for( long nY = 0L; nY < nHeight; nY++ ) + for( long nX = 0L; nX < nWidth; nX++ ) + pWAcc->SetPixel( nY, nX, (BYTE) aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) ) ); + + SvMemFree( pColBuf ); + aNewBmp.ReleaseAccess( pWAcc ); + bRet = TRUE; + } + + ReleaseAccess( pRAcc ); + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + maPrefMapMode = aMap; + maPrefSize = aSize; + } + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +void Bitmap::ImplMedianCut( ULONG* pColBuf, BitmapPalette& rPal, + long nR1, long nR2, long nG1, long nG2, long nB1, long nB2, + long nColors, long nPixels, long& rIndex ) +{ + if( !nPixels ) + return; + + BitmapColor aCol; + const long nRLen = nR2 - nR1; + const long nGLen = nG2 - nG1; + const long nBLen = nB2 - nB1; + long nR, nG, nB; + HPULONG pBuf = pColBuf; + + if( !nRLen && !nGLen && !nBLen ) + { + if( pBuf[ RGB15( nR1, nG1, nB1 ) ] ) + { + aCol.SetRed( (BYTE) ( nR1 << 3 ) ); + aCol.SetGreen( (BYTE) ( nG1 << 3 ) ); + aCol.SetBlue( (BYTE) ( nB1 << 3 ) ); + rPal[ (USHORT) rIndex++ ] = aCol; + } + } + else + { + if( 1 == nColors || 1 == nPixels ) + { + long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0; + + for( nR = nR1; nR <= nR2; nR++ ) + { + for( nG = nG1; nG <= nG2; nG++ ) + { + for( nB = nB1; nB <= nB2; nB++ ) + { + nPixSum = pBuf[ RGB15( nR, nG, nB ) ]; + + if( nPixSum ) + { + nRSum += nR * nPixSum; + nGSum += nG * nPixSum; + nBSum += nB * nPixSum; + } + } + } + } + + aCol.SetRed( (BYTE) ( ( nRSum / nPixels ) << 3 ) ); + aCol.SetGreen( (BYTE) ( ( nGSum / nPixels ) << 3 ) ); + aCol.SetBlue( (BYTE) ( ( nBSum / nPixels ) << 3 ) ); + rPal[ (USHORT) rIndex++ ] = aCol; + } + else + { + const long nTest = ( nPixels >> 1 ); + long nPixOld, nPixNew = 0; + + if( nBLen > nGLen && nBLen > nRLen ) + { + nB = nB1 - 1; + + while( nPixNew < nTest ) + { + nB++, nPixOld = nPixNew; + for( nR = nR1; nR <= nR2; nR++ ) + for( nG = nG1; nG <= nG2; nG++ ) + nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; + } + + if( nB < nB2 ) + { + ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex ); + ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); + } + else + { + ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex ); + ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); + } + } + else if( nGLen > nRLen ) + { + nG = nG1 - 1; + + while( nPixNew < nTest ) + { + nG++, nPixOld = nPixNew; + for( nR = nR1; nR <= nR2; nR++ ) + for( nB = nB1; nB <= nB2; nB++ ) + nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; + } + + if( nG < nG2 ) + { + ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex ); + ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); + } + else + { + ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex ); + ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); + } + } + else + { + nR = nR1 - 1; + + while( nPixNew < nTest ) + { + nR++, nPixOld = nPixNew; + for( nG = nG1; nG <= nG2; nG++ ) + for( nB = nB1; nB <= nB2; nB++ ) + nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; + } + + if( nR < nR2 ) + { + ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex ); + ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); + } + else + { + ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex ); + ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); + } + } + } + } +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::Vectorize( PolyPolygon& rPolyPoly, ULONG nFlags, const Link* pProgress ) +{ + return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress ); +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::Vectorize( GDIMetaFile& rMtf, BYTE cReduce, ULONG nFlags, const Link* pProgress ) +{ + return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress ); +} + +// ------------------------------------------------------------------------ + +BOOL Bitmap::Adjust( short nLuminancePercent, short nContrastPercent, + short nChannelRPercent, short nChannelGPercent, short nChannelBPercent, + double fGamma, BOOL bInvert ) +{ + BOOL bRet = FALSE; + + // nothing to do => return quickly + if( !nLuminancePercent && !nContrastPercent && + !nChannelRPercent && !nChannelGPercent && !nChannelBPercent && + ( fGamma == 1.0 ) && !bInvert ) + { + bRet = TRUE; + } + else + { + BitmapWriteAccess* pAcc = AcquireWriteAccess(); + + if( pAcc ) + { + BitmapColor aCol; + const long nW = pAcc->Width(); + const long nH = pAcc->Height(); + BYTE* cMapR = new BYTE[ 256 ]; + BYTE* cMapG = new BYTE[ 256 ]; + BYTE* cMapB = new BYTE[ 256 ]; + long nX, nY; + double fM, fROff, fGOff, fBOff, fOff; + + // calculate slope + if( nContrastPercent >= 0 ) + fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) ); + else + fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0; + + // total offset = luminance offset + contrast offset + fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0; + + // channel offset = channel offset + total offset + fROff = nChannelRPercent * 2.55 + fOff; + fGOff = nChannelGPercent * 2.55 + fOff; + fBOff = nChannelBPercent * 2.55 + fOff; + + // calculate gamma value + fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma ); + const BOOL bGamma = ( fGamma != 1.0 ); + + // create mapping table + for( nX = 0L; nX < 256L; nX++ ) + { + cMapR[ nX ] = (BYTE) MinMax( FRound( nX * fM + fROff ), 0L, 255L ); + cMapG[ nX ] = (BYTE) MinMax( FRound( nX * fM + fGOff ), 0L, 255L ); + cMapB[ nX ] = (BYTE) MinMax( FRound( nX * fM + fBOff ), 0L, 255L ); + + if( bGamma ) + { + cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma ); + cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma ); + cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma ); + } + + if( bInvert ) + { + cMapR[ nX ] = ~cMapR[ nX ]; + cMapG[ nX ] = ~cMapG[ nX ]; + cMapB[ nX ] = ~cMapB[ nX ]; + } + } + + // do modifying + if( pAcc->HasPalette() ) + { + BitmapColor aNewCol; + + for( USHORT i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ ) + { + const BitmapColor& rCol = pAcc->GetPaletteColor( i ); + aNewCol.SetRed( cMapR[ rCol.GetRed() ] ); + aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] ); + aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] ); + pAcc->SetPaletteColor( i, aNewCol ); + } + } + else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR ) + { + for( nY = 0L; nY < nH; nY++ ) + { + Scanline pScan = pAcc->GetScanline( nY ); + + for( nX = 0L; nX < nW; nX++ ) + { + *pScan = cMapB[ *pScan ]; pScan++; + *pScan = cMapG[ *pScan ]; pScan++; + *pScan = cMapR[ *pScan ]; pScan++; + } + } + } + else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB ) + { + for( nY = 0L; nY < nH; nY++ ) + { + Scanline pScan = pAcc->GetScanline( nY ); + + for( nX = 0L; nX < nW; nX++ ) + { + *pScan = cMapR[ *pScan ]; pScan++; + *pScan = cMapG[ *pScan ]; pScan++; + *pScan = cMapB[ *pScan ]; pScan++; + } + } + } + else + { + for( nY = 0L; nY < nH; nY++ ) + { + for( nX = 0L; nX < nW; nX++ ) + { + aCol = pAcc->GetPixel( nY, nX ); + aCol.SetRed( cMapR[ aCol.GetRed() ] ); + aCol.SetGreen( cMapG[ aCol.GetGreen() ] ); + aCol.SetBlue( cMapB[ aCol.GetBlue() ] ); + pAcc->SetPixel( nY, nX, aCol ); + } + } + } + + delete[] cMapR; + delete[] cMapG; + delete[] cMapB; + ReleaseAccess( pAcc ); + bRet = TRUE; + } + } + + return bRet; +} diff --git a/vcl/source/gdi/bitmap4.cxx b/vcl/source/gdi/bitmap4.cxx new file mode 100644 index 000000000000..d959166272f5 --- /dev/null +++ b/vcl/source/gdi/bitmap4.cxx @@ -0,0 +1,953 @@ +/************************************************************************* + * + * $RCSfile: bitmap4.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ +#define _SV_BITMAP_CXX + +#include <vos/macros.hxx> +#include <tools/new.hxx> +#ifndef _SV_BMPACC_HXX +#include <bmpacc.hxx> +#endif +#ifndef _SV_BITMAP_HXX +#include <bitmap.hxx> +#endif + +// ----------- +// - Defines - +// ----------- + +#define S2(a,b) { register long t; if( ( t = b - a ) < 0 ) { a += t; b -= t; } } +#define MN3(a,b,c) S2(a,b); S2(a,c); +#define MX3(a,b,c) S2(b,c); S2(a,c); +#define MNMX3(a,b,c) MX3(a,b,c); S2(a,b); +#define MNMX4(a,b,c,d) S2(a,b); S2(c,d); S2(a,c); S2(b,d); +#define MNMX5(a,b,c,d,e) S2(a,b); S2(c,d); MN3(a,c,e); MX3(b,d,e); +#define MNMX6(a,b,c,d,e,f) S2(a,d); S2(b,e); S2(c,f); MN3(a,b,c); MX3(d,e,f); + +// ---------- +// - Bitmap - +// ---------- + +BOOL Bitmap::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress ) +{ + const USHORT nBitCount = GetBitCount(); + BOOL bRet = FALSE; + + switch( eFilter ) + { + case( BMP_FILTER_SMOOTH ): + { + const long pSmoothMatrix[] = { 1, 2, 1, 2, 5, 2, 1, 2, 1 }; + bRet = ImplConvolute3( &pSmoothMatrix[ 0 ], 17, pFilterParam, pProgress ); + } + break; + + case( BMP_FILTER_SHARPEN ): + { + const long pSharpenMatrix[] = { -1, -1, -1, -1, 16, -1, -1, -1, -1 }; + bRet = ImplConvolute3( &pSharpenMatrix[ 0 ], 8, pFilterParam, pProgress ); + } + break; + + case( BMP_FILTER_REMOVENOISE ): + bRet = ImplMedianFilter( pFilterParam, pProgress ); + break; + + case( BMP_FILTER_SOBEL_GREY ): + bRet = ImplSobelGrey( pFilterParam, pProgress ); + break; + + case( BMP_FILTER_SOLARIZE ): + bRet = ImplSolarize( pFilterParam, pProgress ); + break; + + case( BMP_FILTER_SEPIA ): + bRet = ImplSepia( pFilterParam, pProgress ); + break; + + case( BMP_FILTER_MOSAIC ): + bRet = ImplMosaic( pFilterParam, pProgress ); + break; + + case( BMP_FILTER_EMBOSS_GREY ): + bRet = ImplEmbossGrey( pFilterParam, pProgress ); + break; + + default: + DBG_ERROR( "Bitmap::Convert(): Unsupported filter" ); + break; + } + + return bRet; +} + +// ----------------------------------------------------------------------------- + +BOOL Bitmap::ImplConvolute3( const long* pMatrix, long nDivisor, + const BmpFilterParam* pFilterParam, const Link* pProgress ) +{ + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + BOOL bRet = FALSE; + + if( pReadAcc ) + { + Bitmap aNewBmp( GetSizePixel(), 24 ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + + if( pWriteAcc ) + { + const long nWidth = pWriteAcc->Width(), nWidth2 = nWidth + 2; + const long nHeight = pWriteAcc->Height(), nHeight2 = nHeight + 2; + long* pColm = new long[ nWidth2 ]; + long* pRows = new long[ nHeight2 ]; + BitmapColor* pColRow1 = (BitmapColor*) new BYTE[ sizeof( BitmapColor ) * nWidth2 ]; + BitmapColor* pColRow2 = (BitmapColor*) new BYTE[ sizeof( BitmapColor ) * nWidth2 ]; + BitmapColor* pColRow3 = (BitmapColor*) new BYTE[ sizeof( BitmapColor ) * nWidth2 ]; + BitmapColor* pRowTmp1 = pColRow1; + BitmapColor* pRowTmp2 = pColRow2; + BitmapColor* pRowTmp3 = pColRow3; + BitmapColor* pColor; + long nY, nX, i, nSumR, nSumG, nSumB, nMatrixVal, nTmp; + long (*pKoeff)[ 256 ] = new long[ 9 ][ 256 ]; + long* pTmp; + + // create LUT of products of matrix value and possible color component values + for( nY = 0; nY < 9; nY++ ) + for( nX = nTmp = 0, nMatrixVal = pMatrix[ nY ]; nX < 256; nX++, nTmp += nMatrixVal ) + pKoeff[ nY ][ nX ] = nTmp; + + // create column LUT + for( i = 0; i < nWidth2; i++ ) + pColm[ i ] = ( i > 0 ) ? ( i - 1 ) : 0; + + pColm[ nWidth + 1 ] = pColm[ nWidth ]; + + // create row LUT + for( i = 0; i < nHeight2; i++ ) + pRows[ i ] = ( i > 0 ) ? ( i - 1 ) : 0; + + pRows[ nHeight + 1 ] = pRows[ nHeight ]; + + // read first three rows of bitmap color + for( i = 0; i < nWidth2; i++ ) + { + pColRow1[ i ] = pReadAcc->GetColor( pRows[ 0 ], pColm[ i ] ); + pColRow2[ i ] = pReadAcc->GetColor( pRows[ 1 ], pColm[ i ] ); + pColRow3[ i ] = pReadAcc->GetColor( pRows[ 2 ], pColm[ i ] ); + } + + // do convolution + for( nY = 0; nY < nHeight; ) + { + for( nX = 0; nX < nWidth; nX++ ) + { + // first row + nSumR = ( pTmp = pKoeff[ 0 ] )[ ( pColor = pRowTmp1 + nX )->GetRed() ]; + nSumG = pTmp[ pColor->GetGreen() ]; + nSumB = pTmp[ pColor->GetBlue() ]; + + nSumR += ( pTmp = pKoeff[ 1 ] )[ ( ++pColor )->GetRed() ]; + nSumG += pTmp[ pColor->GetGreen() ]; + nSumB += pTmp[ pColor->GetBlue() ]; + + nSumR += ( pTmp = pKoeff[ 2 ] )[ ( ++pColor )->GetRed() ]; + nSumG += pTmp[ pColor->GetGreen() ]; + nSumB += pTmp[ pColor->GetBlue() ]; + + // second row + nSumR += ( pTmp = pKoeff[ 3 ] )[ ( pColor = pRowTmp2 + nX )->GetRed() ]; + nSumG += pTmp[ pColor->GetGreen() ]; + nSumB += pTmp[ pColor->GetBlue() ]; + + nSumR += ( pTmp = pKoeff[ 4 ] )[ ( ++pColor )->GetRed() ]; + nSumG += pTmp[ pColor->GetGreen() ]; + nSumB += pTmp[ pColor->GetBlue() ]; + + nSumR += ( pTmp = pKoeff[ 5 ] )[ ( ++pColor )->GetRed() ]; + nSumG += pTmp[ pColor->GetGreen() ]; + nSumB += pTmp[ pColor->GetBlue() ]; + + // third row + nSumR += ( pTmp = pKoeff[ 6 ] )[ ( pColor = pRowTmp3 + nX )->GetRed() ]; + nSumG += pTmp[ pColor->GetGreen() ]; + nSumB += pTmp[ pColor->GetBlue() ]; + + nSumR += ( pTmp = pKoeff[ 7 ] )[ ( ++pColor )->GetRed() ]; + nSumG += pTmp[ pColor->GetGreen() ]; + nSumB += pTmp[ pColor->GetBlue() ]; + + nSumR += ( pTmp = pKoeff[ 8 ] )[ ( ++pColor )->GetRed() ]; + nSumG += pTmp[ pColor->GetGreen() ]; + nSumB += pTmp[ pColor->GetBlue() ]; + + // calculate destination color + pWriteAcc->SetPixel( nY, nX, BitmapColor( (BYTE) MinMax( nSumR / nDivisor, 0, 255 ), + (BYTE) MinMax( nSumG / nDivisor, 0, 255 ), + (BYTE) MinMax( nSumB / nDivisor, 0, 255 ) ) ); + } + + if( ++nY < nHeight ) + { + if( pRowTmp1 == pColRow1 ) + pRowTmp1 = pColRow2, pRowTmp2 = pColRow3, pRowTmp3 = pColRow1; + else if( pRowTmp1 == pColRow2 ) + pRowTmp1 = pColRow3, pRowTmp2 = pColRow1, pRowTmp3 = pColRow2; + else + pRowTmp1 = pColRow1, pRowTmp2 = pColRow2, pRowTmp3 = pColRow3; + + for( i = 0; i < nWidth2; i++ ) + pRowTmp3[ i ] = pReadAcc->GetColor( pRows[ nY + 2 ], pColm[ i ] ); + } + } + + delete[] pKoeff; + delete[] (BYTE*) pColRow1; + delete[] (BYTE*) pColRow2; + delete[] (BYTE*) pColRow3; + delete[] pColm; + delete[] pRows; + + aNewBmp.ReleaseAccess( pWriteAcc ); + + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + + maPrefMapMode = aMap; + maPrefSize = aSize; + } + } + + return bRet; +} + +// ----------------------------------------------------------------------------- + +BOOL Bitmap::ImplMedianFilter( const BmpFilterParam* pFilterParam, const Link* pProgress ) +{ + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + BOOL bRet = FALSE; + + if( pReadAcc ) + { + Bitmap aNewBmp( GetSizePixel(), 24 ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + + if( pWriteAcc ) + { + const long nWidth = pWriteAcc->Width(), nWidth2 = nWidth + 2; + const long nHeight = pWriteAcc->Height(), nHeight2 = nHeight + 2; + long* pColm = new long[ nWidth2 ]; + long* pRows = new long[ nHeight2 ]; + BitmapColor* pColRow1 = (BitmapColor*) new BYTE[ sizeof( BitmapColor ) * nWidth2 ]; + BitmapColor* pColRow2 = (BitmapColor*) new BYTE[ sizeof( BitmapColor ) * nWidth2 ]; + BitmapColor* pColRow3 = (BitmapColor*) new BYTE[ sizeof( BitmapColor ) * nWidth2 ]; + BitmapColor* pRowTmp1 = pColRow1; + BitmapColor* pRowTmp2 = pColRow2; + BitmapColor* pRowTmp3 = pColRow3; + BitmapColor* pColor; + long nY, nX, i; + long nR1, nR2, nR3, nR4, nR5, nR6, nR7, nR8, nR9; + long nG1, nG2, nG3, nG4, nG5, nG6, nG7, nG8, nG9; + long nB1, nB2, nB3, nB4, nB5, nB6, nB7, nB8, nB9; + + // create column LUT + for( i = 0; i < nWidth2; i++ ) + pColm[ i ] = ( i > 0 ) ? ( i - 1 ) : 0; + + pColm[ nWidth + 1 ] = pColm[ nWidth ]; + + // create row LUT + for( i = 0; i < nHeight2; i++ ) + pRows[ i ] = ( i > 0 ) ? ( i - 1 ) : 0; + + pRows[ nHeight + 1 ] = pRows[ nHeight ]; + + // read first three rows of bitmap color + for( i = 0; i < nWidth2; i++ ) + { + pColRow1[ i ] = pReadAcc->GetColor( pRows[ 0 ], pColm[ i ] ); + pColRow2[ i ] = pReadAcc->GetColor( pRows[ 1 ], pColm[ i ] ); + pColRow3[ i ] = pReadAcc->GetColor( pRows[ 2 ], pColm[ i ] ); + } + + // do median filtering + for( nY = 0; nY < nHeight; ) + { + for( nX = 0; nX < nWidth; nX++ ) + { + nR1 = ( pColor = pRowTmp1 + nX )->GetRed(), nG1 = pColor->GetGreen(), nB1 = pColor->GetBlue(); + nR2 = ( ++pColor )->GetRed(), nG2 = pColor->GetGreen(), nB2 = pColor->GetBlue(); + nR3 = ( ++pColor )->GetRed(), nG3 = pColor->GetGreen(), nB3 = pColor->GetBlue(); + + nR4 = ( pColor = pRowTmp2 + nX )->GetRed(), nG4 = pColor->GetGreen(), nB4 = pColor->GetBlue(); + nR5 = ( ++pColor )->GetRed(), nG5 = pColor->GetGreen(), nB5 = pColor->GetBlue(); + nR6 = ( ++pColor )->GetRed(), nG6 = pColor->GetGreen(), nB6 = pColor->GetBlue(); + + nR7 = ( pColor = pRowTmp3 + nX )->GetRed(), nG7 = pColor->GetGreen(), nB7 = pColor->GetBlue(); + nR8 = ( ++pColor )->GetRed(), nG8 = pColor->GetGreen(), nB8 = pColor->GetBlue(); + nR9 = ( ++pColor )->GetRed(), nG9 = pColor->GetGreen(), nB9 = pColor->GetBlue(); + + MNMX6( nR1, nR2, nR3, nR4, nR5, nR6 ); + MNMX5( nR7, nR2, nR3, nR4, nR5 ); + MNMX4( nR8, nR2, nR3, nR4 ); + MNMX3( nR9, nR2, nR3 ); + + MNMX6( nG1, nG2, nG3, nG4, nG5, nG6 ); + MNMX5( nG7, nG2, nG3, nG4, nG5 ); + MNMX4( nG8, nG2, nG3, nG4 ); + MNMX3( nG9, nG2, nG3 ); + + MNMX6( nB1, nB2, nB3, nB4, nB5, nB6 ); + MNMX5( nB7, nB2, nB3, nB4, nB5 ); + MNMX4( nB8, nB2, nB3, nB4 ); + MNMX3( nB9, nB2, nB3 ); + + // set destination color + pWriteAcc->SetPixel( nY, nX, BitmapColor( (BYTE) nR2, (BYTE) nG2, (BYTE) nB2 ) ); + } + + if( ++nY < nHeight ) + { + if( pRowTmp1 == pColRow1 ) + pRowTmp1 = pColRow2, pRowTmp2 = pColRow3, pRowTmp3 = pColRow1; + else if( pRowTmp1 == pColRow2 ) + pRowTmp1 = pColRow3, pRowTmp2 = pColRow1, pRowTmp3 = pColRow2; + else + pRowTmp1 = pColRow1, pRowTmp2 = pColRow2, pRowTmp3 = pColRow3; + + for( i = 0; i < nWidth2; i++ ) + pRowTmp3[ i ] = pReadAcc->GetColor( pRows[ nY + 2 ], pColm[ i ] ); + } + } + + delete[] (BYTE*) pColRow1; + delete[] (BYTE*) pColRow2; + delete[] (BYTE*) pColRow3; + delete[] pColm; + delete[] pRows; + + aNewBmp.ReleaseAccess( pWriteAcc ); + + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + + maPrefMapMode = aMap; + maPrefSize = aSize; + } + } + + return bRet; +} + +// ----------------------------------------------------------------------------- + +BOOL Bitmap::ImplSobelGrey( const BmpFilterParam* pFilterParam, const Link* pProgress ) +{ + BOOL bRet = ImplMakeGreyscales( 256 ); + + if( bRet ) + { + bRet = FALSE; + + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + + if( pReadAcc ) + { + Bitmap aNewBmp( GetSizePixel(), 8, &pReadAcc->GetPalette() ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + + if( pWriteAcc ) + { + BitmapColor aGrey( (BYTE) 0 ); + const long nWidth = pWriteAcc->Width(); + const long nHeight = pWriteAcc->Height(); + const long nMask111 = -1, nMask121 = 0, nMask131 = 1; + const long nMask211 = -2, nMask221 = 0, nMask231 = 2; + const long nMask311 = -1, nMask321 = 0, nMask331 = 1; + const long nMask112 = 1, nMask122 = 2, nMask132 = 1; + const long nMask212 = 0, nMask222 = 0, nMask232 = 0; + const long nMask312 = -1, nMask322 = -2, nMask332 = -1; + long nGrey11, nGrey12, nGrey13; + long nGrey21, nGrey22, nGrey23; + long nGrey31, nGrey32, nGrey33; + long* pHMap = new long[ nWidth + 2 ]; + long* pVMap = new long[ nHeight + 2 ]; + long nX, nY, nSum1, nSum2; + + // fill mapping tables + pHMap[ 0 ] = 0; + for( nX = 1; nX <= nWidth; nX++ ) + pHMap[ nX ] = nX - 1; + pHMap[ nWidth + 1 ] = nWidth - 1; + + pVMap[ 0 ] = 0; + for( nY = 1; nY <= nHeight; nY++ ) + pVMap[ nY ] = nY - 1; + pVMap[ nHeight + 1 ] = nHeight - 1; + + for( nY = 0; nY < nHeight ; nY++ ) + { + nGrey11 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 0 ] ).GetIndex(); + nGrey12 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 1 ] ).GetIndex(); + nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 2 ] ).GetIndex(); + nGrey21 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 0 ] ).GetIndex(); + nGrey22 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 1 ] ).GetIndex(); + nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 2 ] ).GetIndex(); + nGrey31 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 0 ] ).GetIndex(); + nGrey32 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 1 ] ).GetIndex(); + nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 2 ] ).GetIndex(); + + for( nX = 0; nX < nWidth; nX++ ) + { + nSum1 = nSum2 = 0; + + nSum1 += nMask111 * nGrey11; + nSum2 += nMask112 * nGrey11; + + nSum1 += nMask121 * nGrey12; + nSum2 += nMask122 * nGrey12; + + nSum1 += nMask131 * nGrey13; + nSum2 += nMask132 * nGrey13; + + nSum1 += nMask211 * nGrey21; + nSum2 += nMask212 * nGrey21; + + nSum1 += nMask221 * nGrey22; + nSum2 += nMask222 * nGrey22; + + nSum1 += nMask231 * nGrey23; + nSum2 += nMask232 * nGrey23; + + nSum1 += nMask311 * nGrey31; + nSum2 += nMask312 * nGrey31; + + nSum1 += nMask321 * nGrey32; + nSum2 += nMask322 * nGrey32; + + nSum1 += nMask331 * nGrey33; + nSum2 += nMask332 * nGrey33; + + nSum1 = (long) sqrt( ( nSum1 * nSum1 + nSum2 * nSum2 ) ); + aGrey.SetIndex( ~(BYTE) VOS_BOUND( nSum1, 0, 255 ) ); + pWriteAcc->SetPixel( nY, nX, aGrey ); + + if( nX < ( nWidth - 1 ) ) + { + const long nNextX = pHMap[ nX + 3 ]; + + nGrey11 = nGrey12; nGrey12 = nGrey13; nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], nNextX ).GetIndex(); + nGrey21 = nGrey22; nGrey22 = nGrey23; nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], nNextX ).GetIndex(); + nGrey31 = nGrey32; nGrey32 = nGrey33; nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], nNextX ).GetIndex(); + } + } + } + + delete[] pHMap; + delete[] pVMap; + aNewBmp.ReleaseAccess( pWriteAcc ); + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + + maPrefMapMode = aMap; + maPrefSize = aSize; + } + } + } + + return bRet; +} + +// ----------------------------------------------------------------------------- + +BOOL Bitmap::ImplEmbossGrey( const BmpFilterParam* pFilterParam, const Link* pProgress ) +{ + BOOL bRet = ImplMakeGreyscales( 256 ); + + if( bRet ) + { + bRet = FALSE; + + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + + if( pReadAcc ) + { + Bitmap aNewBmp( GetSizePixel(), 8, &pReadAcc->GetPalette() ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + + if( pWriteAcc ) + { + BitmapColor aGrey( (BYTE) 0 ); + const long nWidth = pWriteAcc->Width(); + const long nHeight = pWriteAcc->Height(); + long nGrey11, nGrey12, nGrey13; + long nGrey21, nGrey22, nGrey23; + long nGrey31, nGrey32, nGrey33; + double fAzim = ( ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_EMBOSS_GREY ) ? + ( pFilterParam->maEmbossAngles.mnAzimuthAngle100 * 0.01 ) : 0.0 ) * F_PI180; + double fElev = ( ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_EMBOSS_GREY ) ? + ( pFilterParam->maEmbossAngles.mnElevationAngle100 * 0.01 ) : 90.0 ) * F_PI180; + long* pHMap = new long[ nWidth + 2 ]; + long* pVMap = new long[ nHeight + 2 ]; + long nX, nY, nNx, nNy, nDotL; + const long nLx = FRound( cos( fAzim ) * cos( fElev ) * 255.0 ); + const long nLy = FRound( sin( fAzim ) * cos( fElev ) * 255.0 ); + const long nLz = FRound( sin( fElev ) * 255.0 ); + const long nZ2 = ( ( 6 * 255 ) / 4 ) * ( ( 6 * 255 ) / 4 ); + const long nNzLz = ( ( 6 * 255 ) / 4 ) * nLz; + const BYTE cLz = (BYTE) VOS_BOUND( nLz, 0, 255 ); + + // fill mapping tables + pHMap[ 0 ] = 0; + for( nX = 1; nX <= nWidth; nX++ ) + pHMap[ nX ] = nX - 1; + pHMap[ nWidth + 1 ] = nWidth - 1; + + pVMap[ 0 ] = 0; + for( nY = 1; nY <= nHeight; nY++ ) + pVMap[ nY ] = nY - 1; + pVMap[ nHeight + 1 ] = nHeight - 1; + + for( nY = 0; nY < nHeight ; nY++ ) + { + nGrey11 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 0 ] ).GetIndex(); + nGrey12 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 1 ] ).GetIndex(); + nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 2 ] ).GetIndex(); + nGrey21 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 0 ] ).GetIndex(); + nGrey22 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 1 ] ).GetIndex(); + nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 2 ] ).GetIndex(); + nGrey31 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 0 ] ).GetIndex(); + nGrey32 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 1 ] ).GetIndex(); + nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 2 ] ).GetIndex(); + + for( nX = 0; nX < nWidth; nX++ ) + { + nNx = nGrey11 + nGrey21 + nGrey31 - nGrey13 - nGrey23 - nGrey33; + nNy = nGrey31 + nGrey32 + nGrey33 - nGrey11 - nGrey12 - nGrey13; + + if( !nNx && !nNy ) + aGrey.SetIndex( cLz ); + else if( ( nDotL = nNx * nLx + nNy * nLy +nNzLz ) < 0 ) + aGrey.SetIndex( 0 ); + else + { + const double fGrey = nDotL / sqrt( nNx * nNx + nNy * nNy + nZ2 ); + aGrey.SetIndex( (BYTE) VOS_BOUND( fGrey, 0, 255 ) ); + } + + pWriteAcc->SetPixel( nY, nX, aGrey ); + + if( nX < ( nWidth - 1 ) ) + { + const long nNextX = pHMap[ nX + 3 ]; + + nGrey11 = nGrey12; nGrey12 = nGrey13; nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], nNextX ).GetIndex(); + nGrey21 = nGrey22; nGrey22 = nGrey23; nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], nNextX ).GetIndex(); + nGrey31 = nGrey32; nGrey32 = nGrey33; nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], nNextX ).GetIndex(); + } + } + } + + delete[] pHMap; + delete[] pVMap; + aNewBmp.ReleaseAccess( pWriteAcc ); + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + + maPrefMapMode = aMap; + maPrefSize = aSize; + } + } + } + + return bRet; +} + +// ----------------------------------------------------------------------------- + +BOOL Bitmap::ImplSolarize( const BmpFilterParam* pFilterParam, const Link* pProgress ) +{ + BOOL bRet = FALSE; + BitmapWriteAccess* pWriteAcc = AcquireWriteAccess(); + + if( pWriteAcc ) + { + const BYTE cThreshold = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_SOLARIZE ) ? + pFilterParam->mcSolarGreyThreshold : 128; + + if( pWriteAcc->HasPalette() ) + { + const BitmapPalette& rPal = pWriteAcc->GetPalette(); + + for( USHORT i = 0, nCount = rPal.GetEntryCount(); i < nCount; i++ ) + { + if( rPal[ i ].GetLuminance() >= cThreshold ) + { + BitmapColor aCol( rPal[ i ] ); + pWriteAcc->SetPaletteColor( i, aCol.Invert() ); + } + } + } + else + { + BitmapColor aCol; + const long nWidth = pWriteAcc->Width(); + const long nHeight = pWriteAcc->Height(); + + for( long nY = 0; nY < nHeight ; nY++ ) + { + for( long nX = 0; nX < nWidth; nX++ ) + { + aCol = pWriteAcc->GetPixel( nY, nX ); + + if( aCol.GetLuminance() >= cThreshold ) + pWriteAcc->SetPixel( nY, nX, aCol.Invert() ); + } + } + } + + ReleaseAccess( pWriteAcc ); + bRet = TRUE; + } + + return bRet; +} + +// ----------------------------------------------------------------------------- + +BOOL Bitmap::ImplSepia( const BmpFilterParam* pFilterParam, const Link* pProgress ) +{ + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + BOOL bRet = FALSE; + + if( pReadAcc ) + { + long nSepiaPercent = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_SEPIA ) ? + pFilterParam->mcSolarGreyThreshold : 10; + const long nSepia = 10000 - 100 * VOS_BOUND( nSepiaPercent, 0, 100 ); + BitmapPalette aSepiaPal( 256 ); + + DBG_ASSERT( nSepiaPercent <= 100, "Bitmap::ImplSepia(): sepia value out of range; defaulting to 100%" ); + + for( long i = 0; i < 256; i++ ) + { + BitmapColor& rCol = aSepiaPal[ i ]; + const BYTE cSepiaValue = (BYTE) ( ( nSepia * i ) / 10000 ); + + rCol.SetRed( (BYTE) i ); + rCol.SetGreen( cSepiaValue ); + rCol.SetBlue( cSepiaValue ); + } + + Bitmap aNewBmp( GetSizePixel(), 8, &aSepiaPal ); + BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); + + if( pWriteAcc ) + { + BitmapColor aCol( (BYTE) 0 ); + const long nWidth = pWriteAcc->Width(); + const long nHeight = pWriteAcc->Height(); + + if( pReadAcc->HasPalette() ) + { + for( long nY = 0; nY < nHeight ; nY++ ) + { + const USHORT nPalCount = pReadAcc->GetPaletteEntryCount(); + BYTE* pIndexMap = new BYTE[ nPalCount ]; + + for( USHORT i = 0; i < nPalCount; i++ ) + pIndexMap[ i ] = pReadAcc->GetPaletteColor( i ).GetLuminance(); + + for( long nX = 0; nX < nWidth; nX++ ) + { + aCol.SetIndex( pIndexMap[ pReadAcc->GetPixel( nY, nX ).GetIndex() ] ); + pWriteAcc->SetPixel( nY, nX, aCol ); + } + + delete[] pIndexMap; + } + } + else + { + for( long nY = 0; nY < nHeight ; nY++ ) + { + for( long nX = 0; nX < nWidth; nX++ ) + { + aCol.SetIndex( pReadAcc->GetPixel( nY, nX ).GetLuminance() ); + pWriteAcc->SetPixel( nY, nX, aCol ); + } + } + } + + aNewBmp.ReleaseAccess( pWriteAcc ); + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = aNewBmp; + + maPrefMapMode = aMap; + maPrefSize = aSize; + } + } + + return bRet; +} + +// ----------------------------------------------------------------------------- + +BOOL Bitmap::ImplMosaic( const BmpFilterParam* pFilterParam, const Link* pProgress ) +{ + ULONG nTileWidth = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_MOSAIC ) ? + pFilterParam->maMosaicTileSize.mnTileWidth : 4; + ULONG nTileHeight = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_MOSAIC ) ? + pFilterParam->maMosaicTileSize.mnTileHeight : 4; + BOOL bRet = FALSE; + + if( !nTileWidth ) + nTileWidth = 1; + + if( !nTileHeight ) + nTileHeight = 1; + + if( nTileWidth > 1 || nTileHeight > 1 ) + { + Bitmap* pNewBmp; + BitmapReadAccess* pReadAcc; + BitmapWriteAccess* pWriteAcc; + + if( GetBitCount() > 8 ) + { + pNewBmp = NULL; + pReadAcc = pWriteAcc = AcquireWriteAccess(); + } + else + { + pNewBmp = new Bitmap( GetSizePixel(), 24 ); + pReadAcc = AcquireReadAccess(); + pWriteAcc = pNewBmp->AcquireWriteAccess(); + } + + if( pReadAcc && pWriteAcc ) + { + BitmapColor aCol; + long nWidth = pReadAcc->Width(); + long nHeight = pReadAcc->Height(); + long nX, nY, nX1, nX2, nY1, nY2, nSumR, nSumG, nSumB; + double fArea_1; + + nY1 = 0; nY2 = nTileHeight - 1; + + if( nY2 >= nHeight ) + nY2 = nHeight - 1; + + do + { + nX1 = 0; nX2 = nTileWidth - 1; + + if( nX2 >= nWidth ) + nX2 = nWidth - 1; + + fArea_1 = 1.0 / ( ( nX2 - nX1 + 1 ) * ( nY2 - nY1 + 1 ) ); + + if( !pNewBmp ) + { + do + { + for( nY = nY1, nSumR = nSumG = nSumB = 0; nY <= nY2; nY++ ) + { + for( nX = nX1; nX <= nX2; nX++ ) + { + aCol = pReadAcc->GetPixel( nY, nX ); + nSumR += aCol.GetRed(); + nSumG += aCol.GetGreen(); + nSumB += aCol.GetBlue(); + } + } + + aCol.SetRed( (BYTE) ( nSumR * fArea_1 ) ); + aCol.SetGreen( (BYTE) ( nSumG * fArea_1 ) ); + aCol.SetBlue( (BYTE) ( nSumB * fArea_1 ) ); + + for( nY = nY1; nY <= nY2; nY++ ) + for( nX = nX1; nX <= nX2; nX++ ) + pWriteAcc->SetPixel( nY, nX, aCol ); + + nX1 += nTileWidth; nX2 += nTileWidth; + + if( nX2 >= nWidth ) + { + nX2 = nWidth - 1; + fArea_1 = 1.0 / ( ( nX2 - nX1 + 1 ) * ( nY2 - nY1 + 1 ) ); + } + } + while( nX1 < nWidth ); + } + else + { + do + { + for( nY = nY1, nSumR = nSumG = nSumB = 0; nY <= nY2; nY++ ) + { + for( nX = nX1; nX <= nX2; nX++ ) + { + const BitmapColor& rCol = pReadAcc->GetPaletteColor( (BYTE) pReadAcc->GetPixel( nY, nX ) ); + nSumR += rCol.GetRed(); + nSumG += rCol.GetGreen(); + nSumB += rCol.GetBlue(); + } + } + + aCol.SetRed( (BYTE) ( nSumR * fArea_1 ) ); + aCol.SetGreen( (BYTE) ( nSumG * fArea_1 ) ); + aCol.SetBlue( (BYTE) ( nSumB * fArea_1 ) ); + + for( nY = nY1; nY <= nY2; nY++ ) + for( nX = nX1; nX <= nX2; nX++ ) + pWriteAcc->SetPixel( nY, nX, aCol ); + + nX1 += nTileWidth; nX2 += nTileWidth; + + if( nX2 >= nWidth ) + { + nX2 = nWidth - 1; + fArea_1 = 1.0 / ( ( nX2 - nX1 + 1 ) * ( nY2 - nY1 + 1 ) ); + } + } + while( nX1 < nWidth ); + } + + nY1 += nTileHeight; nY2 += nTileHeight; + + if( nY2 >= nHeight ) + nY2 = nHeight - 1; + } + while( nY1 < nHeight ); + + bRet = TRUE; + } + + ReleaseAccess( pReadAcc ); + + if( pNewBmp ) + { + pNewBmp->ReleaseAccess( pWriteAcc ); + + if( bRet ) + { + const MapMode aMap( maPrefMapMode ); + const Size aSize( maPrefSize ); + + *this = *pNewBmp; + + maPrefMapMode = aMap; + maPrefSize = aSize; + } + + delete pNewBmp; + } + } + else + bRet = TRUE; + + return bRet; +} diff --git a/vcl/source/gdi/bitmapex.cxx b/vcl/source/gdi/bitmapex.cxx new file mode 100644 index 000000000000..a0e388a1db0f --- /dev/null +++ b/vcl/source/gdi/bitmapex.cxx @@ -0,0 +1,690 @@ +/************************************************************************* + * + * $RCSfile: bitmapex.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_BITMAPEX_CXX + +#ifndef _RTL_CRC_H_ +#include <rtl/crc.h> +#endif +#ifndef _SV_SALBTYPE_HXX +#include <salbtype.hxx> +#endif +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _SV_OUTDEV_HXX +#include <outdev.hxx> +#endif +#ifndef _SV_ALPHA_HXX +#include <alpha.hxx> +#endif +#ifndef _SV_BITMAPEX_HXX +#include <bitmapex.hxx> +#endif + +// ------------ +// - BitmapEx - +// ------------ + +BitmapEx::BitmapEx() : + eTransparent( TRANSPARENT_NONE ), + bAlpha ( FALSE ) +{ +} + +// ------------------------------------------------------------------ + +BitmapEx::BitmapEx( const BitmapEx& rBitmapEx ) : + aBitmap ( rBitmapEx.aBitmap ), + aMask ( rBitmapEx.aMask ), + aBitmapSize ( rBitmapEx.aBitmapSize ), + aTransparentColor ( rBitmapEx.aTransparentColor ), + eTransparent ( rBitmapEx.eTransparent ), + bAlpha ( rBitmapEx.bAlpha ) +{ +} + +// ------------------------------------------------------------------ + +BitmapEx::BitmapEx( const Bitmap& rBmp ) : + aBitmap ( rBmp ), + aBitmapSize ( aBitmap.GetSizePixel() ), + eTransparent( TRANSPARENT_NONE ), + bAlpha ( FALSE ) +{ +} + +// ------------------------------------------------------------------ + +BitmapEx::BitmapEx( const Bitmap& rBmp, const Bitmap& rMask ) : + aBitmap ( rBmp ), + aMask ( rMask ), + aBitmapSize ( aBitmap.GetSizePixel() ), + eTransparent ( !rMask ? TRANSPARENT_NONE : TRANSPARENT_BITMAP ), + bAlpha ( FALSE ) +{ +} + +// ------------------------------------------------------------------ + +BitmapEx::BitmapEx( const Bitmap& rBmp, const AlphaMask& rAlphaMask ) : + aBitmap ( rBmp ), + aMask ( rAlphaMask.ImplGetBitmap() ), + aBitmapSize ( aBitmap.GetSizePixel() ), + eTransparent ( !rAlphaMask ? TRANSPARENT_NONE : TRANSPARENT_BITMAP ), + bAlpha ( !rAlphaMask ? FALSE : TRUE ) +{ +} + +// ------------------------------------------------------------------ + +BitmapEx::BitmapEx( const Bitmap& rBmp, const Color& rTransparentColor ) : + aBitmap ( rBmp ), + aBitmapSize ( aBitmap.GetSizePixel() ), + aTransparentColor ( rTransparentColor ), + eTransparent ( TRANSPARENT_BITMAP ), + bAlpha ( FALSE ) +{ + aMask = aBitmap.CreateMask( aTransparentColor ); +} + +// ------------------------------------------------------------------ + +BitmapEx::~BitmapEx() +{ +} + +// ------------------------------------------------------------------ + +BitmapEx& BitmapEx::operator=( const BitmapEx& rBitmapEx ) +{ + if( &rBitmapEx != this ) + { + aBitmap = rBitmapEx.aBitmap; + aMask = rBitmapEx.aMask; + aBitmapSize = rBitmapEx.aBitmapSize; + aTransparentColor = rBitmapEx.aTransparentColor; + eTransparent = rBitmapEx.eTransparent; + bAlpha = rBitmapEx.bAlpha; + } + + return *this; +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::operator==( const BitmapEx& rBitmapEx ) const +{ + if( eTransparent != rBitmapEx.eTransparent ) + return FALSE; + + if( aBitmap != rBitmapEx.aBitmap ) + return FALSE; + + if( aBitmapSize != rBitmapEx.aBitmapSize ) + return FALSE; + + if( eTransparent == TRANSPARENT_NONE ) + return TRUE; + + if( eTransparent == TRANSPARENT_COLOR ) + return aTransparentColor == rBitmapEx.aTransparentColor; + + return( ( aMask == rBitmapEx.aMask ) && ( bAlpha == rBitmapEx.bAlpha ) ); +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::IsEqual( const BitmapEx& rBmpEx ) const +{ + return( rBmpEx.eTransparent == eTransparent && + rBmpEx.bAlpha == bAlpha && + rBmpEx.aBitmap.IsEqual( aBitmap ) && + rBmpEx.aMask.IsEqual( aMask ) ); +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::IsEmpty() const +{ + return( aBitmap.IsEmpty() && aMask.IsEmpty() ); +} + +// ------------------------------------------------------------------ + +void BitmapEx::SetEmpty() +{ + aBitmap.SetEmpty(); + aMask.SetEmpty(); + eTransparent = TRANSPARENT_NONE; + bAlpha = FALSE; +} + +// ------------------------------------------------------------------ + +void BitmapEx::Clear() +{ + SetEmpty(); +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::IsTransparent() const +{ + return( eTransparent != TRANSPARENT_NONE ); +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::IsAlpha() const +{ + return( IsTransparent() && bAlpha ); +} + +// ------------------------------------------------------------------ + +Bitmap BitmapEx::GetBitmap( const Color* pTransReplaceColor ) const +{ + Bitmap aRetBmp( aBitmap ); + + if( pTransReplaceColor && ( eTransparent != TRANSPARENT_NONE ) ) + { + Bitmap aTempMask; + + if( eTransparent == TRANSPARENT_COLOR ) + aTempMask = aBitmap.CreateMask( aTransparentColor ); + else + aTempMask = aMask; + + if( !IsAlpha() ) + aRetBmp.Replace( aTempMask, *pTransReplaceColor ); + else + aRetBmp.Replace( GetAlpha(), *pTransReplaceColor ); + } + + return aRetBmp; +} + +// ------------------------------------------------------------------ + +Bitmap BitmapEx::GetMask() const +{ + Bitmap aRet( aMask ); + + if( IsAlpha() ) + aRet.ImplMakeMono( 255 ); + + return aRet; +} + +// ------------------------------------------------------------------ + +AlphaMask BitmapEx::GetAlpha() const +{ + AlphaMask aAlpha; + + if( IsAlpha() ) + aAlpha.ImplSetBitmap( aMask ); + else + aAlpha = aMask; + + return aAlpha; +} + +// ------------------------------------------------------------------ + +ULONG BitmapEx::GetSizeBytes() const +{ + ULONG nSizeBytes = aBitmap.GetSizeBytes(); + + if( eTransparent == TRANSPARENT_BITMAP ) + nSizeBytes += aMask.GetSizeBytes(); + + return nSizeBytes; +} + +// ------------------------------------------------------------------ + +ULONG BitmapEx::GetChecksum() const +{ + sal_uInt32 nCrc = aBitmap.GetChecksum(); + SVBT32 aBT32; + + LongToSVBT32( (long) eTransparent, aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( (long) bAlpha, aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + if( ( TRANSPARENT_BITMAP == eTransparent ) && !aMask.IsEmpty() ) + { + LongToSVBT32( aMask.GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + + return nCrc; +} + +// ------------------------------------------------------------------ + +void BitmapEx::SetSizePixel( const Size& rNewSize ) +{ + Scale( rNewSize ); +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::Invert() +{ + BOOL bRet = FALSE; + + if( !!aBitmap ) + { + bRet = aBitmap.Invert(); + + if( bRet && ( eTransparent == TRANSPARENT_COLOR ) ) + aTransparentColor = BitmapColor( aTransparentColor ).Invert(); + } + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::Mirror( ULONG nMirrorFlags ) +{ + BOOL bRet = FALSE; + + if( !!aBitmap ) + { + bRet = aBitmap.Mirror( nMirrorFlags ); + + if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask ) + aMask.Mirror( nMirrorFlags ); + } + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::Scale( const double& rScaleX, const double& rScaleY, ULONG nScaleFlag ) +{ + BOOL bRet = FALSE; + + if( !!aBitmap ) + { + bRet = aBitmap.Scale( rScaleX, rScaleY, nScaleFlag ); + + if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask ) + aMask.Scale( rScaleX, rScaleY, BMP_SCALE_FAST ); + + aBitmapSize = aBitmap.GetSizePixel(); + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL BitmapEx::Scale( const Size& rNewSize, ULONG nScaleFlag ) +{ + BOOL bRet; + + if( aBitmapSize.Width() && aBitmapSize.Height() ) + { + bRet = Scale( (double) rNewSize.Width() / aBitmapSize.Width(), + (double) rNewSize.Height() / aBitmapSize.Height(), + nScaleFlag ); + } + else + bRet = TRUE; + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::Rotate( long nAngle10, const Color& rFillColor ) +{ + BOOL bRet = FALSE; + + if( !!aBitmap ) + { + const BOOL bTransRotate = ( Color( COL_TRANSPARENT ) == rFillColor ); + + if( bTransRotate ) + { + if( eTransparent == TRANSPARENT_COLOR ) + bRet = aBitmap.Rotate( nAngle10, aTransparentColor ); + else + { + bRet = aBitmap.Rotate( nAngle10, COL_BLACK ); + + if( eTransparent == TRANSPARENT_NONE ) + { + aMask = Bitmap( aBitmapSize, 1 ); + aMask.Erase( COL_BLACK ); + eTransparent = TRANSPARENT_BITMAP; + } + + if( bRet && !!aMask ) + aMask.Rotate( nAngle10, COL_WHITE ); + } + } + else + { + bRet = aBitmap.Rotate( nAngle10, rFillColor ); + + if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask ) + aMask.Rotate( nAngle10, COL_WHITE ); + } + + aBitmapSize = aBitmap.GetSizePixel(); + } + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::Crop( const Rectangle& rRectPixel ) +{ + BOOL bRet = FALSE; + + if( !!aBitmap ) + { + bRet = aBitmap.Crop( rRectPixel ); + + if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask ) + aMask.Crop( rRectPixel ); + + aBitmapSize = aBitmap.GetSizePixel(); + } + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::Convert( BmpConversion eConversion ) +{ + return( !!aBitmap ? aBitmap.Convert( eConversion ) : FALSE ); +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::ReduceColors( USHORT nNewColorCount, BmpReduce eReduce ) +{ + return( !!aBitmap ? aBitmap.ReduceColors( nNewColorCount, eReduce ) : FALSE ); +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::Expand( ULONG nDX, ULONG nDY, const Color* pInitColor, BOOL bExpandTransparent ) +{ + BOOL bRet = FALSE; + + if( !!aBitmap ) + { + bRet = aBitmap.Expand( nDX, nDY, pInitColor ); + + if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask ) + { + Color aColor( bExpandTransparent ? COL_WHITE : COL_BLACK ); + aMask.Expand( nDX, nDY, &aColor ); + } + + aBitmapSize = aBitmap.GetSizePixel(); + } + + return bRet; +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::Dither( ULONG nDitherFlags, const BitmapPalette* pDitherPal ) +{ + return( !!aBitmap ? aBitmap.Dither( nDitherFlags, pDitherPal ) : FALSE ); +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::Replace( const Color& rSearchColor, const Color& rReplaceColor, ULONG nTol ) +{ + return( !!aBitmap ? aBitmap.Replace( rSearchColor, rReplaceColor, nTol ) : FALSE ); +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::Replace( const Color* pSearchColors, const Color* pReplaceColors, ULONG nColorCount, const ULONG* pTols ) +{ + return( !!aBitmap ? aBitmap.Replace( pSearchColors, pReplaceColors, nColorCount, (ULONG*) pTols ) : FALSE ); +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::Adjust( short nLuminancePercent, short nContrastPercent, + short nChannelRPercent, short nChannelGPercent, short nChannelBPercent, + double fGamma, BOOL bInvert ) +{ + return( !!aBitmap ? aBitmap.Adjust( nLuminancePercent, nContrastPercent, + nChannelRPercent, nChannelGPercent, nChannelBPercent, + fGamma, bInvert ) : FALSE ); +} + +// ------------------------------------------------------------------ + +BOOL BitmapEx::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress ) +{ + return( !!aBitmap ? aBitmap.Filter( eFilter, pFilterParam, pProgress ) : FALSE ); +} + +// ------------------------------------------------------------------ + +void BitmapEx::Draw( OutputDevice* pOutDev, const Point& rDestPt ) const +{ + pOutDev->DrawBitmapEx( rDestPt, *this ); +} + +// ------------------------------------------------------------------ + +void BitmapEx::Draw( OutputDevice* pOutDev, + const Point& rDestPt, const Size& rDestSize ) const +{ + pOutDev->DrawBitmapEx( rDestPt, rDestSize, *this ); +} + +// ------------------------------------------------------------------ + +void BitmapEx::Draw( OutputDevice* pOutDev, + const Point& rDestPt, const Size& rDestSize, + const Point& rSrcPtPixel, const Size& rSrcSizePixel ) const +{ + pOutDev->DrawBitmapEx( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, *this ); +} + +// ------------------------------------------------------------------ + +SvStream& operator<<( SvStream& rOStm, const BitmapEx& rBitmapEx ) +{ + rBitmapEx.aBitmap.Write( rOStm ); + + rOStm << (UINT32) 0x25091962; + rOStm << (UINT32) 0xACB20201; + rOStm << (BYTE) rBitmapEx.eTransparent; + + if( rBitmapEx.eTransparent == TRANSPARENT_BITMAP ) + rBitmapEx.aMask.Write( rOStm ); + else if( rBitmapEx.eTransparent == TRANSPARENT_COLOR ) + rOStm << rBitmapEx.aTransparentColor; + + return rOStm; +} + +// ------------------------------------------------------------------ + +SvStream& operator>>( SvStream& rIStm, BitmapEx& rBitmapEx ) +{ + Bitmap aBmp; + + rIStm >> aBmp; + + if( !rIStm.GetError() ) + { + const ULONG nStmPos = rIStm.Tell(); + UINT32 nMagic1; + UINT32 nMagic2; + + rIStm >> nMagic1 >> nMagic2; + + if( ( nMagic1 != 0x25091962 ) || ( nMagic2 != 0xACB20201 ) || rIStm.GetError() ) + { + rIStm.Seek( nStmPos ); + rBitmapEx = aBmp; + } + else + { + BYTE bTransparent; + + rIStm >> bTransparent; + + if( bTransparent == (BYTE) TRANSPARENT_BITMAP ) + { + Bitmap aMask; + + rIStm >> aMask; + + if( !!aMask) + { + // do we have an alpha mask? + if( ( 8 == aMask.GetBitCount() ) && aMask.HasGreyPalette() ) + { + AlphaMask aAlpha; + + // create alpha mask quickly (without greyscale conversion) + aAlpha.ImplSetBitmap( aMask ); + rBitmapEx = BitmapEx( aBmp, aAlpha ); + } + else + rBitmapEx = BitmapEx( aBmp, aMask ); + } + else + rBitmapEx = aBmp; + } + else if( bTransparent == (BYTE) TRANSPARENT_COLOR ) + { + Color aTransparentColor; + + rIStm >> aTransparentColor; + rBitmapEx = BitmapEx( aBmp, aTransparentColor ); + } + else + rBitmapEx = aBmp; + } + } + + return rIStm; +} + +// ------------------------------------------------------------------ + +#ifdef REMOTE_APPSERVER + +void BitmapEx::ImplDrawRemote( OutputDevice* pOut, + const Point& rSrcPt, const Size& rSrcSz, + const Point& rDestPt, const Size& rDestSz ) const +{ + if( !!aBitmap ) + { + switch( eTransparent ) + { + case( TRANSPARENT_NONE ): + aBitmap.ImplDrawRemote( pOut, rSrcPt, rSrcSz, rDestPt, rDestSz ); + break; + + case( TRANSPARENT_BITMAP ): + { + if( !!aMask ) + { + if( IsAlpha() ) + aBitmap.ImplDrawRemoteAlpha( pOut, rSrcPt, rSrcSz, rDestPt, rDestSz, GetAlpha() ); + else + aBitmap.ImplDrawRemoteEx( pOut, rSrcPt, rSrcSz, rDestPt, rDestSz, aMask ); + } + else + aBitmap.ImplDrawRemote( pOut, rSrcPt, rSrcSz, rDestPt, rDestSz ); + } + break; + + default: + { + DBG_ERROR( "BitmapEx::ImplDrawRemote???" ); + } + break; + } + } +} + +#endif // REMOTE diff --git a/vcl/source/gdi/bmpacc.cxx b/vcl/source/gdi/bmpacc.cxx new file mode 100644 index 000000000000..6fc3657c90fd --- /dev/null +++ b/vcl/source/gdi/bmpacc.cxx @@ -0,0 +1,448 @@ +/************************************************************************* + * + * $RCSfile: bmpacc.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_BMPACC_CXX + +#ifdef W31 +#include <tools/svwin.h> +#endif + +#ifndef _SV_SALBTYPE_HXX +#include <salbtype.hxx> +#endif +#ifndef _SV_IMPBMP_HXX +#include <impbmp.hxx> +#endif +#ifndef _SV_BITMAP_HXX +#include <bitmap.hxx> +#endif +#ifndef _SV_BMPACC_HXX +#include <bmpacc.hxx> +#endif +#include <string.h> + +// -------------------- +// - BitmapReadAccess - +// -------------------- + +BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap, BOOL bModify ) : + mpBuffer ( NULL ), + mpScanBuf ( NULL ), + mbModify ( bModify ), + mFncGetPixel ( NULL ), + mFncSetPixel ( NULL ) +{ + ImplCreate( rBitmap ); +} + +// ------------------------------------------------------------------ + +BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap ) : + mpBuffer ( NULL ), + mpScanBuf ( NULL ), + mbModify ( FALSE ), + mFncGetPixel ( NULL ), + mFncSetPixel ( NULL ) +{ + ImplCreate( rBitmap ); +} + +// ------------------------------------------------------------------ + +BitmapReadAccess::~BitmapReadAccess() +{ + ImplDestroy(); +} + +// ------------------------------------------------------------------ + +void BitmapReadAccess::ImplCreate( Bitmap& rBitmap ) +{ + ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap(); + + BMP_ASSERT( pImpBmp, "Forbidden Access to empty bitmap!" ); + + if( pImpBmp ) + { + if( mbModify && !maBitmap.ImplGetImpBitmap() ) + { + rBitmap.ImplMakeUnique(); + pImpBmp = rBitmap.ImplGetImpBitmap(); + } + else + { + BMP_ASSERT( !mbModify || pImpBmp->ImplGetRefCount() == 2, + "Unpredictable results: bitmap is referenced more than once!" ); + } + + mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify ); + + if( !mpBuffer ) + { + ImpBitmap* pNewImpBmp = new ImpBitmap; + + if( pNewImpBmp->ImplCreate( *pImpBmp, rBitmap.GetBitCount() ) ) + { + pImpBmp = pNewImpBmp; + rBitmap.ImplSetImpBitmap( pImpBmp ); + mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify ); + } + else + delete pNewImpBmp; + } + + if( mpBuffer ) + { + const long nHeight = mpBuffer->mnHeight; + Scanline pTmpLine = mpBuffer->mpBits; + + mpScanBuf = new Scanline[ nHeight ]; + maColorMask = mpBuffer->maColorMask; + + if( BMP_SCANLINE_ADJUSTMENT( mpBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN ) + { + for( long nY = 0L; nY < nHeight; nY++, pTmpLine += mpBuffer->mnScanlineSize ) + mpScanBuf[ nY ] = pTmpLine; + } + else + { + for( long nY = nHeight - 1; nY >= 0; nY--, pTmpLine += mpBuffer->mnScanlineSize ) + mpScanBuf[ nY ] = pTmpLine; + } + + if( !ImplSetAccessPointers( BMP_SCANLINE_FORMAT( mpBuffer->mnFormat ) ) ) + { + delete[] mpScanBuf; + mpScanBuf = NULL; + + pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify ); + mpBuffer = NULL; + } + else + maBitmap = rBitmap; + } + } +} + +// ------------------------------------------------------------------ + +void BitmapReadAccess::ImplDestroy() +{ + ImpBitmap* pImpBmp = maBitmap.ImplGetImpBitmap(); + + delete[] mpScanBuf; + mpScanBuf = NULL; + + if( mpBuffer && pImpBmp ) + { + pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify ); + mpBuffer = NULL; + } +} + +// ------------------------------------------------------------------ + +BOOL BitmapReadAccess::ImplSetAccessPointers( ULONG nFormat ) +{ + BOOL bRet = TRUE; + + switch( nFormat ) + { + CASE_FORMAT( _1BIT_MSB_PAL ) + CASE_FORMAT( _1BIT_LSB_PAL ) + CASE_FORMAT( _4BIT_MSN_PAL ) + CASE_FORMAT( _4BIT_LSN_PAL ) + CASE_FORMAT( _8BIT_PAL ) + CASE_FORMAT( _8BIT_TC_MASK ) + CASE_FORMAT( _16BIT_TC_MASK ) + CASE_FORMAT( _24BIT_TC_BGR ) + CASE_FORMAT( _24BIT_TC_RGB ) + CASE_FORMAT( _24BIT_TC_MASK ) + CASE_FORMAT( _32BIT_TC_ABGR ) + CASE_FORMAT( _32BIT_TC_ARGB ) + CASE_FORMAT( _32BIT_TC_BGRA ) + CASE_FORMAT( _32BIT_TC_RGBA ) + CASE_FORMAT( _32BIT_TC_MASK ) + + default: + bRet = FALSE; + break; + } + + return bRet; +} + +// ------------------------------------------------------------------ + +void BitmapReadAccess::ImplZeroInitUnusedBits() +{ + const sal_uInt32 nWidth = Width(), nHeight = Height(), nScanSize = GetScanlineSize(); + + if( nWidth && nHeight && nScanSize && GetBuffer() ) + { + DBG_ASSERT( !( nScanSize % 4 ), "BitmapWriteAccess::ZeroInitUnusedBits: Unsupported scanline alignment" ); + + sal_uInt32 nBits; + + switch( GetScanlineFormat() ) + { + case( BMP_FORMAT_1BIT_MSB_PAL ): + nBits = 1; + break; + + case( BMP_FORMAT_4BIT_MSN_PAL ): + nBits = 4; + break; + + case( BMP_FORMAT_8BIT_PAL ): + case( BMP_FORMAT_8BIT_TC_MASK ): + nBits = 8; + break; + + case( BMP_FORMAT_16BIT_TC_MASK ): + nBits = 16; + break; + + case( BMP_FORMAT_24BIT_TC_BGR ): + case( BMP_FORMAT_24BIT_TC_RGB ): + case( BMP_FORMAT_24BIT_TC_MASK ): + nBits = 24; + break; + + case( BMP_FORMAT_32BIT_TC_ABGR ): + case( BMP_FORMAT_32BIT_TC_ARGB ): + case( BMP_FORMAT_32BIT_TC_BGRA ): + case( BMP_FORMAT_32BIT_TC_RGBA ): + case( BMP_FORMAT_32BIT_TC_MASK ): + nBits = 32; + break; + + default: + { + DBG_ERROR( "BitmapWriteAccess::ZeroInitUnusedBits: Unsupported pixel format" ); + nBits = 0; + } + break; + } + + if( ( nBits *= nWidth ) & 0x1f ) + { + sal_uInt32 nMask = 0xffffffff << ( ( nScanSize << 3 ) - nBits ); + BYTE* pLast4Bytes = (BYTE*) GetBuffer() + ( nScanSize - 4 ); + +#ifdef __LITTLEENDIAN + nMask = SWAPLONG( nMask ); +#endif + for( long i = 0; i < nHeight; i++, pLast4Bytes += nScanSize ) + ( *(long*) pLast4Bytes ) &= nMask; + } + } +} + +// ------------------------------------------------------------------ + +void BitmapReadAccess::Flush() +{ + ImplDestroy(); +} + +// ------------------------------------------------------------------ + +void BitmapReadAccess::ReAccess( BOOL bModify ) +{ + const ImpBitmap* pImpBmp = maBitmap.ImplGetImpBitmap(); + + BMP_ASSERT( !mpBuffer, "No ReAccess possible while bitmap is being accessed!" ); + BMP_ASSERT( pImpBmp && ( pImpBmp->ImplGetRefCount() > 1UL ), "Accessed bitmap does not exist anymore!" ); + + if( !mpBuffer && pImpBmp && ( pImpBmp->ImplGetRefCount() > 1UL ) ) + { + mbModify = bModify; + ImplCreate( maBitmap ); + } +} + +// ------------------------------------------------------------------ + +USHORT BitmapReadAccess::GetBestPaletteIndex( const BitmapColor& rBitmapColor ) const +{ + return( HasPalette() ? mpBuffer->maPalette.GetBestIndex( rBitmapColor ) : 0 ); +} + +// --------------------- +// - BitmapWriteAccess - +// --------------------- + +BitmapWriteAccess::~BitmapWriteAccess() +{ +} + +// ------------------------------------------------------------------ + +void BitmapWriteAccess::ImplInitDraw() +{ + if( HasPalette() ) + { + if( !maLineColor.IsIndex() ) + maLineColor = (BYTE) GetBestPaletteIndex( maLineColor ); + + if( !maFillColor.IsIndex() ) + maFillColor = (BYTE) GetBestPaletteIndex( maFillColor ); + } +} + +// ------------------------------------------------------------------ + +void BitmapWriteAccess::CopyScanline( long nY, const BitmapReadAccess& rReadAcc ) +{ + BMP_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" ); + BMP_ASSERT( nY < rReadAcc.Height(), "y-coordinate in source out of range!" ); + BMP_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" ); + + if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) && + ( GetScanlineSize() >= rReadAcc.GetScanlineSize() ) ) + { + HMEMCPY( mpScanBuf[ nY ], rReadAcc.GetScanline( nY ), rReadAcc.GetScanlineSize() ); + } + else + for( long nX = 0L, nWidth = Min( mpBuffer->mnWidth, rReadAcc.Width() ); nX < nWidth; nX++ ) + SetPixel( nY, nX, rReadAcc.GetPixel( nY, nX ) ); +} + +// ------------------------------------------------------------------ + +void BitmapWriteAccess::CopyScanline( long nY, const Scanline aSrcScanline, + ULONG nSrcScanlineFormat, ULONG nSrcScanlineSize ) +{ + const ULONG nFormat = BMP_SCANLINE_FORMAT( nSrcScanlineFormat ); + + BMP_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" ); + BMP_ASSERT( ( HasPalette() && nFormat <= BMP_FORMAT_8BIT_PAL ) || + ( !HasPalette() && nFormat > BMP_FORMAT_8BIT_PAL ), + "No copying possible between palette and non palette scanlines!" ); + + const ULONG nCount = Min( GetScanlineSize(), nSrcScanlineSize ); + + if( nCount ) + { + if( GetScanlineFormat() == BMP_SCANLINE_FORMAT( nSrcScanlineFormat ) ) + HMEMCPY( mpScanBuf[ nY ], aSrcScanline, nCount ); + else + { + BMP_ASSERT( nFormat != BMP_FORMAT_8BIT_TC_MASK && nFormat != BMP_FORMAT_16BIT_TC_MASK && + nFormat != BMP_FORMAT_24BIT_TC_MASK && nFormat != BMP_FORMAT_32BIT_TC_MASK, + "No support for pixel formats with color masks yet!" ); + + FncGetPixel pFncGetPixel; + + switch( nFormat ) + { + case( BMP_FORMAT_1BIT_MSB_PAL ): pFncGetPixel = GetPixelFor_1BIT_MSB_PAL; break; + case( BMP_FORMAT_1BIT_LSB_PAL ): pFncGetPixel = GetPixelFor_1BIT_LSB_PAL; break; + case( BMP_FORMAT_4BIT_MSN_PAL ): pFncGetPixel = GetPixelFor_4BIT_MSN_PAL; break; + case( BMP_FORMAT_4BIT_LSN_PAL ): pFncGetPixel = GetPixelFor_4BIT_LSN_PAL; break; + case( BMP_FORMAT_8BIT_PAL ): pFncGetPixel = GetPixelFor_8BIT_PAL; break; + case( BMP_FORMAT_8BIT_TC_MASK ): pFncGetPixel = GetPixelFor_8BIT_TC_MASK; break; + case( BMP_FORMAT_16BIT_TC_MASK ): pFncGetPixel = GetPixelFor_16BIT_TC_MASK; break; + case( BMP_FORMAT_24BIT_TC_BGR ): pFncGetPixel = GetPixelFor_24BIT_TC_BGR; break; + case( BMP_FORMAT_24BIT_TC_RGB ): pFncGetPixel = GetPixelFor_24BIT_TC_RGB; break; + case( BMP_FORMAT_24BIT_TC_MASK ): pFncGetPixel = GetPixelFor_24BIT_TC_MASK; break; + case( BMP_FORMAT_32BIT_TC_ABGR ): pFncGetPixel = GetPixelFor_32BIT_TC_ABGR; break; + case( BMP_FORMAT_32BIT_TC_ARGB ): pFncGetPixel = GetPixelFor_32BIT_TC_ARGB; break; + case( BMP_FORMAT_32BIT_TC_BGRA ): pFncGetPixel = GetPixelFor_32BIT_TC_BGRA; break; + case( BMP_FORMAT_32BIT_TC_RGBA ): pFncGetPixel = GetPixelFor_32BIT_TC_RGBA; break; + case( BMP_FORMAT_32BIT_TC_MASK ): pFncGetPixel = GetPixelFor_32BIT_TC_MASK; break; + + default: + pFncGetPixel = NULL; + break; + } + + if( pFncGetPixel ) + { + const ColorMask aDummyMask; + + for( long nX = 0L, nWidth = mpBuffer->mnWidth; nX < nWidth; nX++ ) + SetPixel( nY, nX, pFncGetPixel( aSrcScanline, nX, aDummyMask ) ); + } + } + } +} + + +// ------------------------------------------------------------------ + +void BitmapWriteAccess::CopyBuffer( const BitmapReadAccess& rReadAcc ) +{ + BMP_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" ); + + if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) && + ( GetScanlineSize() == rReadAcc.GetScanlineSize() ) ) + { + const long nHeight = Min( mpBuffer->mnHeight, rReadAcc.Height() ); + const ULONG nCount = nHeight * mpBuffer->mnScanlineSize; + + HMEMCPY( mpBuffer->mpBits, rReadAcc.GetBuffer(), nCount ); + } + else + for( long nY = 0L, nHeight = Min( mpBuffer->mnHeight, rReadAcc.Height() ); nY < nHeight; nY++ ) + CopyScanline( nY, rReadAcc ); +} diff --git a/vcl/source/gdi/bmpacc2.cxx b/vcl/source/gdi/bmpacc2.cxx new file mode 100644 index 000000000000..a07f58815a88 --- /dev/null +++ b/vcl/source/gdi/bmpacc2.cxx @@ -0,0 +1,353 @@ +/************************************************************************* + * + * $RCSfile: bmpacc2.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_BMPACC2_CXX + +#ifndef _SV_SALBTYPE_HXX +#include <salbtype.hxx> +#endif +#ifndef _SV_BMPACC_HXX +#include <bmpacc.hxx> +#endif + +// ---------------- +// - BitmapAccess - +// ---------------- + +IMPL_FORMAT_GETPIXEL( _1BIT_MSB_PAL ) +{ + return( pScanline[ nX >> 3 ] & ( 1 << ( 7 - ( nX & 7 ) ) ) ? 1 : 0 ); +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_SETPIXEL( _1BIT_MSB_PAL ) +{ + BYTE& rByte = pScanline[ nX >> 3 ]; + + ( rBitmapColor.GetIndex() & 1 ) ? ( rByte |= 1 << ( 7 - ( nX & 7 ) ) ) : + ( rByte &= ~( 1 << ( 7 - ( nX & 7 ) ) ) ); +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_GETPIXEL( _1BIT_LSB_PAL ) +{ + return( pScanline[ nX >> 3 ] & ( 1 << ( nX & 7 ) ) ? 1 : 0 ); +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_SETPIXEL( _1BIT_LSB_PAL ) +{ + BYTE& rByte = pScanline[ nX >> 3 ]; + + ( rBitmapColor.GetIndex() & 1 ) ? ( rByte |= 1 << ( nX & 7 ) ) : + ( rByte &= ~( 1 << ( nX & 7 ) ) ); +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_GETPIXEL( _4BIT_MSN_PAL ) +{ + return( ( pScanline[ nX >> 1 ] >> ( nX & 1 ? 0 : 4 ) ) & 0x0f ); +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_SETPIXEL( _4BIT_MSN_PAL ) +{ + BYTE& rByte = pScanline[ nX >> 1 ]; + + ( nX & 1 ) ? ( rByte &= 0xf0, rByte |= ( rBitmapColor.GetIndex() & 0x0f ) ) : + ( rByte &= 0x0f, rByte |= ( rBitmapColor.GetIndex() << 4 ) ); +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_GETPIXEL( _4BIT_LSN_PAL ) +{ + return( ( pScanline[ nX >> 1 ] >> ( nX & 1 ? 4 : 0 ) ) & 0x0f ); +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_SETPIXEL( _4BIT_LSN_PAL ) +{ + BYTE& rByte = pScanline[ nX >> 1 ]; + + ( nX & 1 ) ? ( rByte &= 0x0f, rByte |= ( rBitmapColor.GetIndex() << 4 ) ) : + ( rByte &= 0xf0, rByte |= ( rBitmapColor.GetIndex() & 0x0f ) ); +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_GETPIXEL( _8BIT_PAL ) +{ + return pScanline[ nX ]; +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_SETPIXEL( _8BIT_PAL ) +{ + pScanline[ nX ] = rBitmapColor; +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_GETPIXEL( _8BIT_TC_MASK ) +{ + BitmapColor aColor; + rMask.GetColorFor8Bit( aColor, pScanline + nX ); + return aColor; +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_SETPIXEL( _8BIT_TC_MASK ) +{ + rMask.SetColorFor8Bit( rBitmapColor, pScanline + nX ); +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_GETPIXEL( _16BIT_TC_MASK ) +{ + BitmapColor aColor; + rMask.GetColorFor16Bit( aColor, pScanline + ( nX << 1UL ) ); + return aColor; +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_SETPIXEL( _16BIT_TC_MASK ) +{ + rMask.SetColorFor16Bit( rBitmapColor, pScanline + ( nX << 1UL ) ); +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_GETPIXEL( _24BIT_TC_BGR ) +{ + BitmapColor aBitmapColor; + + aBitmapColor.SetBlue( *( pScanline = pScanline + nX * 3 )++ ); + aBitmapColor.SetGreen( *pScanline++ ); + aBitmapColor.SetRed( *pScanline ); + + return aBitmapColor; +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_SETPIXEL( _24BIT_TC_BGR ) +{ + *( pScanline = pScanline + nX * 3 )++ = rBitmapColor.GetBlue(); + *pScanline++ = rBitmapColor.GetGreen(); + *pScanline = rBitmapColor.GetRed(); +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_GETPIXEL( _24BIT_TC_RGB ) +{ + BitmapColor aBitmapColor; + + aBitmapColor.SetRed( *( pScanline = pScanline + nX * 3 )++ ); + aBitmapColor.SetGreen( *pScanline++ ); + aBitmapColor.SetBlue( *pScanline ); + + return aBitmapColor; +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_SETPIXEL( _24BIT_TC_RGB ) +{ + *( pScanline = pScanline + nX * 3 )++ = rBitmapColor.GetRed(); + *pScanline++ = rBitmapColor.GetGreen(); + *pScanline = rBitmapColor.GetBlue(); +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_GETPIXEL( _24BIT_TC_MASK ) +{ + BitmapColor aColor; + rMask.GetColorFor24Bit( aColor, pScanline + nX * 3L ); + return aColor; +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_SETPIXEL( _24BIT_TC_MASK ) +{ + rMask.SetColorFor24Bit( rBitmapColor, pScanline + nX * 3L ); +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_GETPIXEL( _32BIT_TC_ABGR ) +{ + BitmapColor aBitmapColor; + + aBitmapColor.SetBlue( *( pScanline = pScanline + ( nX << 2 ) + 1 )++ ); + aBitmapColor.SetGreen( *pScanline++ ); + aBitmapColor.SetRed( *pScanline ); + + return aBitmapColor; +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_SETPIXEL( _32BIT_TC_ABGR ) +{ + *( pScanline = pScanline + ( nX << 2 ) )++ = 0; + *pScanline++ = rBitmapColor.GetBlue(); + *pScanline++ = rBitmapColor.GetGreen(); + *pScanline = rBitmapColor.GetRed(); +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_GETPIXEL( _32BIT_TC_ARGB ) +{ + BitmapColor aBitmapColor; + + aBitmapColor.SetRed( *( pScanline = pScanline + ( nX << 2 ) + 1 )++ ); + aBitmapColor.SetGreen( *pScanline++ ); + aBitmapColor.SetBlue( *pScanline ); + + return aBitmapColor; +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_SETPIXEL( _32BIT_TC_ARGB ) +{ + *( pScanline = pScanline + ( nX << 2 ) )++ = 0; + *pScanline++ = rBitmapColor.GetRed(); + *pScanline++ = rBitmapColor.GetGreen(); + *pScanline = rBitmapColor.GetBlue(); +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_GETPIXEL( _32BIT_TC_BGRA ) +{ + BitmapColor aBitmapColor; + + aBitmapColor.SetBlue( *( pScanline = pScanline + ( nX << 2 ) )++ ); + aBitmapColor.SetGreen( *pScanline++ ); + aBitmapColor.SetRed( *pScanline ); + + return aBitmapColor; +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_SETPIXEL( _32BIT_TC_BGRA ) +{ + *( pScanline = pScanline + ( nX << 2 ) )++ = rBitmapColor.GetBlue(); + *pScanline++ = rBitmapColor.GetGreen(); + *pScanline++ = rBitmapColor.GetRed(); + *pScanline = 0; +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_GETPIXEL( _32BIT_TC_RGBA ) +{ + BitmapColor aBitmapColor; + + aBitmapColor.SetRed( *( pScanline = pScanline + ( nX << 2 ) )++ ); + aBitmapColor.SetGreen( *pScanline++ ); + aBitmapColor.SetBlue( *pScanline ); + + return aBitmapColor; +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_SETPIXEL( _32BIT_TC_RGBA ) +{ + *( pScanline = pScanline + ( nX << 2 ) )++ = rBitmapColor.GetRed(); + *pScanline++ = rBitmapColor.GetGreen(); + *pScanline++ = rBitmapColor.GetBlue(); + *pScanline = 0; +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_GETPIXEL( _32BIT_TC_MASK ) +{ + BitmapColor aColor; + rMask.GetColorFor32Bit( aColor, pScanline + ( nX << 2UL ) ); + return aColor; +} + +// ------------------------------------------------------------------ + +IMPL_FORMAT_SETPIXEL( _32BIT_TC_MASK ) +{ + rMask.SetColorFor32Bit( rBitmapColor, pScanline + ( nX << 2UL ) ); +} diff --git a/vcl/source/gdi/bmpacc3.cxx b/vcl/source/gdi/bmpacc3.cxx new file mode 100644 index 000000000000..c26de8c7ecfa --- /dev/null +++ b/vcl/source/gdi/bmpacc3.cxx @@ -0,0 +1,351 @@ +/************************************************************************* + * + * $RCSfile: bmpacc3.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_BMPACC_CXX + +#ifndef _SV_SALBTYPE_HXX +#include <salbtype.hxx> +#endif +#ifndef _SV_BITMAP_HXX +#include <bitmap.hxx> +#endif +#ifndef _SV_POLY_HXX +#include <poly.hxx> +#endif +#ifndef _SV_REGION_HXX +#include <region.hxx> +#endif +#ifndef _SV_BMPACC_HXX +#include <bmpacc.hxx> +#endif + +// --------------------- +// - BitmapWriteAccess - +// --------------------- + +void BitmapWriteAccess::Erase( const Color& rColor ) +{ + const BitmapColor aOldFillColor( maFillColor ); + const Point aPoint; + const Rectangle aRect( aPoint, maBitmap.GetSizePixel() ); + + SetFillColor( rColor ); + FillRect( aRect ); + maFillColor = aOldFillColor; +} + +// ------------------------------------------------------------------ + +void BitmapWriteAccess::DrawLine( const Point& rStart, const Point& rEnd ) +{ + long nX; + long nY; + + ImplInitDraw(); + + if ( rStart.X() == rEnd.X() ) + { + // vertikale Line + const long nEndY = rEnd.Y(); + + nX = rStart.X(); + nY = rStart.Y(); + + if ( nEndY > nY ) + { + for (; nY <= nEndY; nY++ ) + SetPixel( nY, nX, maLineColor ); + } + else + { + for (; nY >= nEndY; nY-- ) + SetPixel( nY, nX, maLineColor ); + } + } + else if ( rStart.Y() == rEnd.Y() ) + { + // horizontale Line + const long nEndX = rEnd.X(); + + nX = rStart.X(); + nY = rStart.Y(); + + if ( nEndX > nX ) + { + for (; nX <= nEndX; nX++ ) + SetPixel( nY, nX, maLineColor ); + } + else + { + for (; nX >= nEndX; nX-- ) + SetPixel( nY, nX, maLineColor ); + } + } + else + { + const long nDX = labs( rEnd.X() - rStart.X() ); + const long nDY = labs( rEnd.Y() - rStart.Y() ); + long nX1; + long nY1; + long nX2; + long nY2; + + if ( nDX >= nDY ) + { + if ( rStart.X() < rEnd.X() ) + { + nX1 = rStart.X(); + nY1 = rStart.Y(); + nX2 = rEnd.X(); + nY2 = rEnd.Y(); + } + else + { + nX1 = rEnd.X(); + nY1 = rEnd.Y(); + nX2 = rStart.X(); + nY2 = rStart.Y(); + } + + const long nDYX = ( nDY - nDX ) << 1; + const long nDY2 = nDY << 1; + long nD = nDY2 - nDX; + BOOL bPos = nY1 < nY2; + + for ( nX = nX1, nY = nY1; nX <= nX2; nX++ ) + { + SetPixel( nY, nX, maLineColor ); + + if ( nD < 0 ) + nD += nDY2; + else + { + nD += nDYX; + + if ( bPos ) + nY++; + else + nY--; + } + } + } + else + { + if ( rStart.Y() < rEnd.Y() ) + { + nX1 = rStart.X(); + nY1 = rStart.Y(); + nX2 = rEnd.X(); + nY2 = rEnd.Y(); + } + else + { + nX1 = rEnd.X(); + nY1 = rEnd.Y(); + nX2 = rStart.X(); + nY2 = rStart.Y(); + } + + const long nDYX = ( nDX - nDY ) << 1; + const long nDY2 = nDX << 1; + long nD = nDY2 - nDY; + BOOL bPos = nX1 < nX2; + + for ( nX = nX1, nY = nY1; nY <= nY2; nY++ ) + { + SetPixel( nY, nX, maLineColor ); + + if ( nD < 0 ) + nD += nDY2; + else + { + nD += nDYX; + + if ( bPos ) + nX++; + else + nX--; + } + } + } + } +} + +// ------------------------------------------------------------------ + +void BitmapWriteAccess::DrawRect( const Rectangle& rRect ) +{ + ImplInitDraw(); + FillRect( rRect ); + DrawLine( rRect.TopLeft(), rRect.TopRight() ); + DrawLine( rRect.TopRight(), rRect.BottomRight() ); + DrawLine( rRect.BottomRight(), rRect.BottomLeft() ); + DrawLine( rRect.BottomLeft(), rRect.TopLeft() ); +} + +// ------------------------------------------------------------------ + +void BitmapWriteAccess::FillRect( const Rectangle& rRect ) +{ + Point aPoint; + Rectangle aRect( aPoint, maBitmap.GetSizePixel() ); + + aRect.Intersection( rRect ); + + if( !aRect.IsEmpty() ) + { + const long nStartX = rRect.TopLeft().X(); + const long nStartY = rRect.TopLeft().Y(); + const long nEndX = rRect.BottomRight().X(); + const long nEndY = rRect.BottomRight().Y(); + + ImplInitDraw(); + + for( long nY = nStartY; nY <= nEndY; nY++ ) + for( long nX = nStartX; nX <= nEndX; nX++ ) + SetPixel( nY, nX, maFillColor ); + } +} + +// ------------------------------------------------------------------ + +void BitmapWriteAccess::DrawPolygon( const Polygon& rPoly ) +{ + const USHORT nSize = rPoly.GetSize(); + + if( nSize ) + { + Region aRegion( rPoly ); + Rectangle aRect; + + aRegion.Intersect( Rectangle( Point(), Size( Width(), Height() ) ) ); + + if( !aRegion.IsEmpty() ) + { + RegionHandle aRegHandle( aRegion.BeginEnumRects() ); + + ImplInitDraw(); + + while( aRegion.GetNextEnumRect( aRegHandle, aRect ) ) + for( long nY = aRect.Top(), nEndY = aRect.Bottom(); nY <= nEndY; nY++ ) + for( long nX = aRect.Left(), nEndX = aRect.Right(); nX <= nEndX; nX++ ) + SetPixel( nY, nX, maFillColor ); + + aRegion.EndEnumRects( aRegHandle ); + } + + if( maLineColor != maFillColor ) + { + for( USHORT i = 0, nSize1 = nSize - 1; i < nSize1; i++ ) + DrawLine( rPoly[ i ], rPoly[ i + 1 ] ); + + if( rPoly[ nSize - 1 ] != rPoly[ 0 ] ) + DrawLine( rPoly[ nSize - 1 ], rPoly[ 0 ] ); + } + } +} + +// ------------------------------------------------------------------ + +void BitmapWriteAccess::DrawPolyPolygon( const PolyPolygon& rPolyPoly ) +{ + const USHORT nCount = rPolyPoly.Count(); + + if( nCount ) + { + Region aRegion( rPolyPoly ); + Rectangle aRect; + + aRegion.Intersect( Rectangle( Point(), Size( Width(), Height() ) ) ); + + if( !aRegion.IsEmpty() ) + { + RegionHandle aRegHandle( aRegion.BeginEnumRects() ); + + ImplInitDraw(); + + while( aRegion.GetNextEnumRect( aRegHandle, aRect ) ) + for( long nY = aRect.Top(), nEndY = aRect.Bottom(); nY <= nEndY; nY++ ) + for( long nX = aRect.Left(), nEndX = aRect.Right(); nX <= nEndX; nX++ ) + SetPixel( nY, nX, maFillColor ); + + aRegion.EndEnumRects( aRegHandle ); + } + + if( maLineColor != maFillColor ) + { + for( USHORT n = 0; n < nCount; ) + { + const Polygon& rPoly = rPolyPoly[ n++ ]; + const USHORT nSize = rPoly.GetSize(); + + if( nSize ) + { + for( USHORT i = 0, nSize1 = nSize - 1; i < nSize1; i++ ) + DrawLine( rPoly[ i ], rPoly[ i + 1 ] ); + + if( rPoly[ nSize - 1 ] != rPoly[ 0 ] ) + DrawLine( rPoly[ nSize - 1 ], rPoly[ 0 ] ); + } + } + } + } +} diff --git a/vcl/source/gdi/cvtgrf.cxx b/vcl/source/gdi/cvtgrf.cxx new file mode 100644 index 000000000000..1005cf3396d5 --- /dev/null +++ b/vcl/source/gdi/cvtgrf.cxx @@ -0,0 +1,232 @@ +/************************************************************************* + * + * $RCSfile: cvtgrf.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_CVTGRF_CXX + +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#ifndef _SV_METAACT_HXX +#include <metaact.hxx> +#endif +#ifndef _SV_SALINST_HXX +#include <salinst.hxx> +#endif +#ifndef _SV_SVDATA_HXX +#include <svdata.hxx> +#endif +#ifndef _SV_CVTGRF_HXX +#include <cvtgrf.hxx> +#endif + +// -------------- +// - Callback - +// -------------- + +#ifndef REMOTE_APPSERVER + +ULONG ImplFilterCallback( void* pInst, + ULONG nInFormat, void* pInBuffer, ULONG nInBufSize, + ULONG nOutFormat, void** ppOutBuffer ) +{ + return( ( (GraphicConverter*) pInst )->ImplConvert( nInFormat, + pInBuffer, nInBufSize, + ppOutBuffer, nOutFormat ) ); +} + +#endif + +// -------------------- +// - GraphicConverter - +// -------------------- + +GraphicConverter::GraphicConverter() : + mpConvertData( NULL ) +{ +#ifndef REMOTE_APPSERVER + SetFilterCallback( ImplFilterCallback, this ); +#endif +} + +// ------------------------------------------------------------------------ + +GraphicConverter::~GraphicConverter() +{ +} + +// ------------------------------------------------------------------------ + +ULONG GraphicConverter::ImplConvert( ULONG nInFormat, void* pInBuffer, ULONG nInBufSize, + void** ppOutBuffer, ULONG nOutFormat ) +{ + ULONG nRetBufSize = 0UL; + + if( ( nInFormat != nOutFormat ) && pInBuffer ) + { + if( ( nInFormat == CVT_SVM ) || ( nInFormat == CVT_BMP ) ) + { + SvMemoryStream aIStm; + Graphic aGraphic; + + aIStm.SetBuffer( (char*) pInBuffer, nInBufSize, FALSE, nInBufSize ); + aIStm >> aGraphic; + + if( !aIStm.GetError() ) + { + SvMemoryStream aOStm( 64535, 64535 ); + + mpConvertData = new ConvertData( aGraphic, aOStm, nOutFormat ); + + if( maFilterHdl.IsSet() && maFilterHdl.Call( mpConvertData ) ) + { + nRetBufSize = aOStm.Seek( STREAM_SEEK_TO_END ); + *ppOutBuffer = (void*) aOStm.GetData(); + aOStm.ObjectOwnsMemory( FALSE ); + } + + delete mpConvertData; + mpConvertData = NULL; + } + } + else if( ( nOutFormat == CVT_SVM ) || ( nOutFormat == CVT_BMP ) ) + { + SvMemoryStream aIStm; + + aIStm.SetBuffer( (char*) pInBuffer, nInBufSize, FALSE, nInBufSize ); + mpConvertData = new ConvertData( Graphic(), aIStm, nInFormat ); + + if( maFilterHdl.IsSet() && maFilterHdl.Call( mpConvertData ) ) + { + SvMemoryStream aOStm( 645535, 64535 ); + Graphic& rGraphic = mpConvertData->maGraphic; + + if( ( rGraphic.GetType() == GRAPHIC_BITMAP ) && ( CVT_SVM == nOutFormat ) ) + { + GDIMetaFile aMtf; + + aMtf.SetPrefSize( rGraphic.GetPrefSize() ); + aMtf.SetPrefMapMode( rGraphic.GetPrefMapMode() ); + aMtf.AddAction( new MetaBmpExScaleAction( Point(), aMtf.GetPrefSize(), rGraphic.GetBitmapEx() ) ); + rGraphic = aMtf; + } + else if( ( rGraphic.GetType() == GRAPHIC_GDIMETAFILE ) && ( CVT_BMP == nOutFormat ) ) + rGraphic = rGraphic.GetBitmapEx(); + + aOStm << rGraphic; + + if( !aOStm.GetError() ) + { + nRetBufSize = aOStm.Seek( STREAM_SEEK_TO_END ); + *ppOutBuffer = (void*) aOStm.GetData(); + aOStm.ObjectOwnsMemory( FALSE ); + } + } + + delete mpConvertData; + mpConvertData = NULL; + } + } + + return nRetBufSize; +} + +// ------------------------------------------------------------------------ + +ULONG GraphicConverter::Import( SvStream& rIStm, Graphic& rGraphic, ULONG nFormat ) +{ + GraphicConverter* pCvt = ImplGetSVData()->maGDIData.mpGrfConverter; + ULONG nRet = ERRCODE_IO_GENERAL; + + if( pCvt && pCvt->GetFilterHdl().IsSet() ) + { + ConvertData aData( rGraphic, rIStm, nFormat ); + + if( pCvt->GetFilterHdl().Call( &aData ) ) + { + rGraphic = aData.maGraphic; + nRet = ERRCODE_NONE; + } + else if( rIStm.GetError() ) + nRet = rIStm.GetError(); + } + + return nRet; +} + +// ------------------------------------------------------------------------ + +ULONG GraphicConverter::Export( SvStream& rOStm, const Graphic& rGraphic, ULONG nFormat ) +{ + GraphicConverter* pCvt = ImplGetSVData()->maGDIData.mpGrfConverter; + ULONG nRet = ERRCODE_IO_GENERAL; + + if( pCvt && pCvt->GetFilterHdl().IsSet() ) + { + ConvertData aData( rGraphic, rOStm, nFormat ); + + if( pCvt->GetFilterHdl().Call( &aData ) ) + nRet = ERRCODE_NONE; + else if( rOStm.GetError() ) + nRet = rOStm.GetError(); + } + + return nRet; +} diff --git a/vcl/source/gdi/cvtsvm.cxx b/vcl/source/gdi/cvtsvm.cxx new file mode 100644 index 000000000000..f2ac9be53d5d --- /dev/null +++ b/vcl/source/gdi/cvtsvm.cxx @@ -0,0 +1,2106 @@ +/************************************************************************* + * + * $RCSfile: cvtsvm.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_CVTSVM_CXX +#define ENABLE_BYTESTRING_STREAM_OPERATORS + +#include <string.h> + +#ifndef _STACK_HXX //autogen +#include <tools/stack.hxx> +#endif +#ifndef _DEBUG_HXX //autogen +#include <tools/debug.hxx> +#endif +#ifndef _STREAM_HXX //autogen +#include <tools/stream.hxx> +#endif +#ifndef _SV_VIRDEV_HXX +#include <virdev.hxx> +#endif +#ifndef _SV_GRAPH_HXX +#include <graph.hxx> +#endif +#ifndef _SV_LINEINFO_HXX +#include <lineinfo.hxx> +#endif +#ifndef _SV_SALBTYPE_HXX +#include <salbtype.hxx> +#endif +#include <cvtsvm.hxx> + +// ----------- +// - Defines - +// ----------- + +#define CVTSVM_WRITE_SUBACTIONCOUNT 1 + +// ----------- +// - Inlines - +// ----------- + +void ImplReadRect( SvStream& rIStm, Rectangle& rRect ) +{ + Point aTL; + Point aBR; + + rIStm >> aTL; + rIStm >> aBR; + + rRect = Rectangle( aTL, aBR ); +} + +// ------------------------------------------------------------------------ + +void ImplWriteRect( SvStream& rOStm, const Rectangle& rRect ) +{ + rOStm << rRect.TopLeft(); + rOStm << rRect.BottomRight(); +} + +// ------------------------------------------------------------------------ + +void ImplReadPoly( SvStream& rIStm, Polygon& rPoly ) +{ + INT32 nSize; + + rIStm >> nSize; + rPoly = Polygon( (USHORT) nSize ); + + for( USHORT i = 0; i < (USHORT) nSize; i++ ) + rIStm >> rPoly[ i ]; +} + +// ------------------------------------------------------------------------ + +void ImplWritePoly( SvStream& rOStm, const Polygon& rPoly ) +{ + INT32 nSize = rPoly.GetSize(); + + rOStm << nSize; + + for( INT32 i = 0; i < nSize; i++ ) + rOStm << rPoly[ (USHORT) i ]; +} + +// ------------------------------------------------------------------------ + +void ImplReadPolyPoly( SvStream& rIStm, PolyPolygon& rPolyPoly ) +{ + Polygon aPoly; + INT32 nPolyCount; + + rIStm >> nPolyCount; + + for( USHORT i = 0; i < (USHORT) nPolyCount; i++ ) + { + ImplReadPoly( rIStm, aPoly ); + rPolyPoly.Insert( aPoly ); + } +} + +// ------------------------------------------------------------------------ + +void ImplWritePolyPolyAction( SvStream& rOStm, const PolyPolygon& rPolyPoly ) +{ + const USHORT nPoly = rPolyPoly.Count(); + USHORT nPoints = 0; + USHORT n; + + for( n = 0; n < nPoly; n++ ) + nPoints += rPolyPoly[ n ].GetSize(); + + rOStm << (INT16) GDI_POLYPOLYGON_ACTION; + rOStm << (INT32) ( 8 + ( nPoly << 2 ) + ( nPoints << 3 ) ); + rOStm << (INT32) nPoly; + + for( n = 0; n < nPoly; n++ ) + { + const Polygon& rPoly = rPolyPoly[ n ]; + const USHORT nSize = rPoly.GetSize(); + + rOStm << (INT32) nSize; + + for( USHORT j = 0; j < nSize; j++ ) + rOStm << rPoly[ j ]; + } +} + +// ------------------------------------------------------------------------ + +void ImplReadColor( SvStream& rIStm, Color& rColor ) +{ + INT16 nVal; + + rIStm >> nVal; rColor.SetRed( (USHORT) nVal >> 8 ); + rIStm >> nVal; rColor.SetGreen( (USHORT) nVal >> 8 ); + rIStm >> nVal; rColor.SetBlue( (USHORT) nVal >> 8 ); +} + +// ------------------------------------------------------------------------ + +void ImplWriteColor( SvStream& rOStm, const Color& rColor ) +{ + INT16 nVal; + + nVal = ( (INT16) rColor.GetRed() << 8 ) | rColor.GetRed(); + rOStm << nVal; + + nVal = ( (INT16) rColor.GetGreen() << 8 ) | rColor.GetGreen(); + rOStm << nVal; + + nVal = ( (INT16) rColor.GetBlue() << 8 ) | rColor.GetBlue(); + rOStm << nVal; +} + +// ------------------------------------------------------------------------ + +void ImplReadMapMode( SvStream& rIStm, MapMode& rMapMode ) +{ + Point aOrg; + INT32 nXNum; + INT32 nXDenom; + INT32 nYNum; + INT32 nYDenom; + INT16 nUnit; + + rIStm >> nUnit >> aOrg >> nXNum >> nXDenom >> nYNum >> nYDenom; + rMapMode = MapMode( (MapUnit) nUnit, aOrg, Fraction( nXNum, nXDenom ), Fraction( nYNum, nYDenom ) ); +} + +// ------------------------------------------------------------------------ + +void ImplWriteMapMode( SvStream& rOStm, const MapMode& rMapMode ) +{ + rOStm << (INT16) rMapMode.GetMapUnit(); + rOStm << rMapMode.GetOrigin(); + rOStm << (INT32) rMapMode.GetScaleX().GetNumerator(); + rOStm << (INT32) rMapMode.GetScaleX().GetDenominator(); + rOStm << (INT32) rMapMode.GetScaleY().GetNumerator(); + rOStm << (INT32) rMapMode.GetScaleY().GetDenominator(); +} + +// ------------------------------------------------------------------------ + +void ImplWritePushAction( SvStream& rOStm ) +{ + rOStm << (INT16) GDI_PUSH_ACTION; + rOStm << (INT32) 4; +} + +// ------------------------------------------------------------------------ + +void ImplWritePopAction( SvStream& rOStm ) +{ + rOStm << (INT16) GDI_POP_ACTION; + rOStm << (INT32) 4; +} + +// ------------------------------------------------------------------------ + +void ImplWriteLineColor( SvStream& rOStm, const Color& rColor, INT16 nStyle, INT32 nWidth = 0L ) +{ + if( rColor.GetTransparency() > 127 ) + nStyle = 0; + + rOStm << (INT16) GDI_PEN_ACTION; + rOStm << (INT32) 16; + ImplWriteColor( rOStm, rColor ); + rOStm << nWidth; + rOStm << nStyle; +} + +// ------------------------------------------------------------------------ + +void ImplWriteFillColor( SvStream& rOStm, const Color& rColor, INT16 nStyle ) +{ + rOStm << (INT16) GDI_FILLBRUSH_ACTION; + rOStm << (INT32) 20; + ImplWriteColor( rOStm, rColor ); + + if( rColor.GetTransparency() > 127 ) + nStyle = 0; + + if( nStyle > 1 ) + { + ImplWriteColor( rOStm, COL_WHITE ); + rOStm << nStyle; + rOStm << (INT16) 1; + } + else + { + ImplWriteColor( rOStm, COL_BLACK ); + rOStm << nStyle; + rOStm << (INT16) 0; + } +} + +// ------------------------------------------------------------------------ + +void ImplWriteFont( SvStream& rOStm, const Font& rFont, + rtl_TextEncoding& rActualCharSet ) +{ + char aName[32]; + short nWeight; + + ByteString aByteName( rFont.GetName(), rOStm.GetStreamCharSet() ); + strncpy( aName, aByteName.GetBuffer(), 32 ); + + switch ( rFont.GetWeight() ) + { + case WEIGHT_THIN: + case WEIGHT_ULTRALIGHT: + case WEIGHT_LIGHT: + nWeight = 1; + break; + + case WEIGHT_NORMAL: + case WEIGHT_MEDIUM: + nWeight = 2; + break; + + case WEIGHT_BOLD: + case WEIGHT_ULTRABOLD: + case WEIGHT_BLACK: + nWeight = 3; + break; + + default: + nWeight = 0; + break; + } + + rOStm << (INT16) GDI_FONT_ACTION; + rOStm << (INT32) 78; + + rActualCharSet = GetStoreCharSet( rFont.GetCharSet(), rOStm.GetVersion() ); + ImplWriteColor( rOStm, rFont.GetColor() ); + ImplWriteColor( rOStm, rFont.GetFillColor() ); + rOStm.Write( aName, 32 ); + rOStm << rFont.GetSize(); + rOStm << (INT16) 0; // no character orientation anymore + rOStm << (INT16) rFont.GetOrientation(); + rOStm << (INT16) rActualCharSet; + rOStm << (INT16) rFont.GetFamily(); + rOStm << (INT16) rFont.GetPitch(); + rOStm << (INT16) rFont.GetAlign(); + rOStm << (INT16) nWeight; + rOStm << (INT16) rFont.GetUnderline(); + rOStm << (INT16) rFont.GetStrikeout(); + rOStm << (BOOL) ( rFont.GetItalic() != ITALIC_NONE ); + rOStm << rFont.IsOutline(); + rOStm << rFont.IsShadow(); + rOStm << rFont.IsTransparent(); + if ( rActualCharSet == RTL_TEXTENCODING_DONTKNOW ) + rActualCharSet = gsl_getSystemTextEncoding(); +} + +// ------------------------------------------------------------------------ + +void ImplWriteRasterOpAction( SvStream& rOStm, INT16 nRasterOp ) +{ + rOStm << (INT16) GDI_RASTEROP_ACTION << (INT32) 6 << nRasterOp; +} + +// ------------------------------------------------------------------------ + +void ImplSkipActions( SvStream& rIStm, ULONG nSkipCount ) +{ + INT32 nActionSize; + INT16 nType; + + for( ULONG i = 0UL; i < nSkipCount; i++ ) + { + rIStm >> nType >> nActionSize; + rIStm.SeekRel( nActionSize - 4L ); + } +} + +// ---------------- +// - SVMConverter - +// ---------------- + +SVMConverter::SVMConverter( SvStream& rStm, GDIMetaFile& rMtf, ULONG nConvertMode ) +{ + if( !rStm.GetError() ) + { + if( CONVERT_FROM_SVM1 == nConvertMode ) + ImplConvertFromSVM1( rStm, rMtf ); + else if( CONVERT_TO_SVM1 == nConvertMode ) + ImplConvertToSVM1( rStm, rMtf ); + } +} + +// ------------------------------------------------------------------------ + +void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf ) +{ + LineInfo aLineInfo( LINE_NONE, 0 ); + Stack aLIStack; + ULONG nPos = rIStm.Tell(); + const USHORT nOldFormat = rIStm.GetNumberFormatInt(); + rtl_TextEncoding eActualCharSet = gsl_getSystemTextEncoding(); + BOOL bFatLine = FALSE; + + rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + + char aCode[ 5 ]; + MapMode aMapMode; + Size aPrefSz; + INT32 nActions; + INT16 nSize; + INT16 nVersion; + + // Header lesen + rIStm.Read( (char*) &aCode, sizeof( aCode ) ); // Kennung + rIStm >> nSize; // Size + rIStm >> nVersion; // Version + rIStm >> aPrefSz; // PrefSize + ImplReadMapMode( rIStm, aMapMode ); // MapMode + rIStm >> nActions; // Action count + + // Header-Kennung und Versionsnummer pruefen + if( ( memcmp( aCode, "SVGDI", sizeof( aCode ) ) != 0 ) || ( nVersion != 200 ) ) + { + rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR ); + rIStm.SetNumberFormatInt( nOldFormat ); + rIStm.Seek( nPos ); + } + else + { + Polygon aPoly; + Rectangle aRect; + Point aPt, aPt1; + Size aSz; + Color aColor; + INT32 nTmp, nTmp1, nActionSize; + INT16 nType; + + rMtf.SetPrefSize( aPrefSz ); + rMtf.SetPrefMapMode( aMapMode ); + + for( INT32 i = 0L; i < nActions; i++ ) + { + rIStm >> nType; + rIStm >> nActionSize; + + DBG_ASSERT( ( nType <= 33 ) || ( nType >= 1024 ), "Unknown GDIMetaAction while converting!" ); + + switch( nType ) + { + case( GDI_PIXEL_ACTION ): + { + rIStm >> aPt; + ImplReadColor( rIStm, aColor ); + rMtf.AddAction( new MetaPixelAction( aPt, aColor ) ); + } + break; + + case( GDI_POINT_ACTION ): + { + rIStm >> aPt; + rMtf.AddAction( new MetaPointAction( aPt ) ); + } + break; + + case( GDI_LINE_ACTION ): + { + rIStm >> aPt >> aPt1; + rMtf.AddAction( new MetaLineAction( aPt, aPt1, aLineInfo ) ); + } + break; + + case( GDI_RECT_ACTION ): + { + ImplReadRect( rIStm, aRect ); + rIStm >> nTmp >> nTmp1; + + if( nTmp || nTmp1 ) + rMtf.AddAction( new MetaRoundRectAction( aRect, nTmp, nTmp1 ) ); + else + { + rMtf.AddAction( new MetaRectAction( aRect ) ); + + if( bFatLine ) + rMtf.AddAction( new MetaPolyLineAction( aRect, aLineInfo ) ); + } + } + break; + + case( GDI_ELLIPSE_ACTION ): + { + ImplReadRect( rIStm, aRect ); + + if( bFatLine ) + { + const Polygon aPoly( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 ); + + rMtf.AddAction( new MetaPushAction( PUSH_LINECOLOR ) ); + rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, FALSE ) ); + rMtf.AddAction( new MetaPolygonAction( aPoly ) ); + rMtf.AddAction( new MetaPopAction() ); + rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) ); + } + else + rMtf.AddAction( new MetaEllipseAction( aRect ) ); + } + break; + + case( GDI_ARC_ACTION ): + { + ImplReadRect( rIStm, aRect ); + rIStm >> aPt >> aPt1; + + if( bFatLine ) + { + const Polygon aPoly( aRect, aPt, aPt1, POLY_ARC ); + + rMtf.AddAction( new MetaPushAction( PUSH_LINECOLOR ) ); + rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, FALSE ) ); + rMtf.AddAction( new MetaPolygonAction( aPoly ) ); + rMtf.AddAction( new MetaPopAction() ); + rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) ); + } + else + rMtf.AddAction( new MetaArcAction( aRect, aPt, aPt1 ) ); + } + break; + + case( GDI_PIE_ACTION ): + { + ImplReadRect( rIStm, aRect ); + rIStm >> aPt >> aPt1; + + if( bFatLine ) + { + const Polygon aPoly( aRect, aPt, aPt1, POLY_PIE ); + + rMtf.AddAction( new MetaPushAction( PUSH_LINECOLOR ) ); + rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, FALSE ) ); + rMtf.AddAction( new MetaPolygonAction( aPoly ) ); + rMtf.AddAction( new MetaPopAction() ); + rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) ); + } + else + rMtf.AddAction( new MetaPieAction( aRect, aPt, aPt1 ) ); + } + break; + + case( GDI_INVERTRECT_ACTION ): + case( GDI_HIGHLIGHTRECT_ACTION ): + { + ImplReadRect( rIStm, aRect ); + rMtf.AddAction( new MetaPushAction( PUSH_RASTEROP ) ); + rMtf.AddAction( new MetaRasterOpAction( ROP_INVERT ) ); + rMtf.AddAction( new MetaRectAction( aRect ) ); + rMtf.AddAction( new MetaPopAction() ); + } + break; + + case( GDI_POLYLINE_ACTION ): + { + ImplReadPoly( rIStm, aPoly ); + + if( bFatLine ) + rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) ); + else + rMtf.AddAction( new MetaPolyLineAction( aPoly ) ); + } + break; + + case( GDI_POLYGON_ACTION ): + { + ImplReadPoly( rIStm, aPoly ); + + if( bFatLine ) + { + rMtf.AddAction( new MetaPushAction( PUSH_LINECOLOR ) ); + rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, FALSE ) ); + rMtf.AddAction( new MetaPolygonAction( aPoly ) ); + rMtf.AddAction( new MetaPopAction() ); + rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) ); + } + else + rMtf.AddAction( new MetaPolygonAction( aPoly ) ); + } + break; + + case( GDI_POLYPOLYGON_ACTION ): + { + PolyPolygon aPolyPoly; + + ImplReadPolyPoly( rIStm, aPolyPoly ); + + if( bFatLine ) + { + rMtf.AddAction( new MetaPushAction( PUSH_LINECOLOR ) ); + rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, FALSE ) ); + rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) ); + rMtf.AddAction( new MetaPopAction() ); + + for( USHORT nPoly = 0, nCount = aPolyPoly.Count(); nPoly < nCount; nPoly++ ) + rMtf.AddAction( new MetaPolyLineAction( aPolyPoly[ nPoly ], aLineInfo ) ); + } + else + rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) ); + } + break; + + case( GDI_FONT_ACTION ): + { + Font aFont; + char aName[ 32 ]; + INT32 nWidth, nHeight; + INT16 nCharSet, nFamily, nPitch, nAlign, nWeight, nUnderline, nStrikeout; + INT16 nCharOrient, nLineOrient; + BOOL bItalic, bOutline, bShadow, bTransparent; + + ImplReadColor( rIStm, aColor ); aFont.SetColor( aColor ); + ImplReadColor( rIStm, aColor ); aFont.SetFillColor( aColor ); + rIStm.Read( aName, 32 ); + aFont.SetName( UniString( aName, rIStm.GetStreamCharSet() ) ); + rIStm >> nWidth >> nHeight; + rIStm >> nCharOrient >> nLineOrient; + rIStm >> nCharSet >> nFamily >> nPitch >> nAlign >> nWeight >> nUnderline >> nStrikeout; + rIStm >> bItalic >> bOutline >> bShadow >> bTransparent; + + aFont.SetSize( Size( nWidth, nHeight ) ); + aFont.SetCharSet( (CharSet) nCharSet ); + aFont.SetFamily( (FontFamily) nFamily ); + aFont.SetPitch( (FontPitch) nPitch ); + aFont.SetAlign( (FontAlign) nAlign ); + aFont.SetWeight( ( nWeight == 1 ) ? WEIGHT_LIGHT : ( nWeight == 2 ) ? WEIGHT_NORMAL : + ( nWeight == 3 ) ? WEIGHT_BOLD : WEIGHT_DONTKNOW ); + aFont.SetUnderline( (FontUnderline) nUnderline ); + aFont.SetStrikeout( (FontStrikeout) nStrikeout ); + aFont.SetItalic( bItalic ? ITALIC_NORMAL : ITALIC_NONE ); + aFont.SetOutline( bOutline ); + aFont.SetShadow( bShadow ); + aFont.SetOrientation( nLineOrient ); + aFont.SetTransparent( bTransparent ); + + eActualCharSet = aFont.GetCharSet(); + if ( eActualCharSet == RTL_TEXTENCODING_DONTKNOW ) + eActualCharSet = gsl_getSystemTextEncoding(); + rMtf.AddAction( new MetaFontAction( aFont ) ); + } + break; + + case( GDI_TEXT_ACTION ): + { + ByteString aByteStr; + INT32 nIndex, nLen; + + rIStm >> aPt >> nIndex >> nLen >> nTmp; + rIStm.Read( aByteStr.AllocBuffer( (USHORT)nTmp ), nTmp + 1 ); + UniString aStr( aByteStr, eActualCharSet ); + rMtf.AddAction( new MetaTextAction( aPt, aStr, (USHORT) nIndex, (USHORT) nLen ) ); + } + break; + + case( GDI_TEXTARRAY_ACTION ): + { + ByteString aByteStr; + long* pDXAry = NULL; + INT32 nIndex, nLen, nAryLen; + + rIStm >> aPt >> nIndex >> nLen >> nTmp >> nAryLen; + rIStm.Read( aByteStr.AllocBuffer( (USHORT)nTmp ), nTmp + 1 ); + UniString aStr( aByteStr, eActualCharSet ); + + if( nAryLen > 0L ) + { + pDXAry = new long[ nAryLen ]; + + for( long i = 0L; i < nAryLen; i++ ) + rIStm >> nTmp, pDXAry[ i ] = nTmp; + } + + rMtf.AddAction( new MetaTextArrayAction( aPt, aStr, pDXAry, (USHORT) nIndex, (USHORT) nLen ) ); + + if( pDXAry ) + delete[] pDXAry; + } + break; + + case( GDI_STRETCHTEXT_ACTION ): + { + ByteString aByteStr; + INT32 nIndex, nLen, nWidth; + + rIStm >> aPt >> nIndex >> nLen >> nTmp >> nWidth; + rIStm.Read( aByteStr.AllocBuffer( (USHORT)nTmp ), nTmp + 1 ); + UniString aStr( aByteStr, eActualCharSet ); + rMtf.AddAction( new MetaStretchTextAction( aPt, nWidth, aStr, (USHORT) nIndex, (USHORT) nLen ) ); + } + break; + + case( GDI_BITMAP_ACTION ): + { + Bitmap aBmp; + + rIStm >> aPt >> aBmp; + rMtf.AddAction( new MetaBmpAction( aPt, aBmp ) ); + } + break; + + case( GDI_BITMAPSCALE_ACTION ): + { + Bitmap aBmp; + + rIStm >> aPt >> aSz >> aBmp; + rMtf.AddAction( new MetaBmpScaleAction( aPt, aSz, aBmp ) ); + } + break; + + case( GDI_BITMAPSCALEPART_ACTION ): + { + Bitmap aBmp; + Size aSz2; + + rIStm >> aPt >> aSz >> aPt1 >> aSz2 >> aBmp; + rMtf.AddAction( new MetaBmpScalePartAction( aPt, aSz, aPt1, aSz2, aBmp ) ); + } + break; + + case( GDI_PEN_ACTION ): + { + INT32 nPenWidth; + INT16 nPenStyle; + + ImplReadColor( rIStm, aColor ); + rIStm >> nPenWidth >> nPenStyle; + + aLineInfo.SetStyle( nPenStyle ? LINE_SOLID : LINE_NONE ); + aLineInfo.SetWidth( nPenWidth ); + bFatLine = nPenStyle && !aLineInfo.IsDefault(); + + rMtf.AddAction( new MetaLineColorAction( aColor, nPenStyle != 0 ) ); + } + break; + + case( GDI_FILLBRUSH_ACTION ): + { + INT16 nBrushStyle; + + ImplReadColor( rIStm, aColor ); + rIStm.SeekRel( 6L ); + rIStm >> nBrushStyle; + rMtf.AddAction( new MetaFillColorAction( aColor, nBrushStyle != 0 ) ); + rIStm.SeekRel( 2L ); + } + break; + + case( GDI_MAPMODE_ACTION ): + { + ImplReadMapMode( rIStm, aMapMode ); + rMtf.AddAction( new MetaMapModeAction( aMapMode ) ); + } + break; + + case( GDI_CLIPREGION_ACTION ): + { + Region aRegion; + INT16 nRegType; + INT16 bIntersect; + BOOL bClip = FALSE; + + rIStm >> nRegType >> bIntersect; + ImplReadRect( rIStm, aRect ); + + switch( nRegType ) + { + case( 0 ): + break; + + case( 1 ): + { + Rectangle aRegRect; + + ImplReadRect( rIStm, aRegRect ); + aRegion = Region( aRegRect ); + bClip = TRUE; + } + break; + + case( 2 ): + { + ImplReadPoly( rIStm, aPoly ); + aRegion = Region( aPoly ); + bClip = TRUE; + } + break; + + case( 3 ): + { + PolyPolygon aPolyPoly; + INT32 nPolyCount; + + rIStm >> nPolyCount; + + for( USHORT i = 0; i < (USHORT) nPolyCount; i++ ) + { + ImplReadPoly( rIStm, aPoly ); + aPolyPoly.Insert( aPoly ); + } + + aRegion = Region( aPolyPoly ); + bClip = TRUE; + } + break; + } + + if( bIntersect ) + aRegion.Intersect( aRect ); + + rMtf.AddAction( new MetaClipRegionAction( aRegion, bClip ) ); + } + break; + + case( GDI_MOVECLIPREGION_ACTION ): + { + rIStm >> nTmp >> nTmp1; + rMtf.AddAction( new MetaMoveClipRegionAction( nTmp, nTmp1 ) ); + } + break; + + case( GDI_ISECTCLIPREGION_ACTION ): + { + ImplReadRect( rIStm, aRect ); + rMtf.AddAction( new MetaISectRectClipRegionAction( aRect ) ); + } + break; + + case( GDI_RASTEROP_ACTION ): + { + RasterOp eRasterOp; + INT16 nRasterOp; + + rIStm >> nRasterOp; + + switch( nRasterOp ) + { + case( 1 ): + eRasterOp = ROP_INVERT; + break; + + case( 4 ): + case( 5 ): + eRasterOp = ROP_XOR; + break; + + default: + eRasterOp = ROP_OVERPAINT; + break; + } + + rMtf.AddAction( new MetaRasterOpAction( eRasterOp ) ); + } + break; + + case( GDI_PUSH_ACTION ): + { + aLIStack.Push( new LineInfo( aLineInfo ) ); + rMtf.AddAction( new MetaPushAction( PUSH_ALL ) ); + } + break; + + case( GDI_POP_ACTION ): + { + + LineInfo* pLineInfo = (LineInfo*) aLIStack.Pop(); + + // restore line info + if( pLineInfo ) + { + aLineInfo = *pLineInfo; + delete pLineInfo; + bFatLine = ( LINE_NONE != aLineInfo.GetStyle() ) && !aLineInfo.IsDefault(); + } + + rMtf.AddAction( new MetaPopAction() ); + } + break; + + case( GDI_GRADIENT_ACTION ): + { + Color aStartCol; + Color aEndCol; + INT16 nStyle; + INT16 nAngle; + INT16 nBorder; + INT16 nOfsX; + INT16 nOfsY; + INT16 nIntensityStart; + INT16 nIntensityEnd; + + ImplReadRect( rIStm, aRect ); + rIStm >> nStyle; + ImplReadColor( rIStm, aStartCol ); + ImplReadColor( rIStm, aEndCol ); + rIStm >> nAngle >> nBorder >> nOfsX >> nOfsY >> nIntensityStart >> nIntensityEnd; + + Gradient aGrad( (GradientStyle) nStyle, aStartCol, aEndCol ); + + aGrad.SetAngle( nAngle ); + aGrad.SetBorder( nBorder ); + aGrad.SetOfsX( nOfsX ); + aGrad.SetOfsY( nOfsY ); + aGrad.SetStartIntensity( nIntensityStart ); + aGrad.SetEndIntensity( nIntensityEnd ); + rMtf.AddAction( new MetaGradientAction( aRect, aGrad ) ); + } + break; + + case( GDI_TRANSPARENT_COMMENT ): + { + PolyPolygon aPolyPoly; + INT32 nFollowingActionCount; + INT16 nTrans; + + rIStm >> aPolyPoly >> nTrans >> nFollowingActionCount; + ImplSkipActions( rIStm, nFollowingActionCount ); + rMtf.AddAction( new MetaTransparentAction( aPolyPoly, nTrans ) ); + +#ifdef CVTSVM_WRITE_SUBACTIONCOUNT + i += nFollowingActionCount; +#endif + } + break; + + case( GDI_FLOATTRANSPARENT_COMMENT ): + { + GDIMetaFile aMtf; + Point aPos; + Size aSize; + Gradient aGradient; + INT32 nFollowingActionCount; + + rIStm >> aMtf >> aPos >> aSize >> aGradient >> nFollowingActionCount; + ImplSkipActions( rIStm, nFollowingActionCount ); + rMtf.AddAction( new MetaFloatTransparentAction( aMtf, aPos, aSize, aGradient ) ); + +#ifdef CVTSVM_WRITE_SUBACTIONCOUNT + i += nFollowingActionCount; +#endif + } + break; + + case( GDI_HATCH_COMMENT ): + { + PolyPolygon aPolyPoly; + Hatch aHatch; + INT32 nFollowingActionCount; + + rIStm >> aPolyPoly >> aHatch >> nFollowingActionCount; + ImplSkipActions( rIStm, nFollowingActionCount ); + rMtf.AddAction( new MetaHatchAction( aPolyPoly, aHatch ) ); + +#ifdef CVTSVM_WRITE_SUBACTIONCOUNT + i += nFollowingActionCount; +#endif + } + break; + + case( GDI_REFPOINT_COMMENT ): + { + Point aRefPoint; + BOOL bSet; + INT32 nFollowingActionCount; + + rIStm >> aRefPoint >> bSet >> nFollowingActionCount; + ImplSkipActions( rIStm, nFollowingActionCount ); + rMtf.AddAction( new MetaRefPointAction( aRefPoint, bSet ) ); + +#ifdef CVTSVM_WRITE_SUBACTIONCOUNT + i += nFollowingActionCount; +#endif + } + break; + + case( GDI_TEXTLINECOLOR_COMMENT ): + { + Color aColor; + BOOL bSet; + INT32 nFollowingActionCount; + + rIStm >> aColor >> bSet >> nFollowingActionCount; + ImplSkipActions( rIStm, nFollowingActionCount ); + rMtf.AddAction( new MetaTextLineColorAction( aColor, bSet ) ); + +#ifdef CVTSVM_WRITE_SUBACTIONCOUNT + i += nFollowingActionCount; +#endif + } + break; + + case( GDI_TEXTLINE_COMMENT ): + { + Point aStartPt; + long nWidth; + ULONG nStrikeout; + ULONG nUnderline; + INT32 nFollowingActionCount; + + rIStm >> aStartPt >> nWidth >> nStrikeout >> nUnderline >> nFollowingActionCount; + ImplSkipActions( rIStm, nFollowingActionCount ); + rMtf.AddAction( new MetaTextLineAction( aStartPt, nWidth, + (FontStrikeout) nStrikeout, + (FontUnderline) nUnderline ) ); + +#ifdef CVTSVM_WRITE_SUBACTIONCOUNT + i += nFollowingActionCount; +#endif + } + break; + + case( GDI_GRADIENTEX_COMMENT ): + { + PolyPolygon aPolyPoly; + Gradient aGradient; + INT32 nFollowingActionCount; + + rIStm >> aPolyPoly >> aGradient >> nFollowingActionCount; + ImplSkipActions( rIStm, nFollowingActionCount ); + rMtf.AddAction( new MetaGradientExAction( aPolyPoly, aGradient ) ); + +#ifdef CVTSVM_WRITE_SUBACTIONCOUNT + i += nFollowingActionCount; +#endif + } + break; + + case( GDI_COMMENT_COMMENT ): + { + ByteString aComment; + long nValue; + ULONG nDataSize; + BYTE* pData; + INT32 nFollowingActionCount; + + rIStm >> aComment >> nValue >> nDataSize; + + if( nDataSize ) + { + pData = new BYTE[ nDataSize ]; + rIStm.Read( pData, nDataSize ); + } + else + pData = NULL; + + rIStm >> nFollowingActionCount; + ImplSkipActions( rIStm, nFollowingActionCount ); + rMtf.AddAction( new MetaCommentAction( aComment, nValue, pData, nDataSize ) ); + +#ifdef CVTSVM_WRITE_SUBACTIONCOUNT + i += nFollowingActionCount; +#endif + } + break; + + default: + rIStm.SeekRel( nActionSize - 4L ); + break; + } + } + + // cleanup push-pop stack if neccessary + for( void* pLineInfo = aLIStack.Pop(); pLineInfo; pLineInfo = aLIStack.Pop() ) + delete (LineInfo*) pLineInfo; + } + + rIStm.SetNumberFormatInt( nOldFormat ); +} + +// ------------------------------------------------------------------------ + +void SVMConverter::ImplConvertToSVM1( SvStream& rOStm, GDIMetaFile& rMtf ) +{ + ULONG nPos; + ULONG nCountPos; + Font aSaveFont; + const ULONG nActionCount = rMtf.GetActionCount(); + const USHORT nOldFormat = rOStm.GetNumberFormatInt(); + rtl_TextEncoding eActualCharSet = gsl_getSystemTextEncoding(); + const Size aPrefSize( rMtf.GetPrefSize() ); + BOOL bRop_0_1 = FALSE; + VirtualDevice aSaveVDev; + Color aLineCol( COL_BLACK ); + Stack aLineColStack; + + rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + + //MagicCode schreiben + rOStm << "SVGDI"; // Kennung + nPos = rOStm.Tell(); + rOStm << (INT16) 42; // HeaderSize + rOStm << (INT16) 200; // VERSION + rOStm << (INT32) aPrefSize.Width(); + rOStm << (INT32) aPrefSize.Height(); + ImplWriteMapMode( rOStm, rMtf.GetPrefMapMode() ); + + // ActionCount wird spaeter geschrieben + nCountPos = rOStm.Tell(); + rOStm.SeekRel( 4L ); + + const INT32 nActCount = ImplWriteActions( rOStm, rMtf, aSaveVDev, bRop_0_1, aLineCol, aLineColStack, eActualCharSet ); + const ULONG nActPos = rOStm.Tell(); + + rOStm.Seek( nCountPos ); + rOStm << nActCount; + rOStm.Seek( nActPos ); + rOStm.SetNumberFormatInt( nOldFormat ); + + // cleanup push-pop stack if neccessary + for( void* pCol = aLineColStack.Pop(); pCol; pCol = aLineColStack.Pop() ) + delete (Color*) pCol; +} + +// ------------------------------------------------------------------------ + +ULONG SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf, + VirtualDevice& rSaveVDev, BOOL& rRop_0_1, + Color& rLineCol, Stack& rLineColStack, + rtl_TextEncoding& rActualCharSet ) +{ + ULONG nCount = 0; + for( ULONG i = 0, nActionCount = rMtf.GetActionCount(); i < nActionCount; i++ ) + { + const MetaAction* pAction = rMtf.GetAction( i ); + + switch( pAction->GetType() ) + { + case( META_PIXEL_ACTION ): + { + MetaPixelAction* pAct = (MetaPixelAction*) pAction; + + rOStm << (INT16) GDI_PIXEL_ACTION; + rOStm << (INT32) 18; + rOStm << pAct->GetPoint(); + ImplWriteColor( rOStm, pAct->GetColor() ); + nCount++; + } + break; + + case( META_POINT_ACTION ): + { + MetaPointAction* pAct = (MetaPointAction*) pAction; + + rOStm << (INT16) GDI_POINT_ACTION; + rOStm << (INT32) 12; + rOStm << pAct->GetPoint(); + nCount++; + } + break; + + case( META_LINE_ACTION ): + { + MetaLineAction* pAct = (MetaLineAction*) pAction; + const LineInfo& rInfo = pAct->GetLineInfo(); + const BOOL bFatLine = ( !rInfo.IsDefault() && ( LINE_NONE != rInfo.GetStyle() ) ); + + if( bFatLine ) + { + ImplWritePushAction( rOStm ); + ImplWriteLineColor( rOStm, rLineCol, 1, rInfo.GetWidth() ); + } + + rOStm << (INT16) GDI_LINE_ACTION; + rOStm << (INT32) 20; + rOStm << pAct->GetStartPoint(); + rOStm << pAct->GetEndPoint(); + nCount++; + + if( bFatLine ) + { + ImplWritePopAction( rOStm ); + nCount += 3; + } + } + break; + + case( META_RECT_ACTION ): + { + MetaRectAction* pAct = (MetaRectAction*) pAction; + + rOStm << (INT16) GDI_RECT_ACTION; + rOStm << (INT32) 28; + ImplWriteRect( rOStm, pAct->GetRect() ); + rOStm << (INT32) 0; + rOStm << (INT32) 0; + nCount++; + } + break; + + case( META_ROUNDRECT_ACTION ): + { + MetaRoundRectAction* pAct = (MetaRoundRectAction*) pAction; + + rOStm << (INT16) GDI_RECT_ACTION; + rOStm << (INT32) 28; + ImplWriteRect( rOStm, pAct->GetRect() ); + rOStm << (INT32) pAct->GetHorzRound(); + rOStm << (INT32) pAct->GetVertRound(); + nCount++; + } + break; + + case( META_ELLIPSE_ACTION ): + { + MetaEllipseAction* pAct = (MetaEllipseAction*) pAction; + + rOStm << (INT16) GDI_ELLIPSE_ACTION; + rOStm << (INT32) 20; + ImplWriteRect( rOStm, pAct->GetRect() ); + nCount++; + } + break; + + case( META_ARC_ACTION ): + { + MetaArcAction* pAct = (MetaArcAction*) pAction; + + rOStm << (INT16) GDI_ARC_ACTION; + rOStm << (INT32) 36; + ImplWriteRect( rOStm, pAct->GetRect() ); + rOStm << pAct->GetStartPoint(); + rOStm << pAct->GetEndPoint(); + nCount++; + } + break; + + case( META_PIE_ACTION ): + { + MetaPieAction* pAct = (MetaPieAction*) pAction; + + rOStm << (INT16) GDI_PIE_ACTION; + rOStm << (INT32) 36; + ImplWriteRect( rOStm, pAct->GetRect() ); + rOStm << pAct->GetStartPoint(); + rOStm << pAct->GetEndPoint(); + nCount++; + } + break; + + case( META_CHORD_ACTION ): + { + MetaChordAction* pAct = (MetaChordAction*) pAction; + Polygon aChordPoly( pAct->GetRect(), pAct->GetStartPoint(), + pAct->GetEndPoint(), POLY_CHORD ); + const USHORT nPoints = aChordPoly.GetSize(); + + rOStm << (INT16) GDI_POLYGON_ACTION; + rOStm << (INT32) ( 8 + ( nPoints << 3 ) ); + rOStm << (INT32) nPoints; + + for( USHORT n = 0; n < nPoints; n++ ) + rOStm << aChordPoly[ n ]; + + nCount++; + } + break; + + case( META_POLYLINE_ACTION ): + { + MetaPolyLineAction* pAct = (MetaPolyLineAction*) pAction; + const Polygon& rPoly = pAct->GetPolygon(); + const LineInfo& rInfo = pAct->GetLineInfo(); + const USHORT nPoints = rPoly.GetSize(); + const BOOL bFatLine = ( !rInfo.IsDefault() && ( LINE_NONE != rInfo.GetStyle() ) ); + + if( bFatLine ) + { + ImplWritePushAction( rOStm ); + ImplWriteLineColor( rOStm, rLineCol, 1, rInfo.GetWidth() ); + } + + rOStm << (INT16) GDI_POLYLINE_ACTION; + rOStm << (INT32) ( 8 + ( nPoints << 3 ) ); + rOStm << (INT32) nPoints; + + for( USHORT n = 0; n < nPoints; n++ ) + rOStm << rPoly[ n ]; + + nCount++; + + if( bFatLine ) + { + ImplWritePopAction( rOStm ); + nCount += 3; + } + } + break; + + case( META_POLYGON_ACTION ): + { + MetaPolygonAction* pAct = (MetaPolygonAction*) pAction; + const Polygon& rPoly = pAct->GetPolygon(); + const USHORT nPoints = rPoly.GetSize(); + + rOStm << (INT16) GDI_POLYGON_ACTION; + rOStm << (INT32) ( 8 + ( nPoints << 3 ) ); + rOStm << (INT32) nPoints; + + for( USHORT n = 0; n < nPoints; n++ ) + rOStm << rPoly[ n ]; + + nCount++; + } + break; + + case( META_POLYPOLYGON_ACTION ): + { + MetaPolyPolygonAction* pAct = (MetaPolyPolygonAction*) pAction; + ImplWritePolyPolyAction( rOStm, pAct->GetPolyPolygon() ); + nCount++; + } + break; + + case( META_TEXT_ACTION ): + { + MetaTextAction* pAct = (MetaTextAction*) pAction; + ByteString aText( pAct->GetText(), rActualCharSet ); + const ULONG nStrLen = aText.Len(); + + rOStm << (INT16) GDI_TEXT_ACTION; + rOStm << (INT32) ( 24 + ( nStrLen + 1 ) ); + rOStm << pAct->GetPoint(); + rOStm << (INT32) pAct->GetIndex(); + rOStm << (INT32) pAct->GetLen(); + rOStm << (INT32) nStrLen; + rOStm.Write( aText.GetBuffer(), nStrLen + 1 ); + nCount++; + } + break; + + case( META_TEXTARRAY_ACTION ): + { + MetaTextArrayAction* pAct = (MetaTextArrayAction*)pAction; + ByteString aText( pAct->GetText(), rActualCharSet ); + ULONG nAryLen; + ULONG nLen = pAct->GetLen(); + const ULONG nTextLen = aText.Len(); + long* pDXArray = pAct->GetDXArray(); + + if( ( nLen + pAct->GetIndex() ) > nTextLen ) + { + if( pAct->GetIndex() <= nTextLen ) + nLen = nTextLen - pAct->GetIndex(); + else + nLen = 0UL; + } + + if( !pDXArray || !nLen ) + nAryLen = 0; + else + nAryLen = nLen - 1; + + rOStm << (INT16) GDI_TEXTARRAY_ACTION; + rOStm << (INT32) ( 28 + ( nLen + 1 ) + ( nAryLen * 4 ) ); + rOStm << pAct->GetPoint(); + rOStm << (INT32) 0; + rOStm << (INT32) nLen; + rOStm << (INT32) nLen; + rOStm << (INT32) nAryLen; + rOStm.Write( aText.GetBuffer()+pAct->GetIndex(), nLen + 1 ); + + for( ULONG n = 0UL ; n < nAryLen; n++ ) + rOStm << (INT32) pDXArray[ n ]; + + nCount++; + } + break; + + case( META_STRETCHTEXT_ACTION ): + { + MetaStretchTextAction* pAct = (MetaStretchTextAction*) pAction; + ByteString aText( pAct->GetText(), rActualCharSet ); + const ULONG nStrLen = aText.Len(); + + rOStm << (INT16) GDI_STRETCHTEXT_ACTION; + rOStm << (INT32) ( 28 + ( nStrLen + 1 ) ); + rOStm << pAct->GetPoint(); + rOStm << (INT32) pAct->GetIndex(); + rOStm << (INT32) pAct->GetLen(); + rOStm << (INT32) nStrLen; + rOStm << (INT32) pAct->GetWidth(); + rOStm.Write( aText.GetBuffer(), nStrLen + 1 ); + nCount++; + } + break; + + case( META_BMP_ACTION ): + { + MetaBmpAction* pAct = (MetaBmpAction*) pAction; + + rOStm << (INT16) GDI_BITMAP_ACTION; + rOStm << (INT32) 12; + rOStm << pAct->GetPoint(); + rOStm << pAct->GetBitmap(); + nCount++; + } + break; + + case( META_BMPSCALE_ACTION ): + { + MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction; + + rOStm << (INT16) GDI_BITMAPSCALE_ACTION; + rOStm << (INT32) 20; + rOStm << pAct->GetPoint(); + rOStm << pAct->GetSize(); + rOStm << pAct->GetBitmap(); + nCount++; + } + break; + + case( META_BMPSCALEPART_ACTION ): + { + MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction; + + rOStm << (INT16) GDI_BITMAPSCALEPART_ACTION; + rOStm << (INT32) 36; + rOStm << pAct->GetDestPoint(); + rOStm << pAct->GetDestSize(); + rOStm << pAct->GetSrcPoint(); + rOStm << pAct->GetSrcSize(); + rOStm << pAct->GetBitmap(); + nCount++; + } + break; + + case( META_BMPEX_ACTION ): + { + MetaBmpExAction* pAct = (MetaBmpExAction*) pAction; + const Bitmap aBmp( Graphic( pAct->GetBitmapEx() ).GetBitmap() ); + + rOStm << (INT16) GDI_BITMAP_ACTION; + rOStm << (INT32) 12; + rOStm << pAct->GetPoint(); + rOStm << aBmp; + nCount++; + } + break; + + case( META_BMPEXSCALE_ACTION ): + { + MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction; + const Bitmap aBmp( Graphic( pAct->GetBitmapEx() ).GetBitmap() ); + + rOStm << (INT16) GDI_BITMAPSCALE_ACTION; + rOStm << (INT32) 20; + rOStm << pAct->GetPoint(); + rOStm << pAct->GetSize(); + rOStm << aBmp; + nCount++; + } + break; + + case( META_BMPEXSCALEPART_ACTION ): + { + MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction; + const Bitmap aBmp( Graphic( pAct->GetBitmapEx() ).GetBitmap() ); + + rOStm << (INT16) GDI_BITMAPSCALEPART_ACTION; + rOStm << (INT32) 36; + rOStm << pAct->GetDestPoint(); + rOStm << pAct->GetDestSize(); + rOStm << pAct->GetSrcPoint(); + rOStm << pAct->GetSrcSize(); + rOStm << aBmp; + nCount++; + } + break; + + case( META_GRADIENT_ACTION ): + { + MetaGradientAction* pAct = (MetaGradientAction*) pAction; + const Gradient& rGrad = pAct->GetGradient(); + + rOStm << (INT16) GDI_GRADIENT_ACTION; + rOStm << (INT32) 46; + ImplWriteRect( rOStm, pAct->GetRect() ); + rOStm << (INT16) rGrad.GetStyle(); + ImplWriteColor( rOStm, rGrad.GetStartColor() ); + ImplWriteColor( rOStm, rGrad.GetEndColor() ); + rOStm << (INT16) rGrad.GetAngle(); + rOStm << (INT16) rGrad.GetBorder(); + rOStm << (INT16) rGrad.GetOfsX(); + rOStm << (INT16) rGrad.GetOfsY(); + rOStm << (INT16) rGrad.GetStartIntensity(); + rOStm << (INT16) rGrad.GetEndIntensity(); + nCount++; + } + break; + + case( META_GRADIENTEX_ACTION ): + { + const MetaGradientExAction* pA = (MetaGradientExAction*) pAction; + ULONG nOldPos, nNewPos; + + // write RefPoint comment + rOStm << (INT16) GDI_GRADIENTEX_COMMENT; + + // we'll write the ActionSize later + nOldPos = rOStm.Tell(); + rOStm.SeekRel( 4 ); + + // write data + rOStm << pA->GetPolyPolygon() << pA->GetGradient(); + rOStm << (INT32) 0; // number of actions that follow this comment + + // calculate and write ActionSize of comment + nNewPos = rOStm.Tell(); + rOStm.Seek( nOldPos ); + rOStm << (INT32) ( nNewPos - nOldPos ); + rOStm.Seek( nNewPos ); + + nCount++; + } + break; + + case( META_WALLPAPER_ACTION ): + { + MetaWallpaperAction* pAct = (MetaWallpaperAction*) pAction; + const Color& rColor = pAct->GetWallpaper().GetColor(); + + ImplWritePushAction( rOStm ); + ImplWriteLineColor( rOStm, rColor, 1 ); + ImplWriteFillColor( rOStm, rColor, 1 ); + + rOStm << (INT16) GDI_RECT_ACTION; + rOStm << (INT32) 28; + ImplWriteRect( rOStm, pAct->GetRect() ); + rOStm << (INT32) 0; + rOStm << (INT32) 0; + + ImplWritePopAction( rOStm ); + nCount += 5; + } + break; + + case( META_CLIPREGION_ACTION ): + { + MetaClipRegionAction* pAct = (MetaClipRegionAction*) pAction; + const Region& rRegion = pAct->GetRegion(); + Rectangle aClipRect; + + rOStm << (INT16) GDI_CLIPREGION_ACTION; + rOStm << (INT32) 24; + + if( pAct->IsClipping() ) + { + aClipRect = rRegion.GetBoundRect(); + rOStm << (INT16) 1; + } + else + rOStm << (INT16) 0; + + rOStm << (INT16) 0; + ImplWriteRect( rOStm, aClipRect ); + + if( pAct->IsClipping() ) + ImplWriteRect( rOStm, aClipRect ); + + nCount++; + } + break; + + case( META_ISECTRECTCLIPREGION_ACTION ): + { + MetaISectRectClipRegionAction* pAct = (MetaISectRectClipRegionAction*) pAction; + + rOStm << (INT16) GDI_ISECTCLIPREGION_ACTION; + rOStm << (INT32) 20; + rOStm << pAct->GetRect(); + nCount++; + } + break; + + case( META_MOVECLIPREGION_ACTION ): + { + MetaMoveClipRegionAction* pAct = (MetaMoveClipRegionAction*) pAction; + + rOStm << (INT16) GDI_MOVECLIPREGION_ACTION; + rOStm << (INT32) 12; + rOStm << (INT32) pAct->GetHorzMove(); + rOStm << (INT32) pAct->GetVertMove(); + nCount++; + } + break; + + case( META_LINECOLOR_ACTION ): + { + MetaLineColorAction* pAct = (MetaLineColorAction*) pAction; + ImplWriteLineColor( rOStm, rLineCol = pAct->GetColor(), pAct->IsSetting() ? 1 : 0 ); + nCount++; + } + break; + + case( META_FILLCOLOR_ACTION ): + { + MetaFillColorAction* pAct = (MetaFillColorAction*) pAction; + ImplWriteFillColor( rOStm, pAct->GetColor(), pAct->IsSetting() ? 1 : 0 ); + nCount++; + } + break; + + case( META_FONT_ACTION ): + { + rSaveVDev.SetFont( ( (MetaFontAction*) pAction )->GetFont() ); + ImplWriteFont( rOStm, rSaveVDev.GetFont(), rActualCharSet ); + nCount++; + } + break; + + case( META_TEXTCOLOR_ACTION ): + { + Font aSaveFont( rSaveVDev.GetFont() ); + + aSaveFont.SetColor( ( (MetaTextColorAction*) pAction )->GetColor() ); + rSaveVDev.SetFont( aSaveFont ); + ImplWriteFont( rOStm, rSaveVDev.GetFont(), rActualCharSet ); + nCount++; + } + break; + + case( META_TEXTFILLCOLOR_ACTION ): + { + MetaTextFillColorAction* pAct = (MetaTextFillColorAction*) pAction; + Font aSaveFont( rSaveVDev.GetFont() ); + + if( pAct->IsSetting() ) + aSaveFont.SetFillColor( pAct->GetColor() ); + else + aSaveFont.SetFillColor( Color( COL_TRANSPARENT ) ); + + rSaveVDev.SetFont( aSaveFont ); + ImplWriteFont( rOStm, rSaveVDev.GetFont(), rActualCharSet ); + nCount++; + } + break; + + case( META_TEXTALIGN_ACTION ): + { + Font aSaveFont( rSaveVDev.GetFont() ); + + aSaveFont.SetAlign( ( (MetaTextAlignAction*) pAction )->GetTextAlign() ); + rSaveVDev.SetFont( aSaveFont ); + ImplWriteFont( rOStm, rSaveVDev.GetFont(), rActualCharSet ); + nCount++; + } + break; + + case( META_MAPMODE_ACTION ): + { + MetaMapModeAction* pAct = (MetaMapModeAction*) pAction; + + rOStm << (INT16) GDI_MAPMODE_ACTION; + rOStm << (INT32) 30; + ImplWriteMapMode( rOStm, pAct->GetMapMode() ); + nCount++; + } + break; + + case( META_PUSH_ACTION ): + { + ImplWritePushAction( rOStm ); + rLineColStack.Push( new Color( rLineCol ) ); + rSaveVDev.Push(); + nCount++; + } + break; + + case( META_POP_ACTION ): + { + Color* pCol = (Color*) rLineColStack.Pop(); + + if( pCol ) + { + rLineCol = *pCol; + delete pCol; + } + + ImplWritePopAction( rOStm ); + rSaveVDev.Pop(); + nCount++; + } + break; + + case( META_RASTEROP_ACTION ): + { + MetaRasterOpAction* pAct = (MetaRasterOpAction*) pAction; + + if( ( pAct->GetRasterOp() != ROP_0 ) && ( pAct->GetRasterOp() != ROP_1 ) ) + { + INT16 nRasterOp; + + // Falls vorher ROP_0/1 gesetzt war, alten + // Zustand durch Pop erst wieder herstellen + if( rRop_0_1 ) + { + ImplWritePopAction( rOStm ); + rSaveVDev.Pop(); + rRop_0_1 = FALSE; + nCount++; + } + + switch( pAct->GetRasterOp() ) + { + case( ROP_OVERPAINT ) : nRasterOp = 0; break; + case( ROP_XOR ) : nRasterOp = 4; break; + case( ROP_INVERT ): nRasterOp = 1; break; + default: nRasterOp = 0; break; + } + + ImplWriteRasterOpAction( rOStm, nRasterOp ); + nCount++; + } + else + { + ImplWritePushAction( rOStm ); + rSaveVDev.Push(); + + if( pAct->GetRasterOp() == ROP_0 ) + { + ImplWriteLineColor( rOStm, COL_BLACK, 1 ); + ImplWriteFillColor( rOStm, COL_BLACK, 1 ); + } + else + { + ImplWriteLineColor( rOStm, COL_WHITE, 1 ); + ImplWriteFillColor( rOStm, COL_WHITE, 1 ); + } + + ImplWriteRasterOpAction( rOStm, 0 ); + rRop_0_1 = TRUE; + nCount += 4; + } + } + break; + + case( META_TRANSPARENT_ACTION ): + { + const PolyPolygon& rPolyPoly = ( (MetaTransparentAction*) pAction )->GetPolyPolygon(); + const INT16 nTrans = ( (MetaTransparentAction*) pAction )->GetTransparence(); + const INT16 nBrushStyle = ( nTrans < 38 ) ? 8 : ( nTrans < 63 ) ? 9 : 10; + ULONG nOldPos, nNewPos; + + // write transparence comment + rOStm << (INT16) GDI_TRANSPARENT_COMMENT; + + // we'll write the ActionSize later + nOldPos = rOStm.Tell(); + rOStm.SeekRel( 4 ); + + // write comment data + rOStm << rPolyPoly; + rOStm << nTrans; + rOStm << (INT32) 15; // number of actions that follow this comment + + // calculate and write ActionSize of comment + nNewPos = rOStm.Tell(); + rOStm.Seek( nOldPos ); + rOStm << (INT32) ( nNewPos - nOldPos ); + rOStm.Seek( nNewPos ); + + { + // write actions for transparence + ImplWritePushAction( rOStm ); + { + ImplWriteRasterOpAction( rOStm, 4 ); + ImplWritePolyPolyAction( rOStm, rPolyPoly ); + + ImplWritePushAction( rOStm ); + { + ImplWriteRasterOpAction( rOStm, 2 ); + ImplWriteFillColor( rOStm, COL_BLACK, nBrushStyle ); + ImplWritePolyPolyAction( rOStm, rPolyPoly ); + } + ImplWritePopAction( rOStm ); + + ImplWriteRasterOpAction( rOStm, 4 ); + ImplWritePolyPolyAction( rOStm, rPolyPoly ); + } + ImplWritePopAction( rOStm ); + + ImplWritePushAction( rOStm ); + { + ImplWriteFillColor( rOStm, Color(), 0 ); + ImplWritePolyPolyAction( rOStm, rPolyPoly ); + } + ImplWritePopAction( rOStm ); + +#ifdef CVTSVM_WRITE_SUBACTIONCOUNT + nCount += 15; +#endif + } + + nCount++; + } + break; + + case( META_FLOATTRANSPARENT_ACTION ): + { + const MetaFloatTransparentAction* pA = (MetaFloatTransparentAction*) pAction; + const GDIMetaFile& rTransMtf = pA->GetGDIMetaFile(); + const Point& rPos = pA->GetPoint(); + const Size& rSize = pA->GetSize(); + const Gradient& rGradient = pA->GetGradient(); + ULONG nOldPos, nNewPos; + + // write RefPoint comment + rOStm << (INT16) GDI_FLOATTRANSPARENT_COMMENT; + + // we'll write the ActionSize later + nOldPos = rOStm.Tell(); + rOStm.SeekRel( 4 ); + + // write comment data + rOStm << rTransMtf << rPos << rSize << rGradient; + + // calculate and write ActionSize of comment + nNewPos = rOStm.Tell(); + rOStm.Seek( nOldPos ); + rOStm << (INT32) ( nNewPos - nOldPos + 4 ); + rOStm.Seek( ( nOldPos = nNewPos ) + 4 ); + + { + // write actions for float transparence + ULONG nAddCount; + GDIMetaFile aMtf( rTransMtf ); + const Size aSrcSize( rTransMtf.GetPrefSize() ); + Point aSrcPt( rTransMtf.GetPrefMapMode().GetOrigin() ); + const double fScaleX = aSrcSize.Width() ? (double) rSize.Width() / aSrcSize.Width() : 1.0; + const double fScaleY = aSrcSize.Height() ? (double) rSize.Height() / aSrcSize.Height() : 1.0; + long nMoveX, nMoveY; + + if( fScaleX != 1.0 || fScaleY != 1.0 ) + { + aMtf.Scale( fScaleX, fScaleY ); + aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY ); + } + + nMoveX = rPos.X() - aSrcPt.X(), nMoveY = rPos.Y() - aSrcPt.Y(); + + if( nMoveX || nMoveY ) + aMtf.Move( nMoveX, nMoveY ); + + nAddCount = ImplWriteActions( rOStm, aMtf, rSaveVDev, rRop_0_1, rLineCol, rLineColStack, rActualCharSet ); + nNewPos = rOStm.Tell(); + rOStm.Seek( nOldPos ); + rOStm << (INT32) nAddCount; + rOStm.Seek( nNewPos ); + +#ifdef CVTSVM_WRITE_SUBACTIONCOUNT + nCount += nAddCount; +#endif + } + + nCount++; + } + break; + + case( META_HATCH_ACTION ): + { + const MetaHatchAction* pA = (MetaHatchAction*) pAction; + const PolyPolygon& rPolyPoly = pA->GetPolyPolygon(); + const Hatch& rHatch = pA->GetHatch(); + ULONG nOldPos, nNewPos, nAddCount; + + // write hatch comment + rOStm << (INT16) GDI_HATCH_COMMENT; + + // we'll write the ActionSize later + nOldPos = rOStm.Tell(); + rOStm.SeekRel( 4 ); + + // write comment data + rOStm << rPolyPoly; + rOStm << rHatch; + + // calculate and write ActionSize of comment + nNewPos = rOStm.Tell(); + rOStm.Seek( nOldPos ); + rOStm << (INT32) ( nNewPos - nOldPos + 4 ); + rOStm.Seek( ( nOldPos = nNewPos ) + 4 ); + + { + // write actions for hatch + VirtualDevice aVDev; + GDIMetaFile aTmpMtf; + + aVDev.AddHatchActions( rPolyPoly, rHatch, aTmpMtf ); + nAddCount = ImplWriteActions( rOStm, aTmpMtf, rSaveVDev, rRop_0_1, rLineCol, rLineColStack, rActualCharSet ); + nNewPos = rOStm.Tell(); + rOStm.Seek( nOldPos ); + rOStm << (INT32) nAddCount; + rOStm.Seek( nNewPos ); + +#ifdef CVTSVM_WRITE_SUBACTIONCOUNT + nCount += nAddCount; +#endif + } + + nCount++; + } + break; + + case( META_REFPOINT_ACTION ): + { + const MetaRefPointAction* pA = (MetaRefPointAction*) pAction; + const Point& rRefPoint = pA->GetRefPoint(); + const BOOL bSet = pA->IsSetting(); + ULONG nOldPos, nNewPos; + + // write RefPoint comment + rOStm << (INT16) GDI_REFPOINT_COMMENT; + + // we'll write the ActionSize later + nOldPos = rOStm.Tell(); + rOStm.SeekRel( 4 ); + + // write data + rOStm << rRefPoint << bSet; + rOStm << (INT32) 0; // number of actions that follow this comment + + // calculate and write ActionSize of comment + nNewPos = rOStm.Tell(); + rOStm.Seek( nOldPos ); + rOStm << (INT32) ( nNewPos - nOldPos ); + rOStm.Seek( nNewPos ); + + nCount++; + } + break; + + case( META_TEXTLINECOLOR_ACTION ): + { + const MetaTextLineColorAction* pA = (MetaTextLineColorAction*) pAction; + const Color& rColor = pA->GetColor(); + const BOOL bSet = pA->IsSetting(); + ULONG nOldPos, nNewPos; + + // write RefPoint comment + rOStm << (INT16) GDI_TEXTLINECOLOR_COMMENT; + + // we'll write the ActionSize later + nOldPos = rOStm.Tell(); + rOStm.SeekRel( 4 ); + + // write data + rOStm << rColor << bSet; + rOStm << (INT32) 0; // number of actions that follow this comment + + // calculate and write ActionSize of comment + nNewPos = rOStm.Tell(); + rOStm.Seek( nOldPos ); + rOStm << (INT32) ( nNewPos - nOldPos ); + rOStm.Seek( nNewPos ); + + nCount++; + } + break; + + case( META_TEXTLINE_ACTION ): + { + const MetaTextLineAction* pA = (MetaTextLineAction*) pAction; + const Point& rStartPt = pA->GetStartPoint(); + const long nWidth = pA->GetWidth(); + const FontStrikeout eStrikeout = pA->GetStrikeout(); + const FontUnderline eUnderline = pA->GetUnderline(); + ULONG nOldPos, nNewPos; + + // write RefPoint comment + rOStm << (INT16) GDI_TEXTLINE_COMMENT; + + // we'll write the ActionSize later + nOldPos = rOStm.Tell(); + rOStm.SeekRel( 4 ); + + // write data + rOStm << rStartPt << nWidth << (ULONG) eStrikeout << (ULONG) eUnderline; + rOStm << (INT32) 0; // number of actions that follow this comment + + // calculate and write ActionSize of comment + nNewPos = rOStm.Tell(); + rOStm.Seek( nOldPos ); + rOStm << (INT32) ( nNewPos - nOldPos ); + rOStm.Seek( nNewPos ); + + nCount++; + } + break; + + case( META_EPS_ACTION ): + break; + + case( META_COMMENT_ACTION ): + { + const MetaCommentAction* pA = (MetaCommentAction*) pAction; + const ULONG nDataSize = pA->GetDataSize(); + ULONG nOldPos, nNewPos; + + // write RefPoint comment + rOStm << (INT16) GDI_COMMENT_COMMENT; + + // we'll write the ActionSize later + nOldPos = rOStm.Tell(); + rOStm.SeekRel( 4 ); + + // write data + rOStm << pA->GetComment() << pA->GetValue() << nDataSize; + + if( nDataSize ) + rOStm.Write( pA->GetData(), nDataSize ); + + rOStm << (INT32) 0; // number of actions that follow this comment + + // calculate and write ActionSize of comment + nNewPos = rOStm.Tell(); + rOStm.Seek( nOldPos ); + rOStm << (INT32) ( nNewPos - nOldPos ); + rOStm.Seek( nNewPos ); + + nCount++; + } + break; + +#ifdef DBG_UTIL + default: + { + ByteString aStr( "Missing implementation for Action#: " ); + aStr += ByteString::CreateFromInt32( pAction->GetType() ); + aStr += '!'; + DBG_ERROR( aStr.GetBuffer() ); + } + break; +#endif + +/* + case( META_TEXTRECT_ACTION ): + { + MetaTextRectAction* pAct = (MetaTextRectAction*) pAction; + + rOStm << ; + rOStm << ; + + nCount++; + } + break; +*/ + +/* + case( META_MASK_ACTION ): + { + MetaMaskAction* pAct = (MetaMaskAction*) pAction; + + rOStm << ; + rOStm << ; + + nCount++; + } + break; +*/ + +/* + case( META_MASKSCALE_ACTION ): + { + MetaMaskScaleAction* pAct = (MetaMaskScaleAction*) pAction; + + rOStm << ; + rOStm << ; + + nCount++; + } + break; +*/ + +/* + case( META_MASKSCALEPART_ACTION ): + { + MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction; + + rOStm << ; + rOStm << ; + + nCount++; + } + break; +*/ + +/* + case( META_ISECTREGIONCLIPREGION_ACTION ): + { + MetaISectRegionClipRegionAction* pAct = (MetaISectRegionClipRegionAction*) pAction; + + rOStm << ; + rOStm << ; + + nCount++; + } + break; +*/ + } + } + + return nCount; +} diff --git a/vcl/source/gdi/font.cxx b/vcl/source/gdi/font.cxx new file mode 100644 index 000000000000..657d42a21546 --- /dev/null +++ b/vcl/source/gdi/font.cxx @@ -0,0 +1,625 @@ +/************************************************************************* + * + * $RCSfile: font.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_FONT_CXX + +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif +#ifndef _VCOMPAT_HXX +#include <tools/vcompat.hxx> +#endif +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _SV_FONT_HXX +#include <font.hxx> +#endif + +// ======================================================================= + +DBG_NAME( Font ); + +// ----------------------------------------------------------------------- + +Impl_Font::Impl_Font() : + maColor( COL_BLACK ), + maFillColor( COL_TRANSPARENT ) +{ + mnRefCount = 1; + meCharSet = RTL_TEXTENCODING_DONTKNOW; + meLanguage = LANGUAGE_DONTKNOW; + meFamily = FAMILY_DONTKNOW; + mePitch = PITCH_DONTKNOW; + meAlign = ALIGN_TOP; + meWeight = WEIGHT_DONTKNOW; + meWidthType = WIDTH_DONTKNOW; + meUnderline = UNDERLINE_NONE; + meStrikeout = STRIKEOUT_NONE; + meItalic = ITALIC_NONE; + mbWordLine = FALSE; + mbOutline = FALSE; + mbShadow = FALSE; + mbKerning = FALSE; + mbTransparent = TRUE; + mnOrientation = 0; +} + +// ----------------------------------------------------------------------- + +Impl_Font::Impl_Font( const Impl_Font& rImplFont ) : + maColor( rImplFont.maColor ), + maFillColor( rImplFont.maFillColor ), + maName( rImplFont.maName ), + maStyleName( rImplFont.maStyleName ), + maSize( rImplFont.maSize ) +{ + mnRefCount = 1; + meCharSet = rImplFont.meCharSet; + meLanguage = rImplFont.meLanguage; + meFamily = rImplFont.meFamily; + mePitch = rImplFont.mePitch; + meAlign = rImplFont.meAlign; + meWeight = rImplFont.meWeight; + meWidthType = rImplFont.meWidthType; + meUnderline = rImplFont.meUnderline; + meStrikeout = rImplFont.meStrikeout; + meItalic = rImplFont.meItalic; + mbWordLine = rImplFont.mbWordLine; + mbOutline = rImplFont.mbOutline; + mbShadow = rImplFont.mbShadow; + mbKerning = rImplFont.mbKerning; + mbTransparent = rImplFont.mbTransparent; + mnOrientation = rImplFont.mnOrientation; +} + +// ----------------------------------------------------------------------- + +void Font::MakeUnique() +{ + // Falls noch andere Referenzen bestehen, dann kopieren + if ( mpImplFont->mnRefCount != 1 ) + { + if ( mpImplFont->mnRefCount ) + mpImplFont->mnRefCount--; + mpImplFont = new Impl_Font( *mpImplFont ); + } +} + +// ----------------------------------------------------------------------- + +Font::Font() +{ + DBG_CTOR( Font, NULL ); + +#ifdef WIN + static Impl_Font _near aStaticImplFont; +#else + static Impl_Font aStaticImplFont; +#endif + // RefCount == 0 fuer statische Objekte + aStaticImplFont.mnRefCount = 0; + mpImplFont = &aStaticImplFont; +} + +// ----------------------------------------------------------------------- + +Font::Font( const Font& rFont ) +{ + DBG_CTOR( Font, NULL ); + DBG_CHKOBJ( &rFont, Font, NULL ); + DBG_ASSERT( rFont.mpImplFont->mnRefCount < 0xFFFE, "Font: RefCount overflow" ); + + // shared Instance Daten uebernehmen und Referenzcounter erhoehen + mpImplFont = rFont.mpImplFont; + // RefCount == 0 fuer statische Objekte + if ( mpImplFont->mnRefCount ) + mpImplFont->mnRefCount++; +} + +// ----------------------------------------------------------------------- + +Font::Font( const XubString& rName, const Size& rSize ) +{ + DBG_CTOR( Font, NULL ); + + mpImplFont = new Impl_Font; + mpImplFont->maName = rName; + mpImplFont->maSize = rSize; +} + +// ----------------------------------------------------------------------- + +Font::Font( const XubString& rName, const XubString& rStyleName, const Size& rSize ) +{ + DBG_CTOR( Font, NULL ); + + mpImplFont = new Impl_Font; + mpImplFont->maName = rName; + mpImplFont->maStyleName = rStyleName; + mpImplFont->maSize = rSize; +} + +// ----------------------------------------------------------------------- + +Font::Font( FontFamily eFamily, const Size& rSize ) +{ + DBG_CTOR( Font, NULL ); + + mpImplFont = new Impl_Font; + mpImplFont->meFamily = eFamily; + mpImplFont->maSize = rSize; +} + +// ----------------------------------------------------------------------- + +Font::~Font() +{ + DBG_DTOR( Font, NULL ); + + // Wenn es keine statischen ImplDaten sind, dann loeschen, wenn es + // die letzte Referenz ist, sonst Referenzcounter decrementieren + if ( mpImplFont->mnRefCount ) + { + if ( mpImplFont->mnRefCount == 1 ) + delete mpImplFont; + else + mpImplFont->mnRefCount--; + } +} + +// ----------------------------------------------------------------------- + +void Font::SetColor( const Color& rColor ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->maColor = rColor; +} + +// ----------------------------------------------------------------------- + +void Font::SetFillColor( const Color& rColor ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->maFillColor = rColor; + if ( rColor.GetTransparency() ) + mpImplFont->mbTransparent = TRUE; +} + +// ----------------------------------------------------------------------- + +void Font::SetTransparent( BOOL bTransparent ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->mbTransparent = bTransparent; +} + +// ----------------------------------------------------------------------- + +void Font::SetAlign( FontAlign eAlign ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->meAlign = eAlign; +} + +// ----------------------------------------------------------------------- + +void Font::SetName( const XubString& rName ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->maName = rName; +} + +// ----------------------------------------------------------------------- + +void Font::SetStyleName( const XubString& rStyleName ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->maStyleName = rStyleName; +} + +// ----------------------------------------------------------------------- + +void Font::SetSize( const Size& rSize ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->maSize = rSize; +} + +// ----------------------------------------------------------------------- + +void Font::SetFamily( FontFamily eFamily ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->meFamily = eFamily; +} + +// ----------------------------------------------------------------------- + +void Font::SetCharSet( CharSet eCharSet ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->meCharSet = eCharSet; +} + +// ----------------------------------------------------------------------- + +void Font::SetLanguage( LanguageType eLanguage ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->meLanguage = eLanguage; +} + +// ----------------------------------------------------------------------- + +void Font::SetPitch( FontPitch ePitch ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->mePitch = ePitch; +} + +// ----------------------------------------------------------------------- + +void Font::SetOrientation( short nOrientation ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->mnOrientation = nOrientation; +} + +// ----------------------------------------------------------------------- + +void Font::SetKerning( BOOL bKerning ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->mbKerning = bKerning; +} + +// ----------------------------------------------------------------------- + +void Font::SetWeight( FontWeight eWeight ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->meWeight = eWeight; +} + +// ----------------------------------------------------------------------- + +void Font::SetWidthType( FontWidth eWidth ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->meWidthType = eWidth; +} + +// ----------------------------------------------------------------------- + +void Font::SetItalic( FontItalic eItalic ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->meItalic = eItalic; +} + +// ----------------------------------------------------------------------- + +void Font::SetOutline( BOOL bOutline ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->mbOutline = bOutline; +} + +// ----------------------------------------------------------------------- + +void Font::SetShadow( BOOL bShadow ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->mbShadow = bShadow; +} + +// ----------------------------------------------------------------------- + +void Font::SetUnderline( FontUnderline eUnderline ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->meUnderline = eUnderline; +} + +// ----------------------------------------------------------------------- + +void Font::SetStrikeout( FontStrikeout eStrikeout ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->meStrikeout = eStrikeout; +} + +// ----------------------------------------------------------------------- + +void Font::SetWordLineMode( BOOL bWordLine ) +{ + DBG_CHKTHIS( Font, NULL ); + + MakeUnique(); + mpImplFont->mbWordLine = bWordLine; +} + +// ----------------------------------------------------------------------- + +Font& Font::operator=( const Font& rFont ) +{ + DBG_CHKTHIS( Font, NULL ); + DBG_CHKOBJ( &rFont, Font, NULL ); + DBG_ASSERT( rFont.mpImplFont->mnRefCount < 0xFFFE, "Font: RefCount overflow" ); + + // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann + // RefCount == 0 fuer statische Objekte + if ( rFont.mpImplFont->mnRefCount ) + rFont.mpImplFont->mnRefCount++; + + // Wenn es keine statischen ImplDaten sind, dann loeschen, wenn es + // die letzte Referenz ist, sonst Referenzcounter decrementieren + if ( mpImplFont->mnRefCount ) + { + if ( mpImplFont->mnRefCount == 1 ) + delete mpImplFont; + else + mpImplFont->mnRefCount--; + } + + mpImplFont = rFont.mpImplFont; + + return *this; +} + +// ----------------------------------------------------------------------- + +BOOL Font::operator==( const Font& rFont ) const +{ + DBG_CHKTHIS( Font, NULL ); + DBG_CHKOBJ( &rFont, Font, NULL ); + + if ( mpImplFont == rFont.mpImplFont ) + return TRUE; + + if ( (mpImplFont->meWeight == rFont.mpImplFont->meWeight ) && + (mpImplFont->meItalic == rFont.mpImplFont->meItalic ) && + (mpImplFont->meUnderline == rFont.mpImplFont->meUnderline ) && + (mpImplFont->mbWordLine == rFont.mpImplFont->mbWordLine ) && + (mpImplFont->meFamily == rFont.mpImplFont->meFamily ) && + (mpImplFont->mePitch == rFont.mpImplFont->mePitch ) && + (mpImplFont->meCharSet == rFont.mpImplFont->meCharSet ) && + (mpImplFont->meAlign == rFont.mpImplFont->meAlign ) && + (mpImplFont->maName == rFont.mpImplFont->maName ) && + (mpImplFont->maStyleName == rFont.mpImplFont->maStyleName ) && + (mpImplFont->maColor == rFont.mpImplFont->maColor ) && + (mpImplFont->maFillColor == rFont.mpImplFont->maFillColor ) && + (mpImplFont->maSize == rFont.mpImplFont->maSize ) && + (mpImplFont->mnOrientation == rFont.mpImplFont->mnOrientation ) && + (mpImplFont->meStrikeout == rFont.mpImplFont->meStrikeout ) && + (mpImplFont->mbOutline == rFont.mpImplFont->mbOutline ) && + (mpImplFont->mbShadow == rFont.mpImplFont->mbShadow ) && + (mpImplFont->mbKerning == rFont.mpImplFont->mbKerning ) && + (mpImplFont->mbTransparent == rFont.mpImplFont->mbTransparent ) ) + return TRUE; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +void Font::Merge( const Font& rFont ) +{ + if ( rFont.GetName().Len() ) + { + SetName( rFont.GetName() ); + SetStyleName( rFont.GetStyleName() ); + SetFamily( rFont.GetFamily() ); + SetCharSet( GetCharSet() ); + SetLanguage( rFont.GetLanguage() ); + SetPitch( rFont.GetPitch() ); + } + + if ( rFont.GetSize().Height() ) + SetSize( rFont.GetSize() ); + if ( rFont.GetWeight() != WEIGHT_DONTKNOW ) + SetWeight( rFont.GetWeight() ); + if ( rFont.GetWidthType() != WIDTH_DONTKNOW ) + SetWidthType( rFont.GetWidthType() ); + if ( rFont.GetItalic() != ITALIC_DONTKNOW ) + SetItalic( rFont.GetItalic() ); + if ( rFont.GetUnderline() != UNDERLINE_DONTKNOW ) + { + SetUnderline( rFont.GetUnderline() ); + SetWordLineMode( rFont.IsWordLineMode() ); + } + if ( rFont.GetStrikeout() != STRIKEOUT_DONTKNOW ) + { + SetStrikeout( rFont.GetStrikeout() ); + SetWordLineMode( rFont.IsWordLineMode() ); + } + + // Defaults? + SetOrientation( rFont.GetOrientation() ); + SetKerning( rFont.IsKerning() ); + SetOutline( rFont.IsOutline() ); + SetShadow( rFont.IsShadow() ); +} + +// ----------------------------------------------------------------------- + +SvStream& operator>>( SvStream& rIStm, Impl_Font& rImpl_Font ) +{ + VersionCompat aCompat( rIStm, STREAM_READ ); + UINT16 nTmp16; + BOOL bTmp; + + rIStm.ReadByteString( rImpl_Font.maName, rIStm.GetStreamCharSet() ); + rIStm.ReadByteString( rImpl_Font.maStyleName, rIStm.GetStreamCharSet() ); + rIStm >> rImpl_Font.maSize; +// rIStm >> rImpl_Font.maColor; // removed since SUPD396 +// rIStm >> rImpl_Font.maFillColor; // removed since SUPD396 + + rIStm >> nTmp16; rImpl_Font.meCharSet = (rtl_TextEncoding) nTmp16; + rIStm >> nTmp16; rImpl_Font.meFamily = (FontFamily) nTmp16; + rIStm >> nTmp16; rImpl_Font.mePitch = (FontPitch) nTmp16; +// rIStm >> nTmp16; rImpl_Font.meAlign = (FontAlign) nTmp16; // removed since SUPD396 + rIStm >> nTmp16; rImpl_Font.meWeight = (FontWeight) nTmp16; + rIStm >> nTmp16; rImpl_Font.meUnderline = (FontUnderline) nTmp16; + rIStm >> nTmp16; rImpl_Font.meStrikeout = (FontStrikeout) nTmp16; + rIStm >> nTmp16; rImpl_Font.meItalic = (FontItalic) nTmp16; + rIStm >> nTmp16; rImpl_Font.meLanguage = (LanguageType) nTmp16; // new since SUPD 396 + rIStm >> nTmp16; rImpl_Font.meWidthType = (FontWidth) nTmp16; // new since SUPD 396 + + rIStm >> rImpl_Font.mnOrientation; + + rIStm >> bTmp; rImpl_Font.mbWordLine = bTmp; + rIStm >> bTmp; rImpl_Font.mbOutline = bTmp; + rIStm >> bTmp; rImpl_Font.mbShadow = bTmp; + rIStm >> bTmp; rImpl_Font.mbKerning = bTmp; +// rIStm >> bTmp; rImpl_Font.mbTransparent = bTmp; // removed since SUPD396 + + return rIStm; +} + +// ----------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rOStm, const Impl_Font& rImpl_Font ) +{ + VersionCompat aCompat( rOStm, STREAM_WRITE, 1 ); + rOStm.WriteByteString( rImpl_Font.maName, rOStm.GetStreamCharSet() ); + rOStm.WriteByteString( rImpl_Font.maStyleName, rOStm.GetStreamCharSet() ); + rOStm << rImpl_Font.maSize; +// rOStm << rImpl_Font.maColor; // removed since SUPD396 +// rOStm << rImpl_Font.maFillColor; // removed since SUPD396 + + rOStm << (UINT16) GetStoreCharSet( rImpl_Font.meCharSet, rOStm.GetVersion() ); + rOStm << (UINT16) rImpl_Font.meFamily; + rOStm << (UINT16) rImpl_Font.mePitch; +// rOStm << (UINT16) rImpl_Font.meAlign; // removed since SUPD396 + rOStm << (UINT16) rImpl_Font.meWeight; + rOStm << (UINT16) rImpl_Font.meUnderline; + rOStm << (UINT16) rImpl_Font.meStrikeout; + rOStm << (UINT16) rImpl_Font.meItalic; + rOStm << (UINT16) rImpl_Font.meLanguage; // new since SUPD 396 + rOStm << (UINT16) rImpl_Font.meWidthType; // new since SUPD 396 + + rOStm << rImpl_Font.mnOrientation; + + rOStm << (BOOL) rImpl_Font.mbWordLine; + rOStm << (BOOL) rImpl_Font.mbOutline; + rOStm << (BOOL) rImpl_Font.mbShadow; + rOStm << (BOOL) rImpl_Font.mbKerning; +// rOStm << (BOOL) rImpl_Font.mbTransparent; // removed since SUPD396 + + return rOStm; +} + +// ----------------------------------------------------------------------- + +SvStream& operator>>( SvStream& rIStm, Font& rFont ) +{ + rFont.MakeUnique(); + return( rIStm >> *rFont.mpImplFont ); +} + +// ----------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rOStm, const Font& rFont ) +{ + return( rOStm << *rFont.mpImplFont ); +} diff --git a/vcl/source/gdi/gdimtf.cxx b/vcl/source/gdi/gdimtf.cxx new file mode 100644 index 000000000000..852dbfcb87a3 --- /dev/null +++ b/vcl/source/gdi/gdimtf.cxx @@ -0,0 +1,1724 @@ +/************************************************************************* + * + * $RCSfile: gdimtf.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_GDIMTF_CXX + +#ifndef _RTL_CRC_H_ +#include <rtl/crc.h> +#endif +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif +#ifndef _VCOMPAT_HXX +#include <tools/vcompat.hxx> +#endif +#ifndef _SV_METAACT_HXX +#include <metaact.hxx> +#endif +#ifndef _SV_SALBTYPE_HXX +#include <salbtype.hxx> +#endif +#ifndef _SV_OUTDEV_HXX +#include <outdev.hxx> +#endif +#ifndef _SV_WINDOW_HXX +#include <window.hxx> +#endif +#ifndef _SV_CVTSVM_HXX +#include <cvtsvm.hxx> +#endif +#include <gdimtf.hxx> + +// ----------- +// - Defines - +// ----------- + +#define GAMMA( _def_cVal, _def_InvGamma ) ((BYTE)MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0L,255L)) + +// -------------------------- +// - Color exchange structs - +// -------------------------- + +struct ImplColAdjustParam +{ + BYTE* pMapR; + BYTE* pMapG; + BYTE* pMapB; +}; + +struct ImplBmpAdjustParam +{ + short nLuminancePercent; + short nContrastPercent; + short nChannelRPercent; + short nChannelGPercent; + short nChannelBPercent; + double fGamma; + BOOL bInvert; +}; + +// ----------------------------------------------------------------------------- + +struct ImplColConvertParam +{ + MtfConversion eConversion; +}; + +struct ImplBmpConvertParam +{ + BmpConversion eConversion; +}; + +// ----------------------------------------------------------------------------- + +struct ImplColMonoParam +{ + Color aColor; +}; + +struct ImplBmpMonoParam +{ + Color aColor; +}; + +// ----------------------------------------------------------------------------- + +struct ImplColReplaceParam +{ + ULONG* pMinR; + ULONG* pMaxR; + ULONG* pMinG; + ULONG* pMaxG; + ULONG* pMinB; + ULONG* pMaxB; + const Color* pDstCols; + ULONG nCount; +}; + +struct ImplBmpReplaceParam +{ + const Color* pSrcCols; + const Color* pDstCols; + ULONG nCount; + const ULONG* pTols; +}; + + +// --------- +// - Label - +// --------- + +struct ImpLabel +{ + String aLabelName; + ULONG nActionPos; + + ImpLabel( const String& rLabelName, ULONG _nActionPos ) : + aLabelName( rLabelName ), + nActionPos( _nActionPos ) {} +}; + +// ------------- +// - LabelList - +// ------------- + +class ImpLabelList : private List +{ +public: + + ImpLabelList() : List( 8, 4, 4 ) {} + ImpLabelList( const ImpLabelList& rList ); + ~ImpLabelList(); + + void ImplInsert( ImpLabel* p ) { Insert( p, LIST_APPEND ); } + ImpLabel* ImplRemove( ULONG nPos ) { return (ImpLabel*) Remove( nPos ); } + void ImplReplace( ImpLabel* p ) { Replace( (void*)p ); } + ImpLabel* ImplFirst() { return (ImpLabel*) First(); } + ImpLabel* ImplNext() { return (ImpLabel*) Next(); } + ImpLabel* ImplGetLabel( ULONG nPos ) const { return (ImpLabel*) GetObject( nPos ); } + ULONG ImplGetLabelPos( const String& rLabelName ); + ULONG ImplCount() const { return Count(); } +}; + +// ------------------------------------------------------------------------ + +ImpLabelList::ImpLabelList( const ImpLabelList& rList ) : + List( rList ) +{ + for( ImpLabel* pLabel = ImplFirst(); pLabel; pLabel = ImplNext() ) + ImplReplace( new ImpLabel( *pLabel ) ); +} + +// ------------------------------------------------------------------------ + +ImpLabelList::~ImpLabelList() +{ + for( ImpLabel* pLabel = ImplFirst(); pLabel; pLabel = ImplNext() ) + delete pLabel; +} + +// ------------------------------------------------------------------------ + +ULONG ImpLabelList::ImplGetLabelPos( const String& rLabelName ) +{ + ULONG nLabelPos = METAFILE_LABEL_NOTFOUND; + + for( ImpLabel* pLabel = ImplFirst(); pLabel; pLabel = ImplNext() ) + { + if ( rLabelName == pLabel->aLabelName ) + { + nLabelPos = GetCurPos(); + break; + } + } + + return nLabelPos; +} + +// --------------- +// - GDIMetaFile - +// --------------- + +GDIMetaFile::GDIMetaFile() : + List ( 0x3EFF, 64, 64 ), + aPrefSize ( 1, 1 ), + pPrev ( NULL ), + pNext ( NULL ), + pOutDev ( NULL ), + pLabelList ( NULL ), + bPause ( FALSE ), + bRecord ( FALSE ) +{ +} + +// ------------------------------------------------------------------------ + +GDIMetaFile::GDIMetaFile( const GDIMetaFile& rMtf ) : + List ( rMtf ), + aPrefMapMode ( rMtf.aPrefMapMode ), + aPrefSize ( rMtf.aPrefSize ), + aHookHdlLink ( rMtf.aHookHdlLink ), + pPrev ( rMtf.pPrev ), + pNext ( rMtf.pNext ), + pOutDev ( NULL ), + bPause ( FALSE ), + bRecord ( FALSE ) +{ + // RefCount der MetaActions erhoehen + for( void* pAct = First(); pAct; pAct = Next() ) + ( (MetaAction*) pAct )->Duplicate(); + + if( rMtf.pLabelList ) + pLabelList = new ImpLabelList( *rMtf.pLabelList ); + else + pLabelList = NULL; + + if( rMtf.bRecord ) + { + Record( rMtf.pOutDev ); + + if ( rMtf.bPause ) + Pause( TRUE ); + } +} + +// ------------------------------------------------------------------------ + +GDIMetaFile::~GDIMetaFile() +{ + Clear(); +} + +// ------------------------------------------------------------------------ + +GDIMetaFile& GDIMetaFile::operator=( const GDIMetaFile& rMtf ) +{ + if( this != &rMtf ) + { + Clear(); + + List::operator=( rMtf ); + + // RefCount der MetaActions erhoehen + for( void* pAct = First(); pAct; pAct = Next() ) + ( (MetaAction*) pAct )->Duplicate(); + + if( rMtf.pLabelList ) + pLabelList = new ImpLabelList( *rMtf.pLabelList ); + else + pLabelList = NULL; + + aPrefMapMode = rMtf.aPrefMapMode; + aPrefSize = rMtf.aPrefSize; + aHookHdlLink = rMtf.aHookHdlLink; + pPrev = rMtf.pPrev; + pNext = rMtf.pNext; + pOutDev = NULL; + bPause = FALSE; + bRecord = FALSE; + + if( rMtf.bRecord ) + { + Record( rMtf.pOutDev ); + + if( rMtf.bPause ) + Pause( TRUE ); + } + } + + return *this; +} + +// ------------------------------------------------------------------------ + +BOOL GDIMetaFile::operator==( const GDIMetaFile& rMtf ) const +{ + const ULONG nCount = Count(); + BOOL bRet = FALSE; + + if( this == &rMtf ) + bRet = TRUE; + else if( rMtf.GetActionCount() == nCount && + rMtf.GetPrefSize() == aPrefSize && + rMtf.GetPrefMapMode() == aPrefMapMode ) + { + bRet = TRUE; + + for( ULONG n = 0UL; n < nCount; n++ ) + { + if( GetObject( n ) != rMtf.GetObject( n ) ) + { + bRet = FALSE; + break; + } + } + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Clear() +{ + if( bRecord ) + Stop(); + + for( void* pAct = First(); pAct; pAct = Next() ) + ( (MetaAction*) pAct )->Delete(); + + List::Clear(); + + delete pLabelList; + pLabelList = NULL; +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Linker( OutputDevice* pOut, BOOL bLink ) +{ + if( bLink ) + { + pNext = NULL; + pPrev = pOut->GetConnectMetaFile(); + pOut->SetConnectMetaFile( this ); + + if( pPrev ) + pPrev->pNext = this; + } + else + { + if( pNext ) + { + pNext->pPrev = pPrev; + + if( pPrev ) + pPrev->pNext = pNext; + } + else + { + if( pPrev ) + pPrev->pNext = NULL; + + pOut->SetConnectMetaFile( pPrev ); + } + + pPrev = NULL; + pNext = NULL; + } +} + +// ------------------------------------------------------------------------ + +long GDIMetaFile::Hook() +{ + return aHookHdlLink.Call( this ); +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Record( OutputDevice* pOut ) +{ + if( bRecord ) + Stop(); + + Last(); + pOutDev = pOut; + bRecord = TRUE; + Linker( pOut, TRUE ); +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Play( GDIMetaFile& rMtf, ULONG nPos ) +{ + if ( !bRecord && !rMtf.bRecord ) + { + MetaAction* pAction = GetCurAction(); + const ULONG nCount = Count(); + + if( nPos > nCount ) + nPos = nCount; + + for( ULONG nCurPos = GetCurPos(); nCurPos < nPos; nCurPos++ ) + { + if( !Hook() ) + { + pAction->Duplicate(); + rMtf.AddAction( pAction ); + } + + pAction = (MetaAction*) Next(); + } + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Play( OutputDevice* pOut, ULONG nPos ) +{ + if( !bRecord ) + { + MetaAction* pAction = GetCurAction(); + const ULONG nCount = Count(); + ULONG i = 0, nSyncCount = ( pOut->GetOutDevType() == OUTDEV_WINDOW ) ? 0x000000ff : 0xffffffff; + + if( nPos > nCount ) + nPos = nCount; + + for( ULONG nCurPos = GetCurPos(); nCurPos < nPos; nCurPos++ ) + { + if( !Hook() ) + { + pAction->Execute( pOut ); + + // flush output from time to time + if( i++ > nSyncCount ) + ( (Window*) pOut )->Flush(), i = 0; + } + + pAction = (MetaAction*) Next(); + } + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Play( OutputDevice* pOut, const Point& rPos, + const Size& rSize, ULONG nPos ) +{ + Region aDrawClipRegion; + MapMode aDrawMap( GetPrefMapMode() ); + Size aDestSize( pOut->LogicToPixel( rSize ) ); + + if( aDestSize.Width() && aDestSize.Height() ) + { + Size aTmpPrefSize( pOut->LogicToPixel( GetPrefSize(), aDrawMap ) ); + GDIMetaFile* pMtf = pOut->GetConnectMetaFile(); + + if( !aTmpPrefSize.Width() ) + aTmpPrefSize.Width() = aDestSize.Width(); + + if( !aTmpPrefSize.Height() ) + aTmpPrefSize.Height() = aDestSize.Height(); + + Fraction aScaleX( aDestSize.Width(), aTmpPrefSize.Width() ); + Fraction aScaleY( aDestSize.Height(), aTmpPrefSize.Height() ); + + aScaleX *= aDrawMap.GetScaleX(); aDrawMap.SetScaleX( aScaleX ); + aScaleY *= aDrawMap.GetScaleY(); aDrawMap.SetScaleY( aScaleY ); + + aDrawMap.SetOrigin( pOut->PixelToLogic( pOut->LogicToPixel( rPos ), aDrawMap ) ); + + pOut->Push(); + + if ( pMtf && pMtf->IsRecord() && ( pOut->GetOutDevType() != OUTDEV_PRINTER ) ) + pOut->SetRelativeMapMode( aDrawMap ); + else + pOut->SetMapMode( aDrawMap ); + + Play( pOut, nPos ); + + pOut->Pop(); + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Pause( BOOL _bPause ) +{ + if( bRecord ) + { + if( _bPause ) + { + if( !bPause ) + Linker( pOutDev, FALSE ); + } + else + { + if( bPause ) + Linker( pOutDev, TRUE ); + } + + bPause = _bPause; + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Stop() +{ + if( bRecord ) + { + bRecord = FALSE; + + if( !bPause ) + Linker( pOutDev, FALSE ); + else + bPause = FALSE; + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::WindStart() +{ + if( !bRecord ) + First(); +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::WindEnd() +{ + if( !bRecord ) + Last(); +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Wind( ULONG nActionPos ) +{ + if( !bRecord ) + Seek( nActionPos ); +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::WindPrev() +{ + if( !bRecord ) + Prev(); +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::WindNext() +{ + if( !bRecord ) + Next(); +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::AddAction( MetaAction* pAction ) +{ + Insert( pAction, LIST_APPEND ); + + if( pPrev ) + { + pAction->Duplicate(); + pPrev->AddAction( pAction ); + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::AddAction( MetaAction* pAction, ULONG nPos ) +{ + Insert( pAction, nPos ); + + if( pPrev ) + { + pAction->Duplicate(); + pPrev->AddAction( pAction, nPos ); + } +} + +// ------------------------------------------------------------------------ + +MetaAction* GDIMetaFile::CopyAction( ULONG nPos ) const +{ + return ( (MetaAction*) GetObject( nPos ) )->Clone(); +} + +// ------------------------------------------------------------------------ + +ULONG GDIMetaFile::GetActionPos( const String& rLabel ) +{ + ImpLabel* pLabel = NULL; + + if( pLabelList ) + pLabel = pLabelList->ImplGetLabel( pLabelList->ImplGetLabelPos( rLabel ) ); + else + pLabel = NULL; + + return( pLabel ? pLabel->nActionPos : METAFILE_LABEL_NOTFOUND ); +} + +// ------------------------------------------------------------------------ + +BOOL GDIMetaFile::InsertLabel( const String& rLabel, ULONG nActionPos ) +{ + BOOL bRet = FALSE; + + if( !pLabelList ) + pLabelList = new ImpLabelList; + + if( pLabelList->ImplGetLabelPos( rLabel ) == METAFILE_LABEL_NOTFOUND ) + { + pLabelList->ImplInsert( new ImpLabel( rLabel, nActionPos ) ); + bRet = TRUE; + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::RemoveLabel( const String& rLabel ) +{ + if( pLabelList ) + { + const ULONG nLabelPos = pLabelList->ImplGetLabelPos( rLabel ); + + if( nLabelPos != METAFILE_LABEL_NOTFOUND ) + delete pLabelList->ImplRemove( nLabelPos ); + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::RenameLabel( const String& rLabel, const String& rNewLabel ) +{ + if( pLabelList ) + { + const ULONG nLabelPos = pLabelList->ImplGetLabelPos( rLabel ); + + if ( nLabelPos != METAFILE_LABEL_NOTFOUND ) + pLabelList->ImplGetLabel( nLabelPos )->aLabelName = rNewLabel; + } +} + +// ------------------------------------------------------------------------ + +ULONG GDIMetaFile::GetLabelCount() const +{ + return( pLabelList ? pLabelList->ImplCount() : 0UL ); +} + +// ------------------------------------------------------------------------ + +String GDIMetaFile::GetLabel( ULONG nLabel ) +{ + String aString; + + if( pLabelList ) + { + const ImpLabel* pLabel = pLabelList->ImplGetLabel( nLabel ); + + if( pLabel ) + aString = pLabel->aLabelName; + } + + return aString; +} + +// ------------------------------------------------------------------------ + +BOOL GDIMetaFile::SaveStatus() +{ + if ( bRecord ) + { + if ( bPause ) + Linker( pOutDev, TRUE ); + + AddAction( new MetaLineColorAction( pOutDev->GetLineColor(), + pOutDev->IsLineColor() ) ); + AddAction( new MetaFillColorAction( pOutDev->GetFillColor(), + pOutDev->IsFillColor() ) ); + AddAction( new MetaFontAction( pOutDev->GetFont() ) ); + AddAction( new MetaTextColorAction( pOutDev->GetTextColor() ) ); + AddAction( new MetaTextFillColorAction( pOutDev->GetTextFillColor(), + pOutDev->IsTextFillColor() ) ); + AddAction( new MetaTextLineColorAction( pOutDev->GetTextLineColor(), + pOutDev->IsTextLineColor() ) ); + AddAction( new MetaTextAlignAction( pOutDev->GetTextAlign() ) ); + AddAction( new MetaRasterOpAction( pOutDev->GetRasterOp() ) ); + AddAction( new MetaMapModeAction( pOutDev->GetMapMode() ) ); + AddAction( new MetaClipRegionAction( pOutDev->GetClipRegion(), + pOutDev->IsClipRegion() ) ); + + if ( bPause ) + Linker( pOutDev, FALSE ); + + return TRUE; + } + else + return FALSE; +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Move( long nX, long nY ) +{ + for( MetaAction* pAct = (MetaAction*) First(); pAct; pAct = (MetaAction*) Next() ) + { + MetaAction* pModAct; + + if( pAct->GetRefCount() > 1 ) + { + Replace( pModAct = pAct->Clone(), pAct ); + pAct->Delete(); + } + else + pModAct = pAct; + + pModAct->Move( nX, nY ); + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Scale( double fScaleX, double fScaleY ) +{ + for( MetaAction* pAct = (MetaAction*) First(); pAct; pAct = (MetaAction*) Next() ) + { + MetaAction* pModAct; + + if( pAct->GetRefCount() > 1 ) + { + Replace( pModAct = pAct->Clone(), pAct ); + pAct->Delete(); + } + else + pModAct = pAct; + + pModAct->Scale( fScaleX, fScaleY ); + } + + aPrefSize.Width() = FRound( aPrefSize.Width() * fScaleX ); + aPrefSize.Height() = FRound( aPrefSize.Height() * fScaleY ); +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Scale( const Fraction& rScaleX, const Fraction& rScaleY ) +{ + Scale( (double) rScaleX, (double) rScaleY ); +} + +// ------------------------------------------------------------------------ + +Color GDIMetaFile::ImplColAdjustFnc( const Color& rColor, const void* pColParam ) +{ + return Color( rColor.GetTransparency(), + ( (const ImplColAdjustParam*) pColParam )->pMapR[ rColor.GetRed() ], + ( (const ImplColAdjustParam*) pColParam )->pMapG[ rColor.GetGreen() ], + ( (const ImplColAdjustParam*) pColParam )->pMapB[ rColor.GetBlue() ] ); + +} + +// ------------------------------------------------------------------------ + +BitmapEx GDIMetaFile::ImplBmpAdjustFnc( const BitmapEx& rBmpEx, const void* pBmpParam ) +{ + const ImplBmpAdjustParam* p = (const ImplBmpAdjustParam*) pBmpParam; + BitmapEx aRet( rBmpEx ); + + aRet.Adjust( p->nLuminancePercent, p->nContrastPercent, + p->nChannelRPercent, p->nChannelGPercent, p->nChannelBPercent, + p->fGamma, p->bInvert ); + + return aRet; +} + +// ------------------------------------------------------------------------ + +Color GDIMetaFile::ImplColConvertFnc( const Color& rColor, const void* pColParam ) +{ + BYTE cLum = rColor.GetLuminance(); + + if( MTF_CONVERSION_1BIT_THRESHOLD == ( (const ImplColConvertParam*) pColParam )->eConversion ) + cLum = ( cLum < 128 ) ? 0 : 255; + + return Color( rColor.GetTransparency(), cLum, cLum, cLum ); +} + +// ------------------------------------------------------------------------ + +BitmapEx GDIMetaFile::ImplBmpConvertFnc( const BitmapEx& rBmpEx, const void* pBmpParam ) +{ + BitmapEx aRet( rBmpEx ); + + aRet.Convert( ( (const ImplBmpConvertParam*) pBmpParam )->eConversion ); + + return aRet; +} + +// ------------------------------------------------------------------------ + +Color GDIMetaFile::ImplColMonoFnc( const Color& rColor, const void* pColParam ) +{ + return( ( (const ImplColMonoParam*) pColParam )->aColor ); +} + +// ------------------------------------------------------------------------ + +BitmapEx GDIMetaFile::ImplBmpMonoFnc( const BitmapEx& rBmpEx, const void* pBmpParam ) +{ + BitmapPalette aPal( 3 ); + + aPal[ 0 ] = Color( COL_BLACK ); + aPal[ 1 ] = Color( COL_WHITE ); + aPal[ 2 ] = ( (const ImplBmpMonoParam*) pBmpParam )->aColor; + + Bitmap aBmp( rBmpEx.GetSizePixel(), 4, &aPal ); + aBmp.Erase( ( (const ImplBmpMonoParam*) pBmpParam )->aColor ); + + if( rBmpEx.IsAlpha() ) + return BitmapEx( aBmp, rBmpEx.GetAlpha() ); + else if( rBmpEx.IsTransparent() ) + return BitmapEx( aBmp, rBmpEx.GetMask() ); + else + return aBmp; +} + +// ------------------------------------------------------------------------ + +Color GDIMetaFile::ImplColReplaceFnc( const Color& rColor, const void* pColParam ) +{ + const ULONG nR = rColor.GetRed(), nG = rColor.GetGreen(), nB = rColor.GetBlue(); + + for( ULONG i = 0; i < ( (const ImplColReplaceParam*) pColParam )->nCount; i++ ) + { + if( ( ( (const ImplColReplaceParam*) pColParam )->pMinR[ i ] <= nR ) && + ( ( (const ImplColReplaceParam*) pColParam )->pMaxR[ i ] >= nR ) && + ( ( (const ImplColReplaceParam*) pColParam )->pMinG[ i ] <= nG ) && + ( ( (const ImplColReplaceParam*) pColParam )->pMaxG[ i ] >= nG ) && + ( ( (const ImplColReplaceParam*) pColParam )->pMinB[ i ] <= nB ) && + ( ( (const ImplColReplaceParam*) pColParam )->pMaxB[ i ] >= nB ) ) + { + return( ( (const ImplColReplaceParam*) pColParam )->pDstCols[ i ] ); + } + } + + return rColor; +} + +// ------------------------------------------------------------------------ + +BitmapEx GDIMetaFile::ImplBmpReplaceFnc( const BitmapEx& rBmpEx, const void* pBmpParam ) +{ + const ImplBmpReplaceParam* p = (const ImplBmpReplaceParam*) pBmpParam; + BitmapEx aRet( rBmpEx ); + + aRet.Replace( p->pSrcCols, p->pDstCols, p->nCount, p->pTols ); + + return aRet; +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::ImplExchangeColors( ColorExchangeFnc pFncCol, const void* pColParam, + BmpExchangeFnc pFncBmp, const void* pBmpParam ) +{ + GDIMetaFile aMtf; + + aMtf.aPrefSize = aPrefSize; + aMtf.aPrefMapMode = aPrefMapMode; + + for( MetaAction* pAction = (MetaAction*) First(); pAction; pAction = (MetaAction*) Next() ) + { + const USHORT nType = pAction->GetType(); + + switch( nType ) + { + case( META_PIXEL_ACTION ): + { + MetaPixelAction* pAct = (MetaPixelAction*) pAction; + aMtf.Insert( new MetaPixelAction( pAct->GetPoint(), pFncCol( pAct->GetColor(), pColParam ) ), LIST_APPEND ); + } + break; + + case( META_LINECOLOR_ACTION ): + { + MetaLineColorAction* pAct = (MetaLineColorAction*) pAction; + + if( !pAct->IsSetting() ) + pAct->Duplicate(); + else + pAct = new MetaLineColorAction( pFncCol( pAct->GetColor(), pColParam ), TRUE ); + + aMtf.Insert( pAct, LIST_APPEND ); + } + break; + + case( META_FILLCOLOR_ACTION ): + { + MetaFillColorAction* pAct = (MetaFillColorAction*) pAction; + + if( !pAct->IsSetting() ) + pAct->Duplicate(); + else + pAct = new MetaFillColorAction( pFncCol( pAct->GetColor(), pColParam ), TRUE ); + + aMtf.Insert( pAct, LIST_APPEND ); + } + break; + + case( META_TEXTCOLOR_ACTION ): + { + MetaTextColorAction* pAct = (MetaTextColorAction*) pAction; + aMtf.Insert( new MetaTextColorAction( pFncCol( pAct->GetColor(), pColParam ) ), LIST_APPEND ); + } + break; + + case( META_TEXTFILLCOLOR_ACTION ): + { + MetaTextFillColorAction* pAct = (MetaTextFillColorAction*) pAction; + + if( !pAct->IsSetting() ) + pAct->Duplicate(); + else + pAct = new MetaTextFillColorAction( pFncCol( pAct->GetColor(), pColParam ), TRUE ); + + aMtf.Insert( pAct, LIST_APPEND ); + } + break; + + case( META_TEXTLINECOLOR_ACTION ): + { + MetaTextLineColorAction* pAct = (MetaTextLineColorAction*) pAction; + + if( !pAct->IsSetting() ) + pAct->Duplicate(); + else + pAct = new MetaTextLineColorAction( pFncCol( pAct->GetColor(), pColParam ), TRUE ); + + aMtf.Insert( pAct, LIST_APPEND ); + } + break; + + case( META_FONT_ACTION ): + { + MetaFontAction* pAct = (MetaFontAction*) pAction; + Font aFont( pAct->GetFont() ); + + aFont.SetColor( pFncCol( aFont.GetColor(), pColParam ) ); + aFont.SetFillColor( pFncCol( aFont.GetFillColor(), pColParam ) ); + aMtf.Insert( new MetaFontAction( aFont ), LIST_APPEND ); + } + break; + + case( META_WALLPAPER_ACTION ): + { + MetaWallpaperAction* pAct = (MetaWallpaperAction*) pAction; + Wallpaper aWall( pAct->GetWallpaper() ); + const Rectangle& rRect = pAct->GetRect(); + + aWall.SetColor( pFncCol( aWall.GetColor(), pColParam ) ); + + if( aWall.IsBitmap() ) + aWall.SetBitmap( pFncBmp( aWall.GetBitmap(), pBmpParam ) ); + + if( aWall.IsGradient() ) + { + Gradient aGradient( aWall.GetGradient() ); + + aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) ); + aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) ); + aWall.SetGradient( aGradient ); + } + + aMtf.Insert( new MetaWallpaperAction( rRect, aWall ), LIST_APPEND ); + } + break; + + case( META_BMP_ACTION ): + case( META_BMPEX_ACTION ): + case( META_MASK_ACTION ): + { + DBG_ERROR( "Don't use bitmap actions of this type in metafiles!" ); + } + break; + + case( META_BMPSCALE_ACTION ): + { + MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction; + aMtf.Insert( new MetaBmpScaleAction( pAct->GetPoint(), pAct->GetSize(), + pFncBmp( pAct->GetBitmap(), pBmpParam ).GetBitmap() ), + LIST_APPEND ); + } + break; + + case( META_BMPSCALEPART_ACTION ): + { + MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction; + aMtf.Insert( new MetaBmpScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(), + pAct->GetSrcPoint(), pAct->GetSrcSize(), + pFncBmp( pAct->GetBitmap(), pBmpParam ).GetBitmap() ), + LIST_APPEND ); + } + break; + + case( META_BMPEXSCALE_ACTION ): + { + MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction; + aMtf.Insert( new MetaBmpExScaleAction( pAct->GetPoint(), pAct->GetSize(), + pFncBmp( pAct->GetBitmapEx(), pBmpParam ) ), + LIST_APPEND ); + } + break; + + case( META_BMPEXSCALEPART_ACTION ): + { + MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction; + aMtf.Insert( new MetaBmpExScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(), + pAct->GetSrcPoint(), pAct->GetSrcSize(), + pFncBmp( pAct->GetBitmapEx(), pBmpParam ) ), + LIST_APPEND ); + } + break; + + case( META_MASKSCALE_ACTION ): + { + MetaMaskScaleAction* pAct = (MetaMaskScaleAction*) pAction; + aMtf.Insert( new MetaMaskScaleAction( pAct->GetPoint(), pAct->GetSize(), + pAct->GetBitmap(), + pFncCol( pAct->GetColor(), pColParam ) ), + LIST_APPEND ); + } + break; + + case( META_MASKSCALEPART_ACTION ): + { + MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction; + aMtf.Insert( new MetaMaskScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(), + pAct->GetSrcPoint(), pAct->GetSrcSize(), + pAct->GetBitmap(), + pFncCol( pAct->GetColor(), pColParam ) ), + LIST_APPEND ); + } + break; + + case( META_GRADIENT_ACTION ): + { + MetaGradientAction* pAct = (MetaGradientAction*) pAction; + Gradient aGradient( pAct->GetGradient() ); + + aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) ); + aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) ); + aMtf.Insert( new MetaGradientAction( pAct->GetRect(), aGradient ), LIST_APPEND ); + } + break; + + case( META_GRADIENTEX_ACTION ): + { + MetaGradientExAction* pAct = (MetaGradientExAction*) pAction; + Gradient aGradient( pAct->GetGradient() ); + + aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) ); + aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) ); + aMtf.Insert( new MetaGradientExAction( pAct->GetPolyPolygon(), aGradient ), LIST_APPEND ); + } + break; + + case( META_HATCH_ACTION ): + { + MetaHatchAction* pAct = (MetaHatchAction*) pAction; + Hatch aHatch( pAct->GetHatch() ); + + aHatch.SetColor( pFncCol( aHatch.GetColor(), pColParam ) ); + aMtf.Insert( new MetaHatchAction( pAct->GetPolyPolygon(), aHatch ), LIST_APPEND ); + } + break; + + case( META_FLOATTRANSPARENT_ACTION ): + { + MetaFloatTransparentAction* pAct = (MetaFloatTransparentAction*) pAction; + GDIMetaFile aTransMtf( pAct->GetGDIMetaFile() ); + + aTransMtf.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam ); + aMtf.Insert( new MetaFloatTransparentAction( aTransMtf, + pAct->GetPoint(), pAct->GetSize(), + pAct->GetGradient() ), + LIST_APPEND ); + } + break; + + case( META_EPS_ACTION ): + { + MetaEPSAction* pAct = (MetaEPSAction*) pAction; + GDIMetaFile aSubst( pAct->GetSubstitute() ); + + aSubst.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam ); + aMtf.Insert( new MetaEPSAction( pAct->GetPoint(), pAct->GetSize(), + pAct->GetLink(), aSubst ), + LIST_APPEND ); + } + break; + + default: + { + pAction->Duplicate(); + aMtf.Insert( pAction, LIST_APPEND ); + } + break; + } + } + + *this = aMtf; +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Adjust( short nLuminancePercent, short nContrastPercent, + short nChannelRPercent, short nChannelGPercent, + short nChannelBPercent, double fGamma, BOOL bInvert ) +{ + // nothing to do? => return quickly + if( nLuminancePercent || nContrastPercent || + nChannelRPercent || nChannelGPercent || nChannelBPercent || + ( fGamma != 1.0 ) || bInvert ) + { + double fM, fROff, fGOff, fBOff, fOff; + ImplColAdjustParam aColParam; + ImplBmpAdjustParam aBmpParam; + + aColParam.pMapR = new BYTE[ 256 ]; + aColParam.pMapG = new BYTE[ 256 ]; + aColParam.pMapB = new BYTE[ 256 ]; + + // calculate slope + if( nContrastPercent >= 0 ) + fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) ); + else + fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0; + + // total offset = luminance offset + contrast offset + fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0; + + // channel offset = channel offset + total offset + fROff = nChannelRPercent * 2.55 + fOff; + fGOff = nChannelGPercent * 2.55 + fOff; + fBOff = nChannelBPercent * 2.55 + fOff; + + // calculate gamma value + fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma ); + const BOOL bGamma = ( fGamma != 1.0 ); + + // create mapping table + for( long nX = 0L; nX < 256L; nX++ ) + { + aColParam.pMapR[ nX ] = (BYTE) MinMax( FRound( nX * fM + fROff ), 0L, 255L ); + aColParam.pMapG[ nX ] = (BYTE) MinMax( FRound( nX * fM + fGOff ), 0L, 255L ); + aColParam.pMapB[ nX ] = (BYTE) MinMax( FRound( nX * fM + fBOff ), 0L, 255L ); + + if( bGamma ) + { + aColParam.pMapR[ nX ] = GAMMA( aColParam.pMapR[ nX ], fGamma ); + aColParam.pMapG[ nX ] = GAMMA( aColParam.pMapG[ nX ], fGamma ); + aColParam.pMapB[ nX ] = GAMMA( aColParam.pMapB[ nX ], fGamma ); + } + + if( bInvert ) + { + aColParam.pMapR[ nX ] = ~aColParam.pMapR[ nX ]; + aColParam.pMapG[ nX ] = ~aColParam.pMapG[ nX ]; + aColParam.pMapB[ nX ] = ~aColParam.pMapB[ nX ]; + } + } + + aBmpParam.nLuminancePercent = nLuminancePercent; + aBmpParam.nContrastPercent = nContrastPercent; + aBmpParam.nChannelRPercent = nChannelRPercent; + aBmpParam.nChannelGPercent = nChannelGPercent; + aBmpParam.nChannelBPercent = nChannelBPercent; + aBmpParam.fGamma = fGamma; + aBmpParam.bInvert = bInvert; + + // do color adjustment + ImplExchangeColors( ImplColAdjustFnc, &aColParam, ImplBmpAdjustFnc, &aBmpParam ); + + delete[] aColParam.pMapR; + delete[] aColParam.pMapG; + delete[] aColParam.pMapB; + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Convert( MtfConversion eConversion ) +{ + // nothing to do? => return quickly + if( eConversion != MTF_CONVERSION_NONE ) + { + ImplColConvertParam aColParam; + ImplBmpConvertParam aBmpParam; + + aColParam.eConversion = eConversion; + aBmpParam.eConversion = ( MTF_CONVERSION_1BIT_THRESHOLD == eConversion ) ? BMP_CONVERSION_1BIT_THRESHOLD : BMP_CONVERSION_8BIT_GREYS; + + ImplExchangeColors( ImplColConvertFnc, &aColParam, ImplBmpConvertFnc, &aBmpParam ); + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::ReplaceColors( const Color& rSearchColor, const Color& rReplaceColor, ULONG nTol ) +{ + ReplaceColors( &rSearchColor, &rReplaceColor, 1, &nTol ); +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::ReplaceColors( const Color* pSearchColors, const Color* pReplaceColors, ULONG nColorCount, ULONG* pTols ) +{ + ImplColReplaceParam aColParam; + ImplBmpReplaceParam aBmpParam; + + aColParam.pMinR = new ULONG[ nColorCount ]; + aColParam.pMaxR = new ULONG[ nColorCount ]; + aColParam.pMinG = new ULONG[ nColorCount ]; + aColParam.pMaxG = new ULONG[ nColorCount ]; + aColParam.pMinB = new ULONG[ nColorCount ]; + aColParam.pMaxB = new ULONG[ nColorCount ]; + + for( ULONG i = 0; i < nColorCount; i++ ) + { + const long nTol = pTols ? ( pTols[ i ] * 255 ) / 100 : 0; + long nVal; + + nVal = pSearchColors[ i ].GetRed(); + aColParam.pMinR[ i ] = (ULONG) Max( nVal - nTol, 0L ); + aColParam.pMaxR[ i ] = (ULONG) Min( nVal + nTol, 255L ); + + nVal = pSearchColors[ i ].GetGreen(); + aColParam.pMinG[ i ] = (ULONG) Max( nVal - nTol, 0L ); + aColParam.pMaxG[ i ] = (ULONG) Min( nVal + nTol, 255L ); + + nVal = pSearchColors[ i ].GetBlue(); + aColParam.pMinB[ i ] = (ULONG) Max( nVal - nTol, 0L ); + aColParam.pMaxB[ i ] = (ULONG) Min( nVal + nTol, 255L ); + } + + aColParam.pDstCols = pReplaceColors; + aColParam.nCount = nColorCount; + + aBmpParam.pSrcCols = pSearchColors; + aBmpParam.pDstCols = pReplaceColors; + aBmpParam.nCount = nColorCount; + aBmpParam.pTols = pTols; + + ImplExchangeColors( ImplColReplaceFnc, &aColParam, ImplBmpReplaceFnc, &aBmpParam ); + + delete[] aColParam.pMinR; + delete[] aColParam.pMaxR; + delete[] aColParam.pMinG; + delete[] aColParam.pMaxG; + delete[] aColParam.pMinB; + delete[] aColParam.pMaxB; +}; + +// ------------------------------------------------------------------------ + +GDIMetaFile GDIMetaFile::GetMonochromeMtf( const Color& rColor ) const +{ + GDIMetaFile aRet( *this ); + + ImplColMonoParam aColParam; + ImplBmpMonoParam aBmpParam; + + aColParam.aColor = rColor; + aBmpParam.aColor = rColor; + + aRet.ImplExchangeColors( ImplColMonoFnc, &aColParam, ImplBmpMonoFnc, &aBmpParam ); + + return aRet; +} + +// ------------------------------------------------------------------------ + +ULONG GDIMetaFile::GetChecksum() const +{ + GDIMetaFile aMtf; + SvMemoryStream aMemStm( 65535, 65535 ); + ImplMetaWriteData aWriteData; aWriteData.meActualCharSet = aMemStm.GetStreamCharSet(); + SVBT16 aBT16; + SVBT32 aBT32; + ULONG nCrc = 0; + + for( ULONG i = 0, nCount = GetActionCount(); i < nCount; i++ ) + { + MetaAction* pAction = GetAction( i ); + + switch( pAction->GetType() ) + { + case( META_BMP_ACTION ): + { + MetaBmpAction* pAct = (MetaBmpAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + LongToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + case( META_BMPSCALE_ACTION ): + { + MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + LongToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + case( META_BMPSCALEPART_ACTION ): + { + MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + LongToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetDestPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetDestPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetDestSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetDestSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSrcPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSrcPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSrcSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSrcSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + case( META_BMPEX_ACTION ): + { + MetaBmpExAction* pAct = (MetaBmpExAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + LongToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + case( META_BMPEXSCALE_ACTION ): + { + MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + LongToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + case( META_BMPEXSCALEPART_ACTION ): + { + MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + LongToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetDestPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetDestPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetDestSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetDestSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSrcPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSrcPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSrcSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSrcSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + case( META_MASK_ACTION ): + { + MetaMaskAction* pAct = (MetaMaskAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + LongToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetColor().GetColor(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + case( META_MASKSCALE_ACTION ): + { + MetaMaskScaleAction* pAct = (MetaMaskScaleAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + LongToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetColor().GetColor(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + case( META_MASKSCALEPART_ACTION ): + { + MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + LongToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetColor().GetColor(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetDestPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetDestPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetDestSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetDestSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSrcPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSrcPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSrcSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + LongToSVBT32( pAct->GetSrcSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + default: + { + pAction->Write( aMemStm, &aWriteData ); + nCrc = rtl_crc32( nCrc, aMemStm.GetData(), aMemStm.Tell() ); + aMemStm.Seek( 0 ); + } + break; + } + } + + return nCrc; +} + +// ------------------------------------------------------------------------ + +SvStream& operator>>( SvStream& rIStm, GDIMetaFile& rGDIMetaFile ) +{ + if( !rIStm.GetError() ) + { + char aId[ 7 ]; + ULONG nStmPos = rIStm.Tell(); + USHORT nOldFormat = rIStm.GetNumberFormatInt(); + BOOL bError = FALSE; + + rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + + rIStm.Read( aId, 6 ); + aId[ 6 ] = 0; + + if ( !strcmp( aId, "VCLMTF" ) ) + { + // new format + VersionCompat* pCompat; + MetaAction* pAction; + UINT32 nStmCompressMode; + UINT32 nCount; + + pCompat = new VersionCompat( rIStm, STREAM_READ ); + + rIStm >> nStmCompressMode; + rIStm >> rGDIMetaFile.aPrefMapMode; + rIStm >> rGDIMetaFile.aPrefSize; + rIStm >> nCount; + + delete pCompat; + + ImplMetaReadData aReadData; + aReadData.meActualCharSet = rIStm.GetStreamCharSet(); + + for( UINT32 nAction = 0UL; ( nAction < nCount ) && !rIStm.IsEof(); nAction++ ) + { + pAction = MetaAction::ReadMetaAction( rIStm, &aReadData ); + + if( pAction ) + rGDIMetaFile.AddAction( pAction ); + } + } + else + { + // to avoid possible compiler optimizations => new/delete + rIStm.Seek( nStmPos ); + delete( new SVMConverter( rIStm, rGDIMetaFile, CONVERT_FROM_SVM1 ) ); + } + + // check for errors + if( rIStm.GetError() ) + { + rGDIMetaFile.Clear(); + rIStm.Seek( nStmPos ); + } + + rIStm.SetNumberFormatInt( nOldFormat ); + } + + return rIStm; +} + +// ------------------------------------------------------------------------ + +SvStream& operator<<( SvStream& rOStm, const GDIMetaFile& rGDIMetaFile ) +{ + if( !rOStm.GetError() ) + { + if( rOStm.GetVersion() >= SOFFICE_FILEFORMAT_50 ) + ((GDIMetaFile&) rGDIMetaFile ).Write( rOStm ); + else + delete( new SVMConverter( rOStm, (GDIMetaFile&) rGDIMetaFile, CONVERT_TO_SVM1 ) ); + } + + return rOStm; +} + +// ------------------------------------------------------------------------ + +SvStream& GDIMetaFile::Read( SvStream& rIStm ) +{ + Clear(); + rIStm >> *this; + + return rIStm; +} + +// ------------------------------------------------------------------------ + +SvStream& GDIMetaFile::Write( SvStream& rOStm ) +{ + VersionCompat* pCompat; + const UINT32 nStmCompressMode = rOStm.GetCompressMode(); + USHORT nOldFormat = rOStm.GetNumberFormatInt(); + + rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + rOStm.Write( "VCLMTF", 6 ); + + pCompat = new VersionCompat( rOStm, STREAM_WRITE, 1 ); + + rOStm << nStmCompressMode; + rOStm << aPrefMapMode; + rOStm << aPrefSize; + rOStm << (UINT32) GetActionCount(); + + delete pCompat; + + ImplMetaWriteData aWriteData; + aWriteData.meActualCharSet = rOStm.GetStreamCharSet(); + + MetaAction* pAct = (MetaAction*)First(); + while ( pAct ) + { + pAct->Write( rOStm, &aWriteData ); + pAct = (MetaAction*)Next(); + } + + rOStm.SetNumberFormatInt( nOldFormat ); + + return rOStm; +} diff --git a/vcl/source/gdi/gfxlink.cxx b/vcl/source/gdi/gfxlink.cxx new file mode 100644 index 000000000000..3a175017708e --- /dev/null +++ b/vcl/source/gdi/gfxlink.cxx @@ -0,0 +1,450 @@ +/************************************************************************* + * + * $RCSfile: gfxlink.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <tools/vcompat.hxx> +#include <tools/urlobj.hxx> +#include <tools/debug.hxx> +#include <tools/tempfile.hxx> +#include <ucbhelper/content.hxx> +#include "graph.hxx" +#include "gfxlink.hxx" +#include "cvtgrf.hxx" + +// ----------- +// - GfxLink - +// ----------- + +GfxLink::GfxLink() : + meType ( GFX_LINK_TYPE_NONE ), + mnBufSize ( 0 ), + mpBuf ( NULL ), + mpSwap ( NULL ), + mnUserId ( 0UL ) +{ +} + +// ------------------------------------------------------------------------ + +GfxLink::GfxLink( const GfxLink& rGfxLink ) +{ + ImplCopy( rGfxLink ); +} + +// ------------------------------------------------------------------------ + +GfxLink::GfxLink( const String& rPath, GfxLinkType nType ) +{ + sal_Int64 nFileSize = 0; + + try + { + ::ucb::Content aCnt( INetURLObject( rPath, INET_PROT_FILE ).GetMainURL(), + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); + + aCnt.getPropertyValue( ::rtl::OUString::createFromAscii( "Size" ) ) >>= nFileSize; + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + DBG_ERRORFILE( "CommandAbortedException" ); + } + catch( ... ) + { + DBG_ERRORFILE( "Any other exception" ); + } + + meType = nType; + mnBufSize = nFileSize; + mpSwap = NULL; + mnUserId = 0UL; + + if( mnBufSize ) + { + SvFileStream aFileStream( rPath, STREAM_READ ); + + mpBuf = new ImpBuffer( mnBufSize ); + aFileStream.Read( mpBuf->mpBuffer, mnBufSize ); + } + else + mpBuf = NULL; +} + +// ------------------------------------------------------------------------ + +GfxLink::GfxLink( BYTE* pBuf, ULONG nSize, GfxLinkType nType, BOOL bOwns ) +{ + meType = nType; + mnBufSize = nSize; + mpSwap = NULL; + mnUserId = 0UL; + + if( bOwns ) + mpBuf = new ImpBuffer( pBuf ); + else if( nSize ) + { + mpBuf = new ImpBuffer( nSize ); + memcpy( mpBuf->mpBuffer, pBuf, nSize ); + } + else + mpBuf = NULL; +} + +// ------------------------------------------------------------------------ + +GfxLink::~GfxLink() +{ + if( mpBuf && !( --mpBuf->mnRefCount ) ) + delete mpBuf; + + if( mpSwap && !( --mpSwap->mnRefCount ) ) + delete mpSwap; +} + +// ------------------------------------------------------------------------ + +GfxLink& GfxLink::operator=( const GfxLink& rGfxLink ) +{ + if( &rGfxLink != this ) + { + if ( mpBuf && !( --mpBuf->mnRefCount ) ) + delete mpBuf; + + if( mpSwap && !( --mpSwap->mnRefCount ) ) + delete mpSwap; + + ImplCopy( rGfxLink ); + } + + return *this; +} + +// ------------------------------------------------------------------------ + +void GfxLink::ImplCopy( const GfxLink& rGfxLink ) +{ + mnBufSize = rGfxLink.mnBufSize; + meType = rGfxLink.meType; + mpBuf = rGfxLink.mpBuf; + mpSwap = rGfxLink.mpSwap; + mnUserId = rGfxLink.mnUserId; + + if( mpBuf ) + mpBuf->mnRefCount++; + + if( mpSwap ) + mpSwap->mnRefCount++; +} + +// ------------------------------------------------------------------------ + +GfxLinkType GfxLink::GetType() const +{ + return meType; +} + +// ------------------------------------------------------------------------ + +BOOL GfxLink::IsNative() const +{ + return( meType >= GFX_LINK_FIRST_NATIVE_ID && meType <= GFX_LINK_LAST_NATIVE_ID ); +} + +// ------------------------------------------------------------------------ + +ULONG GfxLink::GetDataSize() const +{ + return mnBufSize; +} + +// ------------------------------------------------------------------------ + +const BYTE* GfxLink::GetData() const +{ + if( IsSwappedOut() ) + ( (GfxLink*) this )->SwapIn(); + + return( mpBuf ? mpBuf->mpBuffer : NULL ); +} + +// ------------------------------------------------------------------------ + +BOOL GfxLink::LoadNative( Graphic& rGraphic ) +{ + BOOL bRet = FALSE; + + if( IsNative() && mnBufSize ) + { + const BYTE* pData = GetData(); + + if( pData ) + { + SvMemoryStream aMemStm; + ULONG nCvtType; + + aMemStm.SetBuffer( (char*) pData, mnBufSize, FALSE, mnBufSize ); + + switch( meType ) + { + case( GFX_LINK_TYPE_NATIVE_GIF ): nCvtType = CVT_GIF; break; + case( GFX_LINK_TYPE_NATIVE_JPG ): nCvtType = CVT_JPG; break; + case( GFX_LINK_TYPE_NATIVE_PNG ): nCvtType = CVT_PNG; break; + case( GFX_LINK_TYPE_NATIVE_TIF ): nCvtType = CVT_TIF; break; + case( GFX_LINK_TYPE_NATIVE_WMF ): nCvtType = CVT_WMF; break; + case( GFX_LINK_TYPE_NATIVE_MET ): nCvtType = CVT_MET; break; + case( GFX_LINK_TYPE_NATIVE_PCT ): nCvtType = CVT_PCT; break; + + default: nCvtType = CVT_UNKNOWN; break; + } + + if( nCvtType && ( GraphicConverter::Import( aMemStm, rGraphic, nCvtType ) == ERRCODE_NONE ) ) + bRet = TRUE; + } + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +void GfxLink::SwapOut() +{ + if( !IsSwappedOut() && mpBuf ) + { + mpSwap = new ImpSwap( mpBuf->mpBuffer, mnBufSize ); + + if( !mpSwap->IsSwapped() ) + { + delete mpSwap; + mpSwap = NULL; + } + else if( !( --mpBuf->mnRefCount ) ) + delete mpBuf; + + mpBuf = NULL; + } +} + +// ------------------------------------------------------------------------ + +void GfxLink::SwapIn() +{ + if( IsSwappedOut() ) + { + mpBuf = new ImpBuffer( mpSwap->GetData() ); + + if( !( --mpSwap->mnRefCount ) ) + delete mpSwap; + + mpSwap = NULL; + } +} + +// ------------------------------------------------------------------------ + +SvStream& operator<<( SvStream& rOStream, const GfxLink& rGfxLink ) +{ + VersionCompat* pCompat = new VersionCompat( rOStream, STREAM_WRITE, 1 ); + + rOStream << (UINT16) rGfxLink.GetType() << rGfxLink.GetDataSize() << rGfxLink.GetUserId(); + + delete pCompat; + + if( rGfxLink.GetDataSize() ) + { + if( rGfxLink.IsSwappedOut() ) + rGfxLink.mpSwap->WriteTo( rOStream ); + else + rOStream.Write( rGfxLink.GetData(), rGfxLink.GetDataSize() ); + } + + return rOStream; +} + +// ------------------------------------------------------------------------ + +SvStream& operator>>( SvStream& rIStream, GfxLink& rGfxLink) +{ + ULONG nSize; + ULONG nUserId; + UINT16 nType; + BYTE* pBuf; + VersionCompat* pCompat = new VersionCompat( rIStream, STREAM_READ ); + + rIStream >> nType >> nSize >> nUserId; + + delete pCompat; + + pBuf = new BYTE[ nSize ]; + rIStream.Read( pBuf, nSize ); + + rGfxLink = GfxLink( pBuf, nSize, (GfxLinkType) nType, TRUE ); + rGfxLink.SetUserId( nUserId ); + + return rIStream; +} + +// ----------- +// - ImpSwap - +// ----------- + +ImpSwap::ImpSwap( BYTE* pData, ULONG nDataSize ) : + mnDataSize( nDataSize ), + mnRefCount( 1UL ) +{ + if( pData && mnDataSize ) + { + maFileName = TempFile::CreateTempName(); + + if( maFileName.Len() ) + { + SvFileStream aOStm( maFileName, STREAM_WRITE | STREAM_SHARE_DENYWRITE ); + + aOStm.Write( pData, mnDataSize ); + + if( aOStm.GetError() ) + { + aOStm.Close(); + + try + { + ::ucb::Content aCnt( INetURLObject( maFileName, INET_PROT_FILE ).GetMainURL(), + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); + + aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ), + ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) ); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + DBG_ERRORFILE( "CommandAbortedException" ); + } + catch( ... ) + { + DBG_ERRORFILE( "Any other exception" ); + } + + maFileName.Erase(); + } + } + } +} + +// ------------------------------------------------------------------------ + +ImpSwap::~ImpSwap() +{ + if( IsSwapped() ) + { + try + { + ::ucb::Content aCnt( INetURLObject( maFileName, INET_PROT_FILE ).GetMainURL(), + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); + + aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ), + ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) ); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + DBG_ERRORFILE( "CommandAbortedException" ); + } + catch( ... ) + { + DBG_ERRORFILE( "Any other exception" ); + } + } +} + +// ------------------------------------------------------------------------ + +BYTE* ImpSwap::GetData() const +{ + BYTE* pData; + + if( IsSwapped() ) + { + SvFileStream aIStm( maFileName, STREAM_READ ); + + pData = new BYTE[ mnDataSize ]; + aIStm.Read( pData, mnDataSize ); + + if( aIStm.GetError() ) + { + aIStm.Close(); + delete[] pData; + pData = NULL; + } + } + else + pData = NULL; + + return pData; +} + +// ------------------------------------------------------------------------ + +void ImpSwap::WriteTo( SvStream& rOStm ) const +{ + BYTE* pData = GetData(); + + if( pData ) + { + rOStm.Write( pData, mnDataSize ); + delete[] pData; + } +} diff --git a/vcl/source/gdi/gradient.cxx b/vcl/source/gdi/gradient.cxx new file mode 100644 index 000000000000..7a6489f9c8e6 --- /dev/null +++ b/vcl/source/gdi/gradient.cxx @@ -0,0 +1,386 @@ +/************************************************************************* + * + * $RCSfile: gradient.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_GRADIENT_CXX + +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif +#ifndef _VCOMPAT_HXX +#include <tools/vcompat.hxx> +#endif +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _SV_GRADIENT_HXX +#include <gradient.hxx> +#endif + +// ======================================================================= + +DBG_NAME( Gradient ); + +// ----------------------------------------------------------------------- + +Impl_Gradient::Impl_Gradient() : + maStartColor( COL_BLACK ), + maEndColor( COL_WHITE ) +{ + mnRefCount = 1; + meStyle = GRADIENT_LINEAR; + mnAngle = 0; + mnBorder = 0; + mnOfsX = 50; + mnOfsY = 50; + mnIntensityStart = 100; + mnIntensityEnd = 100; + mnStepCount = 0; +} + +// ----------------------------------------------------------------------- + +Impl_Gradient::Impl_Gradient( const Impl_Gradient& rImplGradient ) : + maStartColor( rImplGradient.maStartColor ), + maEndColor( rImplGradient.maEndColor ) +{ + mnRefCount = 1; + meStyle = rImplGradient.meStyle; + mnAngle = rImplGradient.mnAngle; + mnBorder = rImplGradient.mnBorder; + mnOfsX = rImplGradient.mnOfsX; + mnOfsY = rImplGradient.mnOfsY; + mnIntensityStart = rImplGradient.mnIntensityStart; + mnIntensityEnd = rImplGradient.mnIntensityEnd; + mnStepCount = rImplGradient.mnStepCount; +} + +// ----------------------------------------------------------------------- + +void Gradient::MakeUnique() +{ + // Falls noch andere Referenzen bestehen, dann kopieren + if ( mpImplGradient->mnRefCount != 1 ) + { + if( mpImplGradient->mnRefCount ) + mpImplGradient->mnRefCount--; + + mpImplGradient = new Impl_Gradient( *mpImplGradient ); + } +} + +// ----------------------------------------------------------------------- + +Gradient::Gradient() +{ + DBG_CTOR( Gradient, NULL ); + + mpImplGradient = new Impl_Gradient; +} + +// ----------------------------------------------------------------------- + +Gradient::Gradient( const Gradient& rGradient ) +{ + DBG_CTOR( Gradient, NULL ); + DBG_CHKOBJ( &rGradient, Gradient, NULL ); + + // Instance Daten uebernehmen und Referenzcounter erhoehen + mpImplGradient = rGradient.mpImplGradient; + mpImplGradient->mnRefCount++; +} + +// ----------------------------------------------------------------------- + +Gradient::Gradient( GradientStyle eStyle ) +{ + DBG_CTOR( Gradient, NULL ); + + mpImplGradient = new Impl_Gradient; + mpImplGradient->meStyle = eStyle; +} + +// ----------------------------------------------------------------------- + +Gradient::Gradient( GradientStyle eStyle, + const Color& rStartColor, const Color& rEndColor ) +{ + DBG_CTOR( Gradient, NULL ); + + mpImplGradient = new Impl_Gradient; + mpImplGradient->meStyle = eStyle; + mpImplGradient->maStartColor = rStartColor; + mpImplGradient->maEndColor = rEndColor; +} + +// ----------------------------------------------------------------------- + +Gradient::~Gradient() +{ + DBG_DTOR( Gradient, NULL ); + + // Wenn es die letzte Referenz ist, loeschen, + // sonst Referenzcounter decrementieren + if ( mpImplGradient->mnRefCount == 1 ) + delete mpImplGradient; + else + mpImplGradient->mnRefCount--; +} + +// ----------------------------------------------------------------------- + +void Gradient::SetStyle( GradientStyle eStyle ) +{ + DBG_CHKTHIS( Gradient, NULL ); + + MakeUnique(); + mpImplGradient->meStyle = eStyle; +} + +// ----------------------------------------------------------------------- + +void Gradient::SetStartColor( const Color& rColor ) +{ + DBG_CHKTHIS( Gradient, NULL ); + + MakeUnique(); + mpImplGradient->maStartColor = rColor; +} + +// ----------------------------------------------------------------------- + +void Gradient::SetEndColor( const Color& rColor ) +{ + DBG_CHKTHIS( Gradient, NULL ); + + MakeUnique(); + mpImplGradient->maEndColor = rColor; +} + +// ----------------------------------------------------------------------- + +void Gradient::SetAngle( USHORT nAngle ) +{ + DBG_CHKTHIS( Gradient, NULL ); + + MakeUnique(); + mpImplGradient->mnAngle = nAngle; +} + +// ----------------------------------------------------------------------- + +void Gradient::SetBorder( USHORT nBorder ) +{ + DBG_CHKTHIS( Gradient, NULL ); + + MakeUnique(); + mpImplGradient->mnBorder = nBorder; +} + +// ----------------------------------------------------------------------- + +void Gradient::SetOfsX( USHORT nOfsX ) +{ + DBG_CHKTHIS( Gradient, NULL ); + + MakeUnique(); + mpImplGradient->mnOfsX = nOfsX; +} + +// ----------------------------------------------------------------------- + +void Gradient::SetOfsY( USHORT nOfsY ) +{ + DBG_CHKTHIS( Gradient, NULL ); + + MakeUnique(); + mpImplGradient->mnOfsY = nOfsY; +} + +// ----------------------------------------------------------------------- + +void Gradient::SetStartIntensity( USHORT nIntens ) +{ + DBG_CHKTHIS( Gradient, NULL ); + + MakeUnique(); + mpImplGradient->mnIntensityStart = nIntens; +} + +// ----------------------------------------------------------------------- + +void Gradient::SetEndIntensity( USHORT nIntens ) +{ + DBG_CHKTHIS( Gradient, NULL ); + + MakeUnique(); + mpImplGradient->mnIntensityEnd = nIntens; +} + +// ----------------------------------------------------------------------- + +void Gradient::SetSteps( USHORT nSteps ) +{ + DBG_CHKTHIS( Gradient, NULL ); + + MakeUnique(); + mpImplGradient->mnStepCount = nSteps; +} + +// ----------------------------------------------------------------------- + +Gradient& Gradient::operator=( const Gradient& rGradient ) +{ + DBG_CHKTHIS( Gradient, NULL ); + DBG_CHKOBJ( &rGradient, Gradient, NULL ); + + // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann + rGradient.mpImplGradient->mnRefCount++; + + // Wenn es die letzte Referenz ist, loeschen, + // sonst Referenzcounter decrementieren + if ( mpImplGradient->mnRefCount == 1 ) + delete mpImplGradient; + else + mpImplGradient->mnRefCount--; + mpImplGradient = rGradient.mpImplGradient; + + return *this; +} + +// ----------------------------------------------------------------------- + +BOOL Gradient::operator==( const Gradient& rGradient ) const +{ + DBG_CHKTHIS( Gradient, NULL ); + DBG_CHKOBJ( &rGradient, Gradient, NULL ); + + if ( mpImplGradient == rGradient.mpImplGradient ) + return TRUE; + + if ( (mpImplGradient->meStyle == rGradient.mpImplGradient->meStyle) || + (mpImplGradient->mnAngle == rGradient.mpImplGradient->mnAngle) || + (mpImplGradient->mnBorder == rGradient.mpImplGradient->mnBorder) || + (mpImplGradient->mnOfsX == rGradient.mpImplGradient->mnOfsX) || + (mpImplGradient->mnOfsY == rGradient.mpImplGradient->mnOfsY) || + (mpImplGradient->mnStepCount == rGradient.mpImplGradient->mnStepCount) || + (mpImplGradient->mnIntensityStart == rGradient.mpImplGradient->mnIntensityStart) || + (mpImplGradient->mnIntensityEnd == rGradient.mpImplGradient->mnIntensityEnd) || + (mpImplGradient->maStartColor == rGradient.mpImplGradient->maStartColor) || + (mpImplGradient->maEndColor == rGradient.mpImplGradient->maEndColor) ) + return TRUE; + else + return FALSE; +} + +SvStream& operator>>( SvStream& rIStm, Impl_Gradient& rImpl_Gradient ) +{ + VersionCompat aCompat( rIStm, STREAM_READ ); + UINT16 nTmp16; + + rIStm >> nTmp16; rImpl_Gradient.meStyle = (GradientStyle) nTmp16; + + rIStm >> rImpl_Gradient.maStartColor >> + rImpl_Gradient.maEndColor >> + rImpl_Gradient.mnAngle >> + rImpl_Gradient.mnBorder >> + rImpl_Gradient.mnOfsX >> + rImpl_Gradient.mnOfsY >> + rImpl_Gradient.mnIntensityStart >> + rImpl_Gradient.mnIntensityEnd >> + rImpl_Gradient.mnStepCount; + + return rIStm; +} + +// ----------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rOStm, const Impl_Gradient& rImpl_Gradient ) +{ + VersionCompat aCompat( rOStm, STREAM_WRITE, 1 ); + + rOStm << (UINT16) rImpl_Gradient.meStyle << + rImpl_Gradient.maStartColor << + rImpl_Gradient.maEndColor << + rImpl_Gradient.mnAngle << + rImpl_Gradient.mnBorder << + rImpl_Gradient.mnOfsX << + rImpl_Gradient.mnOfsY << + rImpl_Gradient.mnIntensityStart << + rImpl_Gradient.mnIntensityEnd << + rImpl_Gradient.mnStepCount; + + return rOStm; +} + +// ----------------------------------------------------------------------- + +SvStream& operator>>( SvStream& rIStm, Gradient& rGradient ) +{ + rGradient.MakeUnique(); + return( rIStm >> *rGradient.mpImplGradient ); +} + +// ----------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rOStm, const Gradient& rGradient ) +{ + return( rOStm << *rGradient.mpImplGradient ); +} diff --git a/vcl/source/gdi/graph.cxx b/vcl/source/gdi/graph.cxx new file mode 100644 index 000000000000..3c847d7dd916 --- /dev/null +++ b/vcl/source/gdi/graph.cxx @@ -0,0 +1,832 @@ +/************************************************************************* + * + * $RCSfile: graph.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_GRAPH_CXX + +#ifndef _SV_CLIP_HXX +#include <clip.hxx> +#endif +#ifndef _SV_IMPGRAPH_HXX +#include <impgraph.hxx> +#endif +#ifndef _SV_OUTDEV_HXX +#include <outdev.hxx> +#endif +#ifndef _SV_CLIP_HXX +#include <clip.hxx> +#endif +#ifndef _SV_DRAG_HXX +#include <drag.hxx> +#endif +#include <graph.hxx> + +// ----------------------- +// - Compression defines - +// ----------------------- + +#define COMPRESS_OWN ('S'|('D'<<8UL)) +#define COMPRESS_NONE ( 0UL ) +#define RLE_8 ( 1UL ) +#define RLE_4 ( 2UL ) +#define BITFIELDS ( 3UL ) +#define ZCOMPRESS ( COMPRESS_OWN | 0x01000000UL ) /* == 'SD01' (binary) */ + +// ----------------------- +// - Default-Drawmethode - +// ----------------------- + +static void ImplDrawDefault( OutputDevice* pOutDev, const UniString* pText, + Font* pFont, const Bitmap* pBitmap, + const Point& rDestPt, const Size& rDestSize ) +{ + USHORT nPixel = (USHORT) pOutDev->PixelToLogic( Size( 1, 1 ) ).Width(); + USHORT nWidth = nPixel; + Point aPoint( rDestPt.X() + nWidth, rDestPt.Y() + nWidth ); + Size aSize( rDestSize.Width() - ( nWidth << 1 ), rDestSize.Height() - ( nWidth << 1 ) ); + BOOL bFilled = ( pBitmap != NULL || pFont != NULL ); + Rectangle aBorderRect( aPoint, aSize ); + + pOutDev->Push(); + + pOutDev->SetFillColor(); + + // Auf dem Drucker ein schwarzes Rechteck und auf dem Bildschirm eins mit 3D-Effekt + if ( pOutDev->GetOutDevType() == OUTDEV_PRINTER ) + pOutDev->SetLineColor( COL_BLACK ); + else + { + aBorderRect.Left() += nPixel; + aBorderRect.Top() += nPixel; + + pOutDev->SetLineColor( COL_LIGHTGRAY ); + pOutDev->DrawRect( aBorderRect ); + + aBorderRect.Left() -= nPixel; + aBorderRect.Top() -= nPixel; + aBorderRect.Right() -= nPixel; + aBorderRect.Bottom() -= nPixel; + pOutDev->SetLineColor( COL_GRAY ); + } + + pOutDev->DrawRect( aBorderRect ); + + aPoint.X() += nWidth + 2*nPixel; + aPoint.Y() += nWidth + 2*nPixel; + aSize.Width() -= 2*nWidth + 4*nPixel; + aSize.Height() -= 2*nWidth + 4*nPixel; + + if( aSize.Width() > 0 && aSize.Height() > 0 && pBitmap && !!*pBitmap ) + { + Size aBitmapSize( pOutDev->PixelToLogic(pBitmap->GetSizePixel() ) ); + + if( aSize.Height() > aBitmapSize.Height() && aSize.Width() > aBitmapSize.Width() ) + { + pOutDev->DrawBitmap( aPoint, *pBitmap ); + aPoint.X() += aBitmapSize.Width() + 2*nPixel; + aSize.Width() -= aBitmapSize.Width() + 2*nPixel; + } + } + + if ( aSize.Width() > 0 && aSize.Height() > 0 && pFont && pText && pText->Len() + && !(!pOutDev->IsOutputEnabled() /*&& pOutDev->GetConnectMetaFile() */) ) + { + MapMode aMapMode( MAP_POINT ); + Size aSz = pOutDev->LogicToLogic( Size( 0, 12 ), &aMapMode, NULL ); + long nThreshold = aSz.Height() / 2; + long nStep = nThreshold / 3; + + if ( !nStep ) + nStep = aSz.Height() - nThreshold; + + for(;; aSz.Height() -= nStep ) + { + pFont->SetSize( aSz ); + pOutDev->SetFont( *pFont ); + + long nTextHeight = pOutDev->GetTextHeight(); + long nTextWidth = pOutDev->GetTextWidth( *pText ); + if ( nTextHeight ) + { + // Die N"aherung ber"ucksichtigt keine Ungenauigkeiten durch + // Wortumbr"uche + long nLines = aSize.Height() / nTextHeight; + long nWidth = aSize.Width() * nLines; // N"aherung!!! + + if ( nTextWidth <= nWidth || aSz.Height() <= nThreshold ) + { + USHORT nStart = 0; + USHORT nLen = 0; + + while( nStart < pText->Len() && pText->GetChar( nStart ) == ' ' ) + nStart++; + while( nStart+nLen < pText->Len() && pText->GetChar( nStart+nLen ) != ' ' ) + nLen++; + while( nStart < pText->Len() && nLines-- ) + { + USHORT nNext = nLen; + do + { + while ( nStart+nNext < pText->Len() && pText->GetChar( nStart+nNext ) == ' ' ) + nNext++; + while ( nStart+nNext < pText->Len() && pText->GetChar( nStart+nNext ) != ' ' ) + nNext++; + nTextWidth = pOutDev->GetTextWidth( *pText, nStart, nNext ); + if ( nTextWidth > aSize.Width() ) + break; + nLen = nNext; + } + while ( nStart+nNext < pText->Len() ); + + USHORT n = nLen; + nTextWidth = pOutDev->GetTextWidth( *pText, nStart, n ); + while( nTextWidth > aSize.Width() ) + nTextWidth = pOutDev->GetTextWidth( *pText, nStart, --n ); + pOutDev->DrawText( aPoint, *pText, nStart, n ); + + aPoint.Y() += nTextHeight; + nStart += nLen; + nLen = nNext-nLen; + while( nStart < pText->Len() && pText->GetChar( nStart ) == ' ' ) + { + nStart++; + nLen--; + } + } + break; + } + } + else + break; + } + } + + // Falls die Default-Graphik keinen Inhalt hat, + // malen wir ein rotes Kreuz + if( !bFilled ) + { + aBorderRect.Left()++; + aBorderRect.Top()++; + aBorderRect.Right()--; + aBorderRect.Bottom()--; + + pOutDev->SetLineColor( COL_LIGHTRED ); + pOutDev->DrawLine( aBorderRect.TopLeft(), aBorderRect.BottomRight() ); + pOutDev->DrawLine( aBorderRect.TopRight(), aBorderRect.BottomLeft() ); + } + + pOutDev->Pop(); +} + +// ----------- +// - Graphic - +// ----------- + +TYPEINIT1_AUTOFACTORY( Graphic, SvDataCopyStream ); + +// ------------------------------------------------------------------------ + +Graphic::Graphic() +{ + mpImpGraphic = new ImpGraphic; +} + +// ------------------------------------------------------------------------ + +Graphic::Graphic( const Graphic& rGraphic ) +{ + if( rGraphic.IsAnimated() ) + mpImpGraphic = new ImpGraphic( *rGraphic.mpImpGraphic ); + else + { + mpImpGraphic = rGraphic.mpImpGraphic; + mpImpGraphic->mnRefCount++; + } +} + +// ------------------------------------------------------------------------ + +Graphic::Graphic( const Bitmap& rBmp ) +{ + mpImpGraphic = new ImpGraphic( rBmp ); +} + +// ------------------------------------------------------------------------ + +Graphic::Graphic( const BitmapEx& rBmpEx ) +{ + mpImpGraphic = new ImpGraphic( rBmpEx ); +} + +// ------------------------------------------------------------------------ + +Graphic::Graphic( const Animation& rAnimation ) +{ + mpImpGraphic = new ImpGraphic( rAnimation ); +} + +// ------------------------------------------------------------------------ + +Graphic::Graphic( const GDIMetaFile& rMtf ) +{ + mpImpGraphic = new ImpGraphic( rMtf ); +} + +// ------------------------------------------------------------------------ + +Graphic::~Graphic() +{ + if( mpImpGraphic->mnRefCount == 1UL ) + delete mpImpGraphic; + else + mpImpGraphic->mnRefCount--; +} + +// ------------------------------------------------------------------------ + +void Graphic::ImplTestRefCount() +{ + if( mpImpGraphic->mnRefCount > 1UL ) + { + mpImpGraphic->mnRefCount--; + mpImpGraphic = new ImpGraphic( *mpImpGraphic ); + } +} + +// ------------------------------------------------------------------------ + +Graphic& Graphic::operator=( const Graphic& rGraphic ) +{ + if( &rGraphic != this ) + { + if( rGraphic.IsAnimated() ) + { + if( mpImpGraphic->mnRefCount == 1UL ) + delete mpImpGraphic; + else + mpImpGraphic->mnRefCount--; + + mpImpGraphic = new ImpGraphic( *rGraphic.mpImpGraphic ); + } + else + { + rGraphic.mpImpGraphic->mnRefCount++; + + if( mpImpGraphic->mnRefCount == 1UL ) + delete mpImpGraphic; + else + mpImpGraphic->mnRefCount--; + + mpImpGraphic = rGraphic.mpImpGraphic; + } + } + + return *this; +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::operator==( const Graphic& rGraphic ) const +{ + return( *mpImpGraphic == *rGraphic.mpImpGraphic ); +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::operator!=( const Graphic& rGraphic ) const +{ + return( *mpImpGraphic != *rGraphic.mpImpGraphic ); +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::operator!() const +{ + return( GRAPHIC_NONE == mpImpGraphic->ImplGetType() ); +} + +// ------------------------------------------------------------------------ + +void Graphic::Load( SvStream& rIStm ) +{ + rIStm >> *this; +} + +// ------------------------------------------------------------------------ + +void Graphic::Save( SvStream& rOStm ) +{ + rOStm << *this; +} + +// ------------------------------------------------------------------------ + +void Graphic::Assign( const SvDataCopyStream& rCopyStream ) +{ + *this = (const Graphic& ) rCopyStream; +} + +// ------------------------------------------------------------------------ + +void Graphic::Clear() +{ + ImplTestRefCount(); + mpImpGraphic->ImplClear(); +} + +// ------------------------------------------------------------------------ + +GraphicType Graphic::GetType() const +{ + return mpImpGraphic->ImplGetType(); +} + +// ------------------------------------------------------------------------ + +void Graphic::SetDefaultType() +{ + ImplTestRefCount(); + mpImpGraphic->ImplSetDefaultType(); +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::IsSupportedGraphic() const +{ + return mpImpGraphic->ImplIsSupportedGraphic(); +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::IsTransparent() const +{ + return mpImpGraphic->ImplIsTransparent(); +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::IsAlpha() const +{ + return mpImpGraphic->ImplIsAlpha(); +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::IsAnimated() const +{ + return mpImpGraphic->ImplIsAnimated(); +} + +// ------------------------------------------------------------------------ + +Bitmap Graphic::GetBitmap() const +{ + return mpImpGraphic->ImplGetBitmap(); +} + +// ------------------------------------------------------------------------ + +BitmapEx Graphic::GetBitmapEx() const +{ + return mpImpGraphic->ImplGetBitmapEx(); +} + +// ------------------------------------------------------------------------ + +Animation Graphic::GetAnimation() const +{ + return mpImpGraphic->ImplGetAnimation(); +} + +// ------------------------------------------------------------------------ + +const GDIMetaFile& Graphic::GetGDIMetaFile() const +{ + return mpImpGraphic->ImplGetGDIMetaFile(); +} + +// ------------------------------------------------------------------------ + +Size Graphic::GetPrefSize() const +{ + return mpImpGraphic->ImplGetPrefSize(); +} + +// ------------------------------------------------------------------------ + +void Graphic::SetPrefSize( const Size& rPrefSize ) +{ + ImplTestRefCount(); + mpImpGraphic->ImplSetPrefSize( rPrefSize ); +} + +// ------------------------------------------------------------------------ + +MapMode Graphic::GetPrefMapMode() const +{ + return mpImpGraphic->ImplGetPrefMapMode(); +} + +// ------------------------------------------------------------------------ + +void Graphic::SetPrefMapMode( const MapMode& rPrefMapMode ) +{ + ImplTestRefCount(); + mpImpGraphic->ImplSetPrefMapMode( rPrefMapMode ); +} + +// ------------------------------------------------------------------ + +ULONG Graphic::GetSizeBytes() const +{ + return mpImpGraphic->ImplGetSizeBytes(); +} + +// ------------------------------------------------------------------------ + +void Graphic::Draw( OutputDevice* pOutDev, const Point& rDestPt ) const +{ + mpImpGraphic->ImplDraw( pOutDev, rDestPt ); +} + +// ------------------------------------------------------------------------ + +void Graphic::Draw( OutputDevice* pOutDev, + const Point& rDestPt, const Size& rDestSz ) const +{ + if( GRAPHIC_DEFAULT == mpImpGraphic->ImplGetType() ) + ImplDrawDefault( pOutDev, NULL, NULL, NULL, rDestPt, rDestSz ); + else + mpImpGraphic->ImplDraw( pOutDev, rDestPt, rDestSz ); +} + +// ------------------------------------------------------------------------ + +void Graphic::Draw( OutputDevice* pOutDev, const String& rText, + Font& rFont, const Bitmap& rBitmap, + const Point& rDestPt, const Size& rDestSz ) +{ + ImplDrawDefault( pOutDev, &rText, &rFont, &rBitmap, rDestPt, rDestSz ); +} + +// ------------------------------------------------------------------------ + +void Graphic::StartAnimation( OutputDevice* pOutDev, const Point& rDestPt, long nExtraData, + OutputDevice* pFirstFrameOutDev ) +{ + ImplTestRefCount(); + mpImpGraphic->ImplStartAnimation( pOutDev, rDestPt, nExtraData, pFirstFrameOutDev ); +} + +// ------------------------------------------------------------------------ + +void Graphic::StartAnimation( OutputDevice* pOutDev, const Point& rDestPt, + const Size& rDestSz, long nExtraData, + OutputDevice* pFirstFrameOutDev ) +{ + ImplTestRefCount(); + mpImpGraphic->ImplStartAnimation( pOutDev, rDestPt, rDestSz, nExtraData, pFirstFrameOutDev ); +} + +// ------------------------------------------------------------------------ + +void Graphic::StopAnimation( OutputDevice* pOutDev, long nExtraData ) +{ + ImplTestRefCount(); + mpImpGraphic->ImplStopAnimation( pOutDev, nExtraData ); +} + +// ------------------------------------------------------------------------ + +void Graphic::SetAnimationNotifyHdl( const Link& rLink ) +{ + mpImpGraphic->ImplSetAnimationNotifyHdl( rLink ); +} + +// ------------------------------------------------------------------------ + +Link Graphic::GetAnimationNotifyHdl() const +{ + return mpImpGraphic->ImplGetAnimationNotifyHdl(); +} + +// ------------------------------------------------------------------------ + +ULONG Graphic::GetAnimationLoopCount() const +{ + return mpImpGraphic->ImplGetAnimationLoopCount(); +} + +// ------------------------------------------------------------------------ + +void Graphic::ResetAnimationLoopCount() +{ + mpImpGraphic->ImplResetAnimationLoopCount(); +} + +// ------------------------------------------------------------------------ + +List* Graphic::GetAnimationInfoList() const +{ + return mpImpGraphic->ImplGetAnimationInfoList(); +} + +// ------------------------------------------------------------------------ + +GraphicReader* Graphic::GetContext() +{ + return mpImpGraphic->ImplGetContext(); +} + +// ------------------------------------------------------------------------ + +void Graphic::SetContext( GraphicReader* pReader ) +{ + mpImpGraphic->ImplSetContext( pReader ); +} + +// ------------------------------------------------------------------------ + +USHORT Graphic::GetGraphicsCompressMode( SvStream& rIStm ) +{ + const ULONG nPos = rIStm.Tell(); + const USHORT nOldFormat = rIStm.GetNumberFormatInt(); + UINT32 nTmp32; + UINT16 nTmp16; + USHORT nCompressMode = COMPRESSMODE_NONE; + + rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + + rIStm >> nTmp32; + + // is it a swapped graphic with a bitmap? + rIStm.SeekRel( (nTmp32 == (UINT32) GRAPHIC_BITMAP ) ? 40 : -4 ); + + // try to read bitmap id + rIStm >> nTmp16; + + // check id of BitmapFileHeader + if( 0x4D42 == nTmp16 ) + { + // seek to compress field of BitmapInfoHeader + rIStm.SeekRel( 28 ); + rIStm >> nTmp32; + + // Compare with our own compressmode + if( ZCOMPRESS == nTmp32 ) + nCompressMode = COMPRESSMODE_ZBITMAP; + } + + rIStm.SetNumberFormatInt( nOldFormat ); + rIStm.Seek( nPos ); + + return nCompressMode; +} + +// ------------------------------------------------------------------------ + +void Graphic::SetDocFileName( const String& rName, ULONG nFilePos ) +{ + mpImpGraphic->ImplSetDocFileName( rName, nFilePos ); +} + +// ------------------------------------------------------------------------ + +const String& Graphic::GetDocFileName() const +{ + return mpImpGraphic->ImplGetDocFileName(); +} + +// ------------------------------------------------------------------------ + +ULONG Graphic::GetDocFilePos() const +{ + return mpImpGraphic->ImplGetDocFilePos(); +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::ReadEmbedded( SvStream& rIStream, BOOL bSwap ) +{ + ImplTestRefCount(); + return mpImpGraphic->ImplReadEmbedded( rIStream, bSwap ); +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::WriteEmbedded( SvStream& rOStream ) +{ + ImplTestRefCount(); + return mpImpGraphic->ImplWriteEmbedded( rOStream ); +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::SwapOut() +{ + ImplTestRefCount(); + return mpImpGraphic->ImplSwapOut(); +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::SwapOut( SvStream* pOStream ) +{ + ImplTestRefCount(); + return mpImpGraphic->ImplSwapOut( pOStream ); +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::SwapIn() +{ + ImplTestRefCount(); + return mpImpGraphic->ImplSwapIn(); +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::SwapIn( SvStream* pStrm ) +{ + ImplTestRefCount(); + return mpImpGraphic->ImplSwapIn( pStrm ); +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::IsSwapOut() const +{ + return mpImpGraphic->ImplIsSwapOut(); +} + +// ------------------------------------------------------------------------ + +void Graphic::SetLink( const GfxLink& rGfxLink ) +{ + ImplTestRefCount(); + mpImpGraphic->ImplSetLink( rGfxLink ); +} + +// ------------------------------------------------------------------------ + +GfxLink Graphic::GetLink() +{ + return mpImpGraphic->ImplGetLink(); +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::IsLink() const +{ + return mpImpGraphic->ImplIsLink(); +} + +// ------------------------------------------------------------------------ + +ULONG Graphic::GetChecksum() const +{ + return mpImpGraphic->ImplGetChecksum(); +} + +// ------------------------------------------------------------------------ + +SvStream& operator>>( SvStream& rIStream, Graphic& rGraphic ) +{ + rGraphic.ImplTestRefCount(); + return rIStream >> *rGraphic.mpImpGraphic; +} + +// ------------------------------------------------------------------------ + +SvStream& operator<<( SvStream& rOStream, const Graphic& rGraphic ) +{ + return rOStream << *rGraphic.mpImpGraphic; +} + +// ------------------------------------------------------------------------ + +ULONG Graphic::RegisterClipboardFormatName() +{ + static ULONG nFormat = 0; + + if ( !nFormat ) + nFormat = Clipboard::RegisterFormatName( XubString( RTL_CONSTASCII_USTRINGPARAM( "SVXB (StarView Bitmap/Animation)" ) ) ); + + return nFormat; +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::ClipboardHasFormat() +{ + return Clipboard::HasFormat( RegisterClipboardFormatName() ) + || Clipboard::HasFormat( FORMAT_GDIMETAFILE ) + || Clipboard::HasFormat( FORMAT_BITMAP ); +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::DragServerHasFormat( USHORT nItem ) +{ + return DragServer::HasFormat( nItem, RegisterClipboardFormatName() ) + || DragServer::HasFormat( nItem, FORMAT_GDIMETAFILE ) + || DragServer::HasFormat( nItem, FORMAT_BITMAP ); +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::Copy() const +{ + SotDataMemberObjectRef aDataObject = new SotDataMemberObject; + SvData* pData = new SvData( RegisterClipboardFormatName() ); + + pData->SetData( (SvDataCopyStream*) this, TRANSFER_COPY ); + aDataObject->Append( pData ); + VclClipboard::Copy( aDataObject ); + + return TRUE; +} + +// ------------------------------------------------------------------------ + +BOOL Graphic::Paste() +{ + const ULONG nFormat = RegisterClipboardFormatName(); + BOOL bRet = FALSE; + + if( VclClipboard::HasFormat( nFormat ) ) + { + SotDataObjectRef aDataObject = VclClipboard::Paste(); + SvData aData( nFormat ); + + if( aDataObject.Is() && aDataObject->GetData( &aData ) ) + { + Graphic* pGraphic = NULL; + + if( aData.GetData( (SvDataCopyStream**) &pGraphic, StaticType(), TRANSFER_MOVE ) ) + *this = *pGraphic; + + delete pGraphic; + bRet = TRUE; + } + } + + return bRet; +} diff --git a/vcl/source/gdi/hatch.cxx b/vcl/source/gdi/hatch.cxx new file mode 100644 index 000000000000..ac66e89fd0cf --- /dev/null +++ b/vcl/source/gdi/hatch.cxx @@ -0,0 +1,262 @@ +/************************************************************************* + * + * $RCSfile: hatch.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_HATCH_CXX + +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif +#ifndef _VCOMPAT_HXX +#include <tools/vcompat.hxx> +#endif +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _SV_HATCX_HXX +#include <hatch.hxx> +#endif + +DBG_NAME( Hatch ); + +// -------------- +// - ImplHatch - +// -------------- + +ImplHatch::ImplHatch() : + mnRefCount ( 1 ), + maColor ( COL_BLACK ), + meStyle ( HATCH_SINGLE ), + mnDistance ( 1 ), + mnAngle ( 0 ) +{ +} + +// ----------------------------------------------------------------------- + +ImplHatch::ImplHatch( const ImplHatch& rImplHatch ) : + mnRefCount ( 1 ), + maColor ( rImplHatch.maColor ), + meStyle ( rImplHatch.meStyle ), + mnDistance ( rImplHatch.mnDistance ), + mnAngle ( rImplHatch.mnAngle ) +{ +} + +// --------- +// - Hatch - +// --------- + +Hatch::Hatch() +{ + DBG_CTOR( Hatch, NULL ); + mpImplHatch = new ImplHatch; +} + +// ----------------------------------------------------------------------- + +Hatch::Hatch( const Hatch& rHatch ) +{ + DBG_CTOR( Hatch, NULL ); + DBG_CHKOBJ( &rHatch, Hatch, NULL ); + mpImplHatch = rHatch.mpImplHatch; + mpImplHatch->mnRefCount++; +} + +// ----------------------------------------------------------------------- + +Hatch::Hatch( HatchStyle eStyle, const Color& rColor, + long nDistance, USHORT nAngle10 ) +{ + DBG_CTOR( Hatch, NULL ); + mpImplHatch = new ImplHatch; + mpImplHatch->maColor = rColor; + mpImplHatch->meStyle = eStyle; + mpImplHatch->mnDistance = nDistance; + mpImplHatch->mnAngle = nAngle10; +} + +// ----------------------------------------------------------------------- + +Hatch::~Hatch() +{ + DBG_DTOR( Hatch, NULL ); + if( !( --mpImplHatch->mnRefCount ) ) + delete mpImplHatch; +} + +// ----------------------------------------------------------------------- + +Hatch& Hatch::operator=( const Hatch& rHatch ) +{ + DBG_CHKTHIS( Hatch, NULL ); + DBG_CHKOBJ( &rHatch, Hatch, NULL ); + + rHatch.mpImplHatch->mnRefCount++; + + if( !( --mpImplHatch->mnRefCount ) ) + delete mpImplHatch; + + mpImplHatch = rHatch.mpImplHatch; + return *this; +} + +// ----------------------------------------------------------------------- + +BOOL Hatch::operator==( const Hatch& rHatch ) const +{ + DBG_CHKTHIS( Hatch, NULL ); + DBG_CHKOBJ( &rHatch, Hatch, NULL ); + + return( mpImplHatch == rHatch.mpImplHatch || + ( mpImplHatch->maColor == rHatch.mpImplHatch->maColor && + mpImplHatch->meStyle == rHatch.mpImplHatch->meStyle && + mpImplHatch->mnDistance == rHatch.mpImplHatch->mnDistance && + mpImplHatch->mnAngle == rHatch.mpImplHatch->mnAngle ) ); +} + +// ----------------------------------------------------------------------- + +void Hatch::ImplMakeUnique() +{ + if( mpImplHatch->mnRefCount != 1 ) + { + if( mpImplHatch->mnRefCount ) + mpImplHatch->mnRefCount--; + + mpImplHatch = new ImplHatch( *mpImplHatch ); + } +} + +// ----------------------------------------------------------------------- + +void Hatch::SetStyle( HatchStyle eStyle ) +{ + DBG_CHKTHIS( Hatch, NULL ); + ImplMakeUnique(); + mpImplHatch->meStyle = eStyle; +} + +// ----------------------------------------------------------------------- + +void Hatch::SetColor( const Color& rColor ) +{ + DBG_CHKTHIS( Hatch, NULL ); + ImplMakeUnique(); + mpImplHatch->maColor = rColor; +} + +// ----------------------------------------------------------------------- + +void Hatch::SetDistance( long nDistance ) +{ + DBG_CHKTHIS( Hatch, NULL ); + ImplMakeUnique(); + mpImplHatch->mnDistance = nDistance; +} + +// ----------------------------------------------------------------------- + +void Hatch::SetAngle( USHORT nAngle10 ) +{ + DBG_CHKTHIS( Hatch, NULL ); + ImplMakeUnique(); + mpImplHatch->mnAngle = nAngle10; +} + +// ----------------------------------------------------------------------- + +SvStream& operator>>( SvStream& rIStm, ImplHatch& rImplHatch ) +{ + VersionCompat aCompat( rIStm, STREAM_READ ); + UINT16 nTmp16; + + rIStm >> nTmp16; rImplHatch.meStyle = (HatchStyle) nTmp16; + rIStm >> rImplHatch.maColor >> rImplHatch.mnDistance >> rImplHatch.mnAngle; + + return rIStm; +} + +// ----------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rOStm, const ImplHatch& rImplHatch ) +{ + VersionCompat aCompat( rOStm, STREAM_WRITE, 1 ); + + rOStm << (UINT16) rImplHatch.meStyle << rImplHatch.maColor; + rOStm << rImplHatch.mnDistance << rImplHatch.mnAngle; + + return rOStm; +} + +// ----------------------------------------------------------------------- + +SvStream& operator>>( SvStream& rIStm, Hatch& rHatch ) +{ + rHatch.ImplMakeUnique(); + return( rIStm >> *rHatch.mpImplHatch ); +} + +// ----------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rOStm, const Hatch& rHatch ) +{ + return( rOStm << *rHatch.mpImplHatch ); +} diff --git a/vcl/source/gdi/image.cxx b/vcl/source/gdi/image.cxx new file mode 100644 index 000000000000..16188cdc5143 --- /dev/null +++ b/vcl/source/gdi/image.cxx @@ -0,0 +1,1521 @@ +/************************************************************************* + * + * $RCSfile: image.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <string.h> + +#define _SV_IMAGE_CXX + +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif + +#ifndef _SV_RC_H +#include <rc.h> +#endif +#ifndef _SV_RC_HXX +#include <rc.hxx> +#endif +#ifndef _SV_RESMGR_HXX +#include <resmgr.hxx> +#endif +#ifndef _SV_SETTINGS_HXX +#include <settings.hxx> +#endif +#ifndef _SV_OUTDEV_HXX +#include <outdev.hxx> +#endif +#ifndef _SV_IMAGE_H +#include <image.h> +#endif +#define private public +#ifndef _SV_IMAGE_HXX +#include <image.hxx> +#endif +#undef private + +// ======================================================================= + +DBG_NAME( Image ); +DBG_NAME( ImageList ); + +#define IMAGE_FILE_VERSION 100 + +// ======================================================================= + +ImplImageList::~ImplImageList() +{ + if ( mpImageBitmap ) + delete mpImageBitmap; + delete mpAry; +} + +// ======================================================================= + +ImplImageRefData::~ImplImageRefData() +{ + mpImplData->mnIRefCount--; + if ( mpImplData->mnRefCount || mpImplData->mnIRefCount ) + { + mpImplData->mpAry[mnIndex].mnRefCount--; + if ( !mpImplData->mpAry[mnIndex].mnRefCount ) + mpImplData->mnRealCount--; + } + else + delete mpImplData; +} + +// ----------------------------------------------------------------------- + +BOOL ImplImageRefData::IsEqual( const ImplImageRefData& rData ) +{ + if ( (mpImplData == rData.mpImplData) && (mnIndex == rData.mnIndex) ) + return TRUE; + else + return FALSE; +} + +// ======================================================================= + +ImplImageData::ImplImageData( const Bitmap& rBmp, const Bitmap& rMaskBmp ) : + maBmp( rBmp ), + maMaskBmp( rMaskBmp ) +{ + mbColor = FALSE; + mpImageBitmap = NULL; +} + +// ----------------------------------------------------------------------- + +ImplImageData::ImplImageData( const Bitmap& rBmp, const Color& rColor ) : + maBmp( rBmp ), + maColor( rColor ) +{ + mbColor = TRUE; + mpImageBitmap = NULL; +} + +// ----------------------------------------------------------------------- + +ImplImageData::~ImplImageData() +{ + if ( mpImageBitmap ) + delete mpImageBitmap; +} + +// ----------------------------------------------------------------------- + +BOOL ImplImageData::IsEqual( const ImplImageData& rData ) +{ + if ( (maBmp == rData.maBmp) && (maMaskBmp == rData.maMaskBmp) && + (maColor == rData.maColor) && (mbColor == rData.mbColor) ) + return TRUE; + else + return FALSE; +} + +// ======================================================================= + +ImplImage::~ImplImage() +{ + switch ( meType ) + { + case IMAGETYPE_BITMAP: + delete (Bitmap*)mpData; + break; + + case IMAGETYPE_IMAGE: + delete (ImplImageData*)mpData; + break; + + case IMAGETYPE_IMAGEREF: + delete (ImplImageRefData*)mpData; + break; + } +} + +// ======================================================================= + +Image::Image() +{ + DBG_CTOR( Image, NULL ); + + mpImplData = NULL; +} + +// ----------------------------------------------------------------------- + +Image::Image( const ResId& rResId ) +{ + DBG_CTOR( Image, NULL ); + + rResId.SetRT( RSC_IMAGE ); + ResMgr* pResMgr = rResId.GetResMgr(); + if ( !pResMgr ) + pResMgr = Resource::GetResManager(); + + if ( pResMgr->GetResource( rResId ) ) + { + // Header ueberspringen + pResMgr->Increment( sizeof( RSHEADER_TYPE ) ); + + USHORT nObjMask = pResMgr->ReadShort(); + + Bitmap aImageBitmap; + Bitmap aMaskBitmap; + Color aMaskColor; + if( nObjMask & RSC_IMAGE_IMAGEBITMAP ) + { + aImageBitmap = Bitmap( ResId( (RSHEADER_TYPE*)pResMgr->GetClass() ) ); + pResMgr->Increment( pResMgr->GetObjSize( (RSHEADER_TYPE*)pResMgr->GetClass() ) ); + } + if( nObjMask & RSC_IMAGE_MASKBITMAP ) + { + aMaskBitmap = Bitmap( ResId( (RSHEADER_TYPE*)pResMgr->GetClass() ) ); + pResMgr->Increment( pResMgr->GetObjSize( (RSHEADER_TYPE*)pResMgr->GetClass() ) ); + } + if( nObjMask & RSC_IMAGE_MASKCOLOR ) + { + aMaskColor = Color( ResId( (RSHEADER_TYPE*)pResMgr->GetClass() ) ); + pResMgr->Increment( pResMgr->GetObjSize( (RSHEADER_TYPE*)pResMgr->GetClass() ) ); + } + + if ( !aImageBitmap ) + mpImplData = NULL; + else + { + mpImplData = new ImplImage; + mpImplData->mnRefCount = 1; + if ( !aMaskBitmap ) + { + if( nObjMask & RSC_IMAGE_MASKCOLOR ) + { + mpImplData->meType = IMAGETYPE_IMAGE; + mpImplData->mpData = new ImplImageData( aImageBitmap, aMaskColor ); + } + else + { + mpImplData->meType = IMAGETYPE_BITMAP; + mpImplData->mpData = new Bitmap( aImageBitmap ); + } + } + else + { + mpImplData->meType = IMAGETYPE_IMAGE; + mpImplData->mpData = new ImplImageData( aImageBitmap, aMaskBitmap ); + } + } + } + else + { + DBG_ERROR( "Image::Image( const ResId& rResId ): No resource!" ); + mpImplData = NULL; + } +} + +// ----------------------------------------------------------------------- + +Image::Image( const Image& rImage ) +{ + DBG_CTOR( Image, NULL ); + + mpImplData = rImage.mpImplData; + if ( mpImplData ) + mpImplData->mnRefCount++; +} + +// ----------------------------------------------------------------------- + +Image::Image( const Bitmap& rBitmap ) +{ + DBG_CTOR( Image, NULL ); + + if ( !rBitmap ) + mpImplData = NULL; + else + { + mpImplData = new ImplImage; + mpImplData->mnRefCount = 1; + mpImplData->meType = IMAGETYPE_BITMAP; + mpImplData->mpData = new Bitmap( rBitmap ); + } +} + +// ----------------------------------------------------------------------- + +Image::Image( const Bitmap& rBitmap, const Bitmap& rMaskBitmap ) +{ + DBG_CTOR( Image, NULL ); + + if ( !rBitmap ) + mpImplData = NULL; + else + { + mpImplData = new ImplImage; + mpImplData->mnRefCount = 1; + if ( !rMaskBitmap ) + { + mpImplData->meType = IMAGETYPE_BITMAP; + mpImplData->mpData = new Bitmap( rBitmap ); + } + else + { + mpImplData->meType = IMAGETYPE_IMAGE; + mpImplData->mpData = new ImplImageData( rBitmap, rMaskBitmap ); + } + } +} + +// ----------------------------------------------------------------------- + +Image::Image( const Bitmap& rBitmap, const Color& rColor ) +{ + DBG_CTOR( Image, NULL ); + + if ( !rBitmap ) + mpImplData = NULL; + else + { + mpImplData = new ImplImage; + mpImplData->mnRefCount = 1; + mpImplData->meType = IMAGETYPE_IMAGE; + mpImplData->mpData = new ImplImageData( rBitmap, rColor ); + } +} + +// ----------------------------------------------------------------------- + +Image::Image( const BitmapEx& rBitmapEx ) +{ + DBG_CTOR( Image, NULL ); + + const Bitmap aBmp( rBitmapEx.GetBitmap() ); + + if( !aBmp ) + mpImplData = NULL; + else + { + const Bitmap aMask( rBitmapEx.GetMask() ); + + mpImplData = new ImplImage; + mpImplData->mnRefCount = 1; + + if( !aMask ) + { + mpImplData->meType = IMAGETYPE_BITMAP; + mpImplData->mpData = new Bitmap( aBmp ); + } + else + { + mpImplData->meType = IMAGETYPE_IMAGE; + mpImplData->mpData = new ImplImageData( aBmp, aMask ); + } + } +} + +// ----------------------------------------------------------------------- + +Image::~Image() +{ + DBG_DTOR( Image, NULL ); + + if ( mpImplData ) + { + if ( mpImplData->mnRefCount > 1 ) + mpImplData->mnRefCount--; + else + delete mpImplData; + } +} + +// ----------------------------------------------------------------------- + +Size Image::GetSizePixel() const +{ + DBG_CHKTHIS( Image, NULL ); + + if ( mpImplData ) + { + switch ( mpImplData->meType ) + { + case IMAGETYPE_BITMAP: + return ((Bitmap*)mpImplData->mpData)->GetSizePixel(); + + case IMAGETYPE_IMAGE: + return ((ImplImageData*)mpImplData->mpData)->maBmp.GetSizePixel(); + + case IMAGETYPE_IMAGEREF: + return ((ImplImageRefData*)mpImplData->mpData)->mpImplData->maImageSize; + } + } + + return Size(); +} + +// ----------------------------------------------------------------------- + +Image& Image::operator=( const Image& rImage ) +{ + DBG_CHKTHIS( Image, NULL ); + DBG_CHKOBJ( &rImage, Image, NULL ); + + // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann + if ( rImage.mpImplData ) + rImage.mpImplData->mnRefCount++; + + // Abkoppeln + if ( mpImplData ) + { + if ( mpImplData->mnRefCount > 1 ) + mpImplData->mnRefCount--; + else + delete mpImplData; + } + + // Neue Daten zuweisen + mpImplData = rImage.mpImplData; + + return *this; +} + +// ----------------------------------------------------------------------- + +BOOL Image::operator==( const Image& rImage ) const +{ + DBG_CHKTHIS( Image, NULL ); + DBG_CHKOBJ( &rImage, Image, NULL ); + + if ( rImage.mpImplData == mpImplData ) + return TRUE; + if ( !rImage.mpImplData || !mpImplData ) + return FALSE; + + if ( rImage.mpImplData->mpData == mpImplData->mpData ) + return TRUE; + + if ( rImage.mpImplData->meType == mpImplData->meType ) + { + switch ( mpImplData->meType ) + { + case IMAGETYPE_BITMAP: + if ( *((Bitmap*)rImage.mpImplData->mpData) == *((Bitmap*)mpImplData->mpData) ) + return TRUE; + break; + + case IMAGETYPE_IMAGE: + if ( ((ImplImageData*)rImage.mpImplData->mpData)->IsEqual( *((ImplImageData*)mpImplData->mpData) ) ) + return TRUE; + break; + + case IMAGETYPE_IMAGEREF: + if ( ((ImplImageRefData*)rImage.mpImplData->mpData)->IsEqual( *((ImplImageRefData*)mpImplData->mpData) ) ) + return TRUE; + break; + } + } + + return FALSE; +} + +// ======================================================================= + +static void ImplCopyImageListData( ImageList* pThis ) +{ + if ( pThis->mpImplData->mnRefCount > 1 ) + { + pThis->mpImplData->mnRefCount--; + + ImplImageList* pNewData = new ImplImageList; + pNewData->mnRefCount = 1; + pNewData->mnIRefCount = 0; + pNewData->mnCount = pThis->mpImplData->mnCount; + pNewData->mnRealCount = pThis->mpImplData->mnRealCount; + pNewData->mnArySize = pThis->mpImplData->mnArySize; + pNewData->mpAry = new ImageAryData[pNewData->mnArySize]; + pNewData->maImageSize = pThis->mpImplData->maImageSize; + pNewData->mpImageBitmap = new ImplImageBmp; + pNewData->mpImageBitmap->Create( pNewData->maImageSize.Width(), + pNewData->maImageSize.Height(), + pNewData->mnArySize ); + memset( pNewData->mpAry, 0, pNewData->mnArySize*sizeof(ImageAryData) ); + + USHORT i = 0; + USHORT n = 0; + while ( i < pThis->mpImplData->mnArySize ) + { + // Nur die Images kopieren, die gebraucht werden + if ( pThis->mpImplData->mpAry[i].mnId ) + { + pNewData->mpAry[n].mnId = pThis->mpImplData->mpAry[i].mnId; + pNewData->mpAry[n].mnRefCount = 1; + pNewData->mpImageBitmap->Replace( n, + *(pThis->mpImplData->mpImageBitmap), + i ); + n++; + } + + i++; + } + + pThis->mpImplData = pNewData; + } +} + +// ----------------------------------------------------------------------- + +static void ImplBmpImageCreate( ImageList* pThis, + const Bitmap& rBitmap, const Bitmap& rMaskBmp, + const Color& rColor, BOOL bColor, + USHORT nInit, USHORT* mpIdAry = NULL, + USHORT nGrow = 4 ) +{ + // Falls es sich um eine leere ImageListe handelt, dann Defaul-Werte + // setzen und nichts machen + if ( !nInit ) + { + pThis->mpImplData = NULL; + pThis->mnInitSize = 1; + pThis->mnGrowSize = nGrow; + return; + } + + DBG_ASSERT( !nInit || rBitmap.GetSizePixel().Width(), + "ImageList::ImageList(): nInitSize != 0 and BmpSize.Width() == 0" ); + DBG_ASSERT( (rBitmap.GetSizePixel().Width() % nInit) == 0, + "ImageList::ImageList(): BmpSize % nInitSize != 0" ); + DBG_ASSERT( !rMaskBmp || (rMaskBmp.GetSizePixel() == rBitmap.GetSizePixel()), + "ImageList::ImageList(): BmpSize != MaskBmpSize" ); +#ifdef DBG_UTIL + if ( mpIdAry ) + { + for ( USHORT n1 = 0; n1 < nInit; n1++ ) + { + USHORT nId = mpIdAry[n1]; + if ( !nId ) + { + DBG_ERROR( "ImageList::ImageList(): Id == 0" ); + } + for ( USHORT n2 = 0; n2 < n1; n2++ ) + { + if ( nId == mpIdAry[n2] ) + { + DBG_ERROR1( "ImageList::ImageList(): Double Id (%u)", nId ); + } + } + } + } +#endif + + Size aBmpSize = rBitmap.GetSizePixel(); + pThis->mnInitSize = nInit; + pThis->mnGrowSize = nGrow; + pThis->mpImplData = new ImplImageList; + pThis->mpImplData->mnRefCount = 1; + pThis->mpImplData->mnIRefCount = 0; + pThis->mpImplData->mnCount = nInit; + pThis->mpImplData->mnRealCount = nInit; + pThis->mpImplData->mnArySize = nInit; + pThis->mpImplData->mpAry = new ImageAryData[nInit]; + pThis->mpImplData->maImageSize = Size( aBmpSize.Width() / nInit, aBmpSize.Height() ); + + for ( USHORT i = 0; i < nInit; i++ ) + { + if ( mpIdAry ) + pThis->mpImplData->mpAry[i].mnId = mpIdAry[i]; + else + pThis->mpImplData->mpAry[i].mnId = i+1; + pThis->mpImplData->mpAry[i].mnRefCount = 1; + } + + pThis->mpImplData->mpImageBitmap = new ImplImageBmp; + pThis->mpImplData->mpImageBitmap->Create( rBitmap, rMaskBmp, + rColor, bColor, + pThis->mpImplData->maImageSize.Width(), + pThis->mpImplData->maImageSize.Height(), + nInit ); +} + +// ======================================================================= + +ImageList::ImageList( USHORT nInit, USHORT nGrow ) +{ + DBG_CTOR( ImageList, NULL ); + + mpImplData = NULL; + mnInitSize = nInit; + mnGrowSize = nGrow; +} + +// ----------------------------------------------------------------------- + +ImageList::ImageList( const ResId& rResId ) +{ + DBG_CTOR( ImageList, NULL ); + + rResId.SetRT( RSC_IMAGELIST ); + ResMgr* pResMgr = rResId.GetResMgr(); + if ( !pResMgr ) + pResMgr = Resource::GetResManager(); + + if ( pResMgr->GetResource( rResId ) ) + { + // Header ueberspringen + pResMgr->Increment( sizeof( RSHEADER_TYPE ) ); + + USHORT nObjMask = pResMgr->ReadShort(); + + Bitmap aImageBitmap; + Bitmap aMaskBitmap; + Color aMaskColor; + BOOL bCol = FALSE; + BOOL bIsIdList = FALSE; + + if ( nObjMask & RSC_IMAGELIST_IMAGEBITMAP ) + { + aImageBitmap = Bitmap( ResId( (RSHEADER_TYPE*)pResMgr->GetClass() ) ); + pResMgr->Increment( pResMgr->GetObjSize( (RSHEADER_TYPE*)pResMgr->GetClass() ) ); + } + if ( nObjMask & RSC_IMAGELIST_MASKBITMAP ) + { + aMaskBitmap = Bitmap( ResId( (RSHEADER_TYPE*)pResMgr->GetClass() ) ); + pResMgr->Increment( pResMgr->GetObjSize( (RSHEADER_TYPE*)pResMgr->GetClass() ) ); + } + if ( nObjMask & RSC_IMAGELIST_MASKCOLOR ) + { + aMaskColor = Color( ResId( (RSHEADER_TYPE*)pResMgr->GetClass() ) ); + pResMgr->Increment( pResMgr->GetObjSize( (RSHEADER_TYPE*)pResMgr->GetClass() ) ); + bCol = TRUE; + } + if ( nObjMask & RSC_IMAGELIST_IDLIST ) + { + bIsIdList = TRUE; + USHORT nCount = pResMgr->ReadShort(); + USHORT* pAry = new USHORT[ nCount ]; + for( int i = 0; i < nCount; i++ ) + pAry[ i ] = pResMgr->ReadShort(); + ImplBmpImageCreate( this, aImageBitmap, aMaskBitmap, aMaskColor, + bCol, nCount, pAry, 4 ); + delete pAry; + } + if ( nObjMask & RSC_IMAGELIST_IDCOUNT ) + { + USHORT nCount = pResMgr->ReadShort(); + if ( !bIsIdList ) + { + ImplBmpImageCreate( this, aImageBitmap, aMaskBitmap, aMaskColor, + bCol, nCount, NULL, 4 ); + } + } + } +} + +// ----------------------------------------------------------------------- + +ImageList::ImageList( const ImageList& rImageList ) +{ + DBG_CTOR( ImageList, NULL ); + + mpImplData = rImageList.mpImplData; + if ( mpImplData ) + mpImplData->mnRefCount++; +} + +// ----------------------------------------------------------------------- + +ImageList::ImageList( const Bitmap& rBitmap, + USHORT nInit, USHORT* mpIdAry, USHORT nGrow ) +{ + DBG_CTOR( ImageList, NULL ); + + ImplBmpImageCreate( this, rBitmap, Bitmap(), Color(), FALSE, + nInit, mpIdAry, nGrow ); +} + +// ----------------------------------------------------------------------- + +ImageList::ImageList( const Bitmap& rBitmap, const Bitmap& rMaskBmp, + USHORT nInit, USHORT* mpIdAry, USHORT nGrow ) +{ + DBG_CTOR( ImageList, NULL ); + + ImplBmpImageCreate( this, rBitmap, rMaskBmp, Color(), FALSE, + nInit, mpIdAry, nGrow ); +} + +// ----------------------------------------------------------------------- + +ImageList::ImageList( const Bitmap& rBitmap, const Color& rColor, + USHORT nInit, USHORT* mpIdAry, USHORT nGrow ) +{ + DBG_CTOR( ImageList, NULL ); + + ImplBmpImageCreate( this, rBitmap, Bitmap(), rColor, TRUE, + nInit, mpIdAry, nGrow ); +} + +// ----------------------------------------------------------------------- + +ImageList::~ImageList() +{ + DBG_DTOR( ImageList, NULL ); + + if ( mpImplData ) + { + mpImplData->mnRefCount--; + if ( !mpImplData->mnRefCount && !mpImplData->mnIRefCount ) + delete mpImplData; + } +} + +// ----------------------------------------------------------------------- + +void ImageList::AddImage( USHORT nId, const Image& rImage ) +{ + DBG_CHKTHIS( ImageList, NULL ); + DBG_CHKOBJ( &rImage, Image, NULL ); + DBG_ASSERT( nId, "ImageList::AddImage(): ImageId == 0" ); + DBG_ASSERT( GetImagePos( nId ) == IMAGELIST_IMAGE_NOTFOUND, + "ImageList::AddImage() - ImageId already exists" ); + DBG_ASSERT( rImage.mpImplData, "ImageList::AddImage(): Wrong Size" ); + DBG_ASSERT( !mpImplData || (rImage.GetSizePixel() == mpImplData->maImageSize), + "ImageList::AddImage(): Wrong Size" ); + + ImageType eImageType = rImage.mpImplData->meType; + Size aImageSize = rImage.GetSizePixel(); + USHORT nIndex; + + if ( !mpImplData ) + { + mpImplData = new ImplImageList; + mpImplData->mnRefCount = 1; + mpImplData->mnIRefCount = 0; + mpImplData->mnCount = 0; + mpImplData->mnRealCount = 0; + mpImplData->mnArySize = mnInitSize; + mpImplData->mpAry = new ImageAryData[mnInitSize]; + mpImplData->maImageSize = aImageSize; + mpImplData->mpImageBitmap = new ImplImageBmp; + mpImplData->mpImageBitmap->Create( aImageSize.Width(), aImageSize.Height(), + mnInitSize ); + memset( mpImplData->mpAry, 0, mpImplData->mnArySize*sizeof(ImageAryData) ); + } + else + ImplCopyImageListData( this ); + + // Gegebenenfalls unser Array erweitern und freien Index ermitteln + if ( mpImplData->mnRealCount == mpImplData->mnArySize ) + { + ImageAryData* pOldAry = mpImplData->mpAry; + USHORT nOldSize = mpImplData->mnArySize; + + mpImplData->mnArySize += mnGrowSize; + mpImplData->mpAry = new ImageAryData[mpImplData->mnArySize]; + memset( mpImplData->mpAry, 0, mpImplData->mnArySize*sizeof(ImageAryData) ); + memcpy( mpImplData->mpAry, pOldAry, nOldSize*sizeof(ImageAryData) ); + mpImplData->mpImageBitmap->Expand( mnGrowSize ); + delete pOldAry; + + nIndex = mpImplData->mnRealCount; + } + else + { + nIndex = 0; + while ( mpImplData->mpAry[nIndex].mnRefCount ) + nIndex++; + } + + // Image in Bitmap einfuegen + switch ( eImageType ) + { + case IMAGETYPE_BITMAP: + mpImplData->mpImageBitmap->Replace( nIndex, *((Bitmap*)rImage.mpImplData->mpData) ); + break; + + case IMAGETYPE_IMAGE: + { + ImplImageData* pData = (ImplImageData*)rImage.mpImplData->mpData; + if ( pData->mpImageBitmap ) + mpImplData->mpImageBitmap->Replace( nIndex, *(pData->mpImageBitmap), 0 ); + else + { + if ( pData->mbColor ) + mpImplData->mpImageBitmap->Replace( nIndex, pData->maBmp, pData->maColor ); + else + mpImplData->mpImageBitmap->Replace( nIndex, pData->maBmp, pData->maMaskBmp ); + } + } + break; + + case IMAGETYPE_IMAGEREF: + { + ImplImageRefData* pData = (ImplImageRefData*)rImage.mpImplData->mpData; + mpImplData->mpImageBitmap->Replace( nIndex, *(pData->mpImplData->mpImageBitmap), + pData->mnIndex ); + } + break; + } + + // Array-Daten updaten + mpImplData->mnCount++; + mpImplData->mnRealCount++; + mpImplData->mpAry[nIndex].mnId = nId; + mpImplData->mpAry[nIndex].mnRefCount = 1; +} + +// ----------------------------------------------------------------------- + +void ImageList::CopyImage( USHORT nId, USHORT nCopyId ) +{ + DBG_CHKTHIS( ImageList, NULL ); + DBG_ASSERT( nId, "ImageList::CopyImage(): ImageId == 0" ); + DBG_ASSERT( GetImagePos( nId ) == IMAGELIST_IMAGE_NOTFOUND, + "ImageList::CopyImage(): ImageId already exists" ); + DBG_ASSERT( GetImagePos( nCopyId ) != IMAGELIST_IMAGE_NOTFOUND, + "ImageList::CopyImage(): Unknown nCopyId" ); + + USHORT nIndex; + USHORT nCopyIndex = 0; + + // Index von CopyId holen + while ( nCopyIndex < mpImplData->mnArySize ) + { + if ( mpImplData->mpAry[nCopyIndex].mnId == nCopyId ) + break; + + nCopyIndex++; + } + if ( nCopyIndex >= mpImplData->mnArySize ) + return; + + // Referenz-Counter ueberpruefen + ImplCopyImageListData( this ); + + // Gegebenenfalls unser Array erweitern + if ( mpImplData->mnRealCount == mpImplData->mnArySize ) + { + ImageAryData* pOldAry = mpImplData->mpAry; + USHORT nOldSize = mpImplData->mnArySize; + + mpImplData->mnArySize += mnGrowSize; + mpImplData->mpAry = new ImageAryData[mpImplData->mnArySize]; + memset( mpImplData->mpAry, 0, mpImplData->mnArySize*sizeof(ImageAryData) ); + memcpy( mpImplData->mpAry, pOldAry, nOldSize*sizeof(ImageAryData) ); + mpImplData->mpImageBitmap->Expand( mnGrowSize ); + delete pOldAry; + + nIndex = mpImplData->mnRealCount; + } + else + { + nIndex = 0; + while ( mpImplData->mpAry[nIndex].mnRefCount ) + nIndex++; + } + + // Kopieren + mpImplData->mpImageBitmap->Replace( nIndex, *(mpImplData->mpImageBitmap), nCopyIndex ); + + // Array-Daten updaten + mpImplData->mnCount++; + mpImplData->mnRealCount++; + mpImplData->mpAry[nIndex].mnId = nId; + mpImplData->mpAry[nIndex].mnRefCount = 1; +} + +// ----------------------------------------------------------------------- + +void ImageList::ReplaceImage( USHORT nId, const Image& rImage ) +{ + DBG_CHKTHIS( ImageList, NULL ); + DBG_CHKOBJ( &rImage, Image, NULL ); + DBG_ASSERT( GetImagePos( nId ) != IMAGELIST_IMAGE_NOTFOUND, + "ImageList::ReplaceImage(): Unknown nId" ); + + RemoveImage( nId ); + AddImage( nId, rImage ); +} + +// ----------------------------------------------------------------------- + +void ImageList::ReplaceImage( USHORT nId, USHORT nReplaceId ) +{ + DBG_CHKTHIS( ImageList, NULL ); + DBG_ASSERT( GetImagePos( nId ) != IMAGELIST_IMAGE_NOTFOUND, + "ImageList::ReplaceImage(): Unknown nId" ); + DBG_ASSERT( GetImagePos( nReplaceId ) != IMAGELIST_IMAGE_NOTFOUND, + "ImageList::ReplaceImage(): Unknown nReplaceId" ); + + USHORT nPos1 = 0; + USHORT nPos2 = 0; + + // Index von Id holen + while ( nPos1 < mpImplData->mnArySize ) + { + if ( mpImplData->mpAry[nPos1].mnId == nId ) + break; + + nPos1++; + } + if ( nPos1 >= mpImplData->mnArySize ) + return; + + // Index von ReplaceId holen + while ( nPos2 < mpImplData->mnArySize ) + { + if ( mpImplData->mpAry[nPos2].mnId == nReplaceId ) + break; + + nPos2++; + } + if ( nPos2 >= mpImplData->mnArySize ) + return; + + // Referenz-Counter ueberpruefen + ImplCopyImageListData( this ); + + // Ersetzen + mpImplData->mpImageBitmap->Replace( nPos1, nPos2 ); +} + +// ----------------------------------------------------------------------- + +void ImageList::MergeImage( USHORT nId, USHORT nMergeId ) +{ + DBG_CHKTHIS( ImageList, NULL ); + DBG_ASSERT( GetImagePos( nId ) != IMAGELIST_IMAGE_NOTFOUND, + "ImageList::MergeImage(): Unknown nId" ); + DBG_ASSERT( GetImagePos( nMergeId ) != IMAGELIST_IMAGE_NOTFOUND, + "ImageList::MergeImage(): Unknown nMergeId" ); + + USHORT nPos1 = 0; + USHORT nPos2 = 0; + + // Index von Id holen + while ( nPos1 < mpImplData->mnArySize ) + { + if ( mpImplData->mpAry[nPos1].mnId == nId ) + break; + + nPos1++; + } + if ( nPos1 >= mpImplData->mnArySize ) + return; + + // Index von MergeId holen + while ( nPos2 < mpImplData->mnArySize ) + { + if ( mpImplData->mpAry[nPos2].mnId == nMergeId ) + break; + + nPos2++; + } + if ( nPos2 >= mpImplData->mnArySize ) + return; + + // Referenz-Counter ueberpruefen + ImplCopyImageListData( this ); + + // Ersetzen + mpImplData->mpImageBitmap->Merge( nPos1, nPos2 ); +} + +// ----------------------------------------------------------------------- + +void ImageList::RemoveImage( USHORT nId ) +{ + DBG_CHKTHIS( ImageList, NULL ); + + if ( mpImplData ) + { + ImplCopyImageListData( this ); + + USHORT i = 0; + while ( i < mpImplData->mnArySize ) + { + if ( mpImplData->mpAry[i].mnId == nId ) + break; + + i++; + } + + if ( i < mpImplData->mnArySize ) + { + mpImplData->mpAry[i].mnRefCount--; + mpImplData->mpAry[i].mnId = 0; + if ( !mpImplData->mpAry[i].mnRefCount ) + mpImplData->mnRealCount--; + + mpImplData->mnCount--; + } + } +} + +// ----------------------------------------------------------------------- + +Image ImageList::GetImage( USHORT nId ) const +{ + DBG_CHKTHIS( ImageList, NULL ); + + Image aImage; + + if ( mpImplData ) + { + USHORT i = 0; + while ( i < mpImplData->mnArySize ) + { + if ( mpImplData->mpAry[i].mnId == nId ) + break; + + i++; + } + + if ( i < mpImplData->mnArySize ) + { + ImplImageRefData* mpData = new ImplImageRefData; + + mpImplData->mnIRefCount++; + mpImplData->mpAry[i].mnRefCount++; + mpData->mpImplData = mpImplData; + mpData->mnIndex = i; + + aImage.mpImplData = new ImplImage; + aImage.mpImplData->mnRefCount = 1; + aImage.mpImplData->meType = IMAGETYPE_IMAGEREF; + aImage.mpImplData->mpData = mpData; + } + } + + return aImage; +} + +// ----------------------------------------------------------------------- + +void ImageList::Clear() +{ + DBG_CHKTHIS( ImageList, NULL ); + + if ( mpImplData ) + { + if ( mpImplData->mnRefCount > 1 ) + mpImplData->mnRefCount--; + else + delete mpImplData; + } + + mpImplData = 0; +} + +// ----------------------------------------------------------------------- + +USHORT ImageList::GetImageCount() const +{ + DBG_CHKTHIS( ImageList, NULL ); + + if ( mpImplData ) + return mpImplData->mnCount; + else + return 0; +} + +// ----------------------------------------------------------------------- + +USHORT ImageList::GetImagePos( USHORT nId ) const +{ + DBG_CHKTHIS( ImageList, NULL ); + + if ( mpImplData && nId ) + { + USHORT nPos = 0; + USHORT i = 0; + while ( i < mpImplData->mnArySize ) + { + if ( mpImplData->mpAry[i].mnId == nId ) + return nPos; + + if ( mpImplData->mpAry[i].mnId ) + nPos++; + i++; + } + } + + return IMAGELIST_IMAGE_NOTFOUND; +} + +// ----------------------------------------------------------------------- + +USHORT ImageList::GetImageId( USHORT nPos ) const +{ + DBG_CHKTHIS( ImageList, NULL ); + + if ( mpImplData ) + { + USHORT nRealPos = 0; + USHORT i = 0; + while ( i < mpImplData->mnArySize ) + { + if ( (nPos == nRealPos) && (mpImplData->mpAry[i].mnId) ) + return mpImplData->mpAry[i].mnId; + + if ( mpImplData->mpAry[i].mnId ) + nRealPos++; + i++; + } + } + + return 0; +} + +// ----------------------------------------------------------------------- + +Size ImageList::GetImageSize() const +{ + DBG_CHKTHIS( ImageList, NULL ); + + if ( mpImplData ) + return mpImplData->maImageSize; + else + return Size(); +} + +// ----------------------------------------------------------------------- + +Bitmap ImageList::GetBitmap() const +{ + DBG_CHKTHIS( ImageList, NULL ); + + Bitmap aBmp; + + if ( mpImplData ) + { + // Positionen ermitteln, die in der Bitmap enthalten sein sollen + USHORT* mpPosAry = new USHORT[mpImplData->mnCount]; + USHORT nPosCount = 0; + for ( USHORT i = 0; i < mpImplData->mnArySize; i++ ) + { + if ( mpImplData->mpAry[i].mnId ) + { + mpPosAry[nPosCount] = i; + nPosCount++; + } + } + + // Bitmap besorgen + aBmp = mpImplData->mpImageBitmap->GetBitmap( nPosCount, mpPosAry ); + + // Temporaeres Array loeschen + delete mpPosAry; + } + + return aBmp; +} + +// ----------------------------------------------------------------------- + +Bitmap ImageList::GetMaskBitmap() const +{ + DBG_CHKTHIS( ImageList, NULL ); + + Bitmap aBmp; + + if ( HasMaskBitmap() ) + { + // Positionen ermitteln, die in der Bitmap enthalten sein sollen + USHORT* mpPosAry = new USHORT[mpImplData->mnCount]; + USHORT nPosCount = 0; + for ( USHORT i = 0; i < mpImplData->mnArySize; i++ ) + { + if ( mpImplData->mpAry[i].mnId ) + { + mpPosAry[nPosCount] = i; + nPosCount++; + } + } + + // Bitmap besorgen + aBmp = mpImplData->mpImageBitmap->GetMaskBitmap( nPosCount, mpPosAry ); + + // Temporaeres Array loeschen + delete mpPosAry; + } + + return aBmp; +} + +// ----------------------------------------------------------------------- + +BOOL ImageList::HasMaskBitmap() const +{ + DBG_CHKTHIS( ImageList, NULL ); + + if ( mpImplData ) + return mpImplData->mpImageBitmap->HasMaskBitmap(); + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +Color ImageList::GetMaskColor() const +{ + DBG_CHKTHIS( ImageList, NULL ); + + Color aColor; + + if ( HasMaskColor() ) + aColor = mpImplData->mpImageBitmap->GetMaskColor(); + + return aColor; +} + +// ----------------------------------------------------------------------- + +BOOL ImageList::HasMaskColor() const +{ + DBG_CHKTHIS( ImageList, NULL ); + + if ( mpImplData ) + return mpImplData->mpImageBitmap->HasMaskColor(); + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +ImageList& ImageList::operator=( const ImageList& rImageList ) +{ + DBG_CHKTHIS( ImageList, NULL ); + DBG_CHKOBJ( &rImageList, ImageList, NULL ); + + // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann + if ( rImageList.mpImplData ) + rImageList.mpImplData->mnRefCount++; + + // Abkoppeln + if ( mpImplData ) + { + mpImplData->mnRefCount--; + if ( !mpImplData->mnRefCount && !mpImplData->mnIRefCount ) + delete mpImplData; + } + + // Neue Daten zuweisen + mpImplData = rImageList.mpImplData; + mnInitSize = rImageList.mnInitSize; + mnGrowSize = rImageList.mnGrowSize; + + return *this; +} + +// ----------------------------------------------------------------------- + +BOOL ImageList::operator==( const ImageList& rImageList ) const +{ + DBG_CHKTHIS( ImageList, NULL ); + DBG_CHKOBJ( &rImageList, ImageList, NULL ); + + if ( rImageList.mpImplData == mpImplData ) + return TRUE; + if ( !rImageList.mpImplData || !mpImplData ) + return FALSE; + + if ( (rImageList.mpImplData->mnCount == mpImplData->mnCount) && + (rImageList.mpImplData->maImageSize == mpImplData->maImageSize) ) + return TRUE; + + return FALSE; +} + +// ----------------------------------------------------------------------- + +SvStream& operator>>( SvStream& rIStream, ImageList& rImageList ) +{ + DBG_CHKOBJ( &rImageList, ImageList, NULL ); + + // Falls es eine bestehende ImageListe ist, dann erst abkoppeln + if ( rImageList.mpImplData ) + { + rImageList.mpImplData->mnRefCount--; + if ( !rImageList.mpImplData->mnRefCount && !rImageList.mpImplData->mnIRefCount ) + delete rImageList.mpImplData; + } + rImageList.mpImplData = NULL; + + // Daten lesen + USHORT nVersion; + Size aImageSize; + BOOL bImageList; + rIStream >> nVersion; + rIStream >> rImageList.mnInitSize; + rIStream >> rImageList.mnGrowSize; + rIStream >> bImageList; + + // Wenn es eine leere ImageListe ist, dann brauchen wir nicht weiter lesen + if ( !bImageList ) + return rIStream; + + // Image-Groesse lesen + rIStream >> aImageSize.Width(); + rIStream >> aImageSize.Height(); + + // Image-Daten anlegen und initialisieren + rImageList.mpImplData = new ImplImageList; + rImageList.mpImplData->mnRefCount = 1; + rImageList.mpImplData->mnIRefCount = 0; + rImageList.mpImplData->mnCount = rImageList.mnInitSize; + rImageList.mpImplData->mnRealCount = rImageList.mnInitSize; + rImageList.mpImplData->mnArySize = rImageList.mnInitSize; + rImageList.mpImplData->mpAry = new ImageAryData[rImageList.mnInitSize]; + rImageList.mpImplData->maImageSize = aImageSize; + + // Array mit ID's lesen und initialisieren + for ( USHORT i = 0; i < rImageList.mnInitSize; i++ ) + { + rIStream >> rImageList.mpImplData->mpAry[i].mnId; + rImageList.mpImplData->mpAry[i].mnRefCount = 1; + } + + // Bitmaps lesen + Bitmap aBitmap; + Bitmap aMaskBitmap; + Color aMaskColor; + BYTE bMaskBitmap; + BYTE bMaskColor; + rIStream >> aBitmap; + rIStream >> bMaskBitmap; + if ( bMaskBitmap ) + rIStream >> aMaskBitmap; + rIStream >> bMaskColor; + if ( bMaskColor ) + rIStream >> aMaskColor; + + // Systemdaten anlegen + rImageList.mpImplData->mpImageBitmap = new ImplImageBmp; + rImageList.mpImplData->mpImageBitmap->Create( aBitmap, aMaskBitmap, + aMaskColor, bMaskColor, + aImageSize.Width(), + aImageSize.Height(), + rImageList.mnInitSize ); + return rIStream; +} + +// ----------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rOStream, const ImageList& rImageList ) +{ + DBG_CHKOBJ( &rImageList, ImageList, NULL ); + + BOOL bImageList = (rImageList.mpImplData) ? TRUE : FALSE; + + USHORT nVersion = IMAGE_FILE_VERSION; + rOStream << nVersion; + + // Wenn es eine leere ImageListe ist, dann nur InitSize und + // GrowSize schreiben + if ( !bImageList || !rImageList.mpImplData->mnCount ) + { + BOOL bSaveImageList = FALSE; + rOStream << rImageList.mnInitSize; + rOStream << rImageList.mnGrowSize; + rOStream << bSaveImageList; + return rOStream; + } + + // Normale Daten schreiben + rOStream << rImageList.mpImplData->mnCount; + rOStream << rImageList.mnGrowSize; + rOStream << bImageList; + rOStream << rImageList.mpImplData->maImageSize.Width(); + rOStream << rImageList.mpImplData->maImageSize.Height(); + + // Array schreiben und feststellen, welche Eintraege gespeichert werden + // muessen + USHORT* mpPosAry = new USHORT[rImageList.mpImplData->mnCount]; + USHORT nPosCount = 0; + for ( USHORT i = 0; i < rImageList.mpImplData->mnArySize; i++ ) + { + if ( rImageList.mpImplData->mpAry[i].mnId ) + { + rOStream << rImageList.mpImplData->mpAry[i].mnId; + mpPosAry[nPosCount] = i; + nPosCount++; + } + } + + // Bitmaps rausschreiben + Bitmap aBmp; + BYTE bMaskBitmap = (BYTE)rImageList.mpImplData->mpImageBitmap->HasMaskBitmap(); + BYTE bMaskColor = (BYTE)rImageList.mpImplData->mpImageBitmap->HasMaskColor(); + aBmp = rImageList.mpImplData->mpImageBitmap->GetBitmap( nPosCount, mpPosAry ); + rOStream << aBmp; + rOStream << bMaskBitmap; + if ( bMaskBitmap ) + { + aBmp = rImageList.mpImplData->mpImageBitmap->GetMaskBitmap( nPosCount, mpPosAry ); + rOStream << aBmp; + } + rOStream << bMaskColor; + if ( bMaskColor ) + { + Color aColor = rImageList.mpImplData->mpImageBitmap->GetMaskColor(); + rOStream << aColor; + } + + // Temporaeres Array loeschen + delete mpPosAry; + + return rOStream; +} + +// ======================================================================= + +void OutputDevice::DrawImage( const Point& rPos, const Image& rImage, + USHORT nStyle ) +{ + DBG_CHKOBJ( &rImage, Image, NULL ); + DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, + "DrawImage(): Images can't be drawn on any mprinter" ); + + if( !rImage.mpImplData ) + return; + + switch( rImage.mpImplData->meType ) + { + case IMAGETYPE_BITMAP: + { + DrawBitmap( rPos, *((Bitmap*)rImage.mpImplData->mpData) ); + } + break; + + case IMAGETYPE_IMAGE: + { + ImplImageData* pData = (ImplImageData*)rImage.mpImplData->mpData; + + if ( !pData->mpImageBitmap ) + { + Size aSize = pData->maBmp.GetSizePixel(); + pData->mpImageBitmap = new ImplImageBmp; + pData->mpImageBitmap->Create( pData->maBmp, pData->maMaskBmp, + pData->maColor, pData->mbColor, + aSize.Width(), aSize.Height(), + 1 ); + } + + pData->mpImageBitmap->Draw( 0, this, rPos, nStyle ); + } + break; + + case IMAGETYPE_IMAGEREF: + { + ImplImageRefData* pData = (ImplImageRefData*)rImage.mpImplData->mpData; + pData->mpImplData->mpImageBitmap->Draw( pData->mnIndex, this, rPos, nStyle ); + } + break; + } +} + +// ======================================================================= + +void OutputDevice::DrawImage( const Point& rPos, const Size& rSize, + const Image& rImage, USHORT nStyle ) +{ + DBG_CHKOBJ( &rImage, Image, NULL ); + DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, + "DrawImage(): Images can't be drawn on any mprinter" ); + + if( !rImage.mpImplData ) + return; + + switch( rImage.mpImplData->meType ) + { + case IMAGETYPE_BITMAP: + { + DrawBitmap( rPos, rSize, *((Bitmap*)rImage.mpImplData->mpData) ); + } + break; + + case IMAGETYPE_IMAGE: + { + ImplImageData* pData = (ImplImageData*)rImage.mpImplData->mpData; + + if ( !pData->mpImageBitmap ) + { + Size aSize = pData->maBmp.GetSizePixel(); + pData->mpImageBitmap = new ImplImageBmp; + pData->mpImageBitmap->Create( pData->maBmp, pData->maMaskBmp, + pData->maColor, pData->mbColor, + aSize.Width(), aSize.Height(), + 1 ); + } + + pData->mpImageBitmap->Draw( 0, this, rPos, nStyle, &rSize ); + } + break; + + case IMAGETYPE_IMAGEREF: + { + ImplImageRefData* pData = (ImplImageRefData*)rImage.mpImplData->mpData; + pData->mpImplData->mpImageBitmap->Draw( pData->mnIndex, this, rPos, nStyle, &rSize ); + } + break; + } +} diff --git a/vcl/source/gdi/imgcons.cxx b/vcl/source/gdi/imgcons.cxx new file mode 100644 index 000000000000..d20f9c26f1c9 --- /dev/null +++ b/vcl/source/gdi/imgcons.cxx @@ -0,0 +1,593 @@ +/************************************************************************* + * + * $RCSfile: imgcons.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <bmpacc.hxx> +#include <bitmapex.hxx> +#include <image.hxx> +#include <imgcons.hxx> + +// ------------------- +// - ImplColorMapper - +// ------------------- + +class ImplColorMapper +{ + Color maCol; + ULONG mnR; + ULONG mnG; + ULONG mnB; + ULONG mnT; + ULONG mnRShift; + ULONG mnGShift; + ULONG mnBShift; + ULONG mnTShift; + + ULONG ImplCalcMaskShift( ULONG nVal ); + +public: + + ImplColorMapper( ULONG nRMask, ULONG nGMask, ULONG nBMask, ULONG nTMask ); + ~ImplColorMapper(); + + const Color& ImplGetColor( ULONG nColor ) + { + maCol.SetRed( (UINT8) ( ( nColor & mnR ) >> mnRShift ) ); + maCol.SetGreen( (UINT8) ( ( nColor & mnG ) >> mnGShift ) ); + maCol.SetBlue( (UINT8) ( ( nColor & mnB ) >> mnBShift ) ); + maCol.SetTransparency( (UINT8) ( ( nColor & mnT ) >> mnTShift ) ); + return maCol; + } +}; + +// ----------------------------------------------------------------------------- + +ImplColorMapper::ImplColorMapper( ULONG nRMask, ULONG nGMask, ULONG nBMask, ULONG nTMask ) : + mnR( nRMask ), + mnG( nGMask ), + mnB( nBMask ), + mnT( nTMask ) +{ + mnRShift = ImplCalcMaskShift( mnR ); + mnGShift = ImplCalcMaskShift( mnG ); + mnBShift = ImplCalcMaskShift( mnB ); + mnTShift = ImplCalcMaskShift( mnT ); +} + +// ----------------------------------------------------------------------------- + +ImplColorMapper::~ImplColorMapper() +{ +} + +// ----------------------------------------------------------------------------- + +ULONG ImplColorMapper::ImplCalcMaskShift( ULONG nVal ) +{ + DBG_ASSERT( nVal > 0, "Mask has no value!" ); + + ULONG nRet = 0UL; + + for( ULONG i = 0UL; i < 32; i++ ) + { + if( nVal & ( 1UL << i ) ) + { + nRet = i; + break; + } + } + + return nRet; +} + +// ----------------- +// - ImageConsumer - +// ----------------- + +ImageConsumer::ImageConsumer() : + mnStatus( 0UL ), + mpPal ( NULL ), + mpMapper( NULL ), + mbTrans ( FALSE ) +{ +} + +// ----------------------------------------------------------------------------- + +ImageConsumer::~ImageConsumer() +{ + delete[] mpPal; + delete mpMapper; +} + +// ----------------------------------------------------------------------------- + +void ImageConsumer::Init( ULONG nWidth, ULONG nHeight ) +{ + maSize = Size( nWidth, nHeight ); + maBitmap = maMask = Bitmap(); + mnStatus = 0UL; + mbTrans = FALSE; +} + +// ----------------------------------------------------------------------------- + +void ImageConsumer::SetColorModel( USHORT nBitCount, + ULONG nPalEntries, const ULONG* pRGBAPal, + ULONG nRMask, ULONG nGMask, ULONG nBMask, ULONG nAMask ) +{ + DBG_ASSERT( maSize.Width() && maSize.Height(), "Missing call to ImageConsumer::Init(...)!" ); + + BitmapPalette aPal( Min( (USHORT) nPalEntries, (USHORT) 256 ) ); + + if( nPalEntries ) + { + BitmapColor aCol; + const ULONG* pTmp = pRGBAPal; + + delete mpMapper; + mpMapper = NULL; + + delete[] mpPal; + mpPal = new Color[ nPalEntries ]; + + for( ULONG i = 0; i < nPalEntries; i++, pTmp++ ) + { + Color& rCol = mpPal[ i ]; + BYTE cVal; + + cVal = (BYTE) ( ( *pTmp & 0xff000000UL ) >> 24UL ); + rCol.SetRed( cVal ); + if( i < 256UL ) + aPal[ (USHORT) i ].SetRed( cVal ); + + cVal = (BYTE) ( ( *pTmp & 0x00ff0000UL ) >> 16UL ); + rCol.SetGreen( cVal ); + if( i < 256UL ) + aPal[ (USHORT) i ].SetGreen( cVal ); + + cVal = (BYTE) ( ( *pTmp & 0x0000ff00UL ) >> 8UL ); + rCol.SetBlue( cVal ); + if( i < 256UL ) + aPal[ (USHORT) i ].SetBlue( cVal ); + + rCol.SetTransparency( (BYTE) ( ( *pTmp & 0x000000ffUL ) ) ); + } + + if( nBitCount <= 1 ) + nBitCount = 1; + else if( nBitCount <= 4 ) + nBitCount = 4; + else if( nBitCount <= 8 ) + nBitCount = 8; + else + nBitCount = 24; + } + else + { + delete mpMapper; + mpMapper = new ImplColorMapper( nRMask, nGMask, nBMask, nAMask ); + + delete[] mpPal; + mpPal = NULL; + + nBitCount = 24; + } + + if( !maBitmap ) + { + + maBitmap = Bitmap( maSize, nBitCount, &aPal ); + maMask = Bitmap( maSize, 1 ); + maMask.Erase( COL_BLACK ); + mbTrans = FALSE; + } +} + +// ----------------------------------------------------------------------------- + +void ImageConsumer::SetPixelsByBytes( ULONG nConsX, ULONG nConsY, + ULONG nConsWidth, ULONG nConsHeight, + const BYTE* pData, ULONG nOffset, ULONG nScanSize ) +{ + DBG_ASSERT( !!maBitmap && !!maMask, "Missing call to ImageConsumer::SetColorModel(...)!" ); + + BitmapWriteAccess* pBmpAcc = maBitmap.AcquireWriteAccess(); + BitmapWriteAccess* pMskAcc = maMask.AcquireWriteAccess(); + + if( pBmpAcc && pMskAcc ) + { + const long nWidth = pBmpAcc->Width(); + const long nHeight = pBmpAcc->Height(); + + maChangedRect = Rectangle( Point(), Size( nWidth, nHeight ) ); + maChangedRect.Intersection( Rectangle( Point( nConsX, nConsY ), Size( nConsWidth, nConsHeight ) ) ); + + if( !maChangedRect.IsEmpty() ) + { + const long nStartX = maChangedRect.Left(); + const long nEndX = maChangedRect.Right(); + const long nStartY = maChangedRect.Top(); + const long nEndY = maChangedRect.Bottom(); + + if( mpMapper && ( pBmpAcc->GetBitCount() > 8 ) ) + { + BitmapColor aCol; + BitmapColor aMskWhite( pMskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); + + for( long nY = nStartY; nY <= nEndY; nY++ ) + { + const BYTE* pTmp = pData + ( nY - nStartY ) * nScanSize + nOffset; + + for( long nX = nStartX; nX <= nEndX; nX++ ) + { + const Color& rCol = mpMapper->ImplGetColor( *pTmp++ ); + + // 0: Transparent; >0: Non-Transparent + if( !rCol.GetTransparency() ) + { + pMskAcc->SetPixel( nY, nX, aMskWhite ); + mbTrans = TRUE; + } + else + { + aCol.SetRed( rCol.GetRed() ); + aCol.SetGreen( rCol.GetGreen() ); + aCol.SetBlue( rCol.GetBlue() ); + pBmpAcc->SetPixel( nY, nX, aCol ); + } + } + } + + DataChanged(); + } + else if( mpPal && ( pBmpAcc->GetBitCount() <= 8 ) ) + { + BitmapColor aIndex( (BYTE) 0 ); + BitmapColor aMskWhite( pMskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); + + for( long nY = nStartY; nY <= nEndY; nY++ ) + { + const BYTE* pTmp = pData + ( nY - nStartY ) * nScanSize + nOffset; + + for( long nX = nStartX; nX <= nEndX; nX++ ) + { + const BYTE cIndex = *pTmp++; + const Color& rCol = mpPal[ cIndex ]; + + // 0: Transparent; >0: Non-Transparent + if( !rCol.GetTransparency() ) + { + pMskAcc->SetPixel( nY, nX, aMskWhite ); + mbTrans = TRUE; + } + else + { + aIndex.SetIndex( cIndex ); + pBmpAcc->SetPixel( nY, nX, aIndex ); + } + } + } + + DataChanged(); + } + else if( mpPal && ( pBmpAcc->GetBitCount() > 8 ) ) + { + BitmapColor aCol; + BitmapColor aMskWhite( pMskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); + + for( long nY = nStartY; nY <= nEndY; nY++ ) + { + const BYTE* pTmp = pData + ( nY - nStartY ) * nScanSize + nOffset; + + for( long nX = nStartX; nX <= nEndX; nX++ ) + { + const BYTE cIndex = *pTmp++; + const Color& rCol = mpPal[ cIndex ]; + + // 0: Transparent; >0: Non-Transparent + if( !rCol.GetTransparency() ) + { + pMskAcc->SetPixel( nY, nX, aMskWhite ); + mbTrans = TRUE; + } + else + { + aCol.SetRed( rCol.GetRed() ); + aCol.SetGreen( rCol.GetGreen() ); + aCol.SetBlue( rCol.GetBlue() ); + pBmpAcc->SetPixel( nY, nX, aCol ); + } + } + } + + DataChanged(); + } + else + { + DBG_ERROR( "Producer format error!" ); + maChangedRect.SetEmpty(); + } + } + } + else + maChangedRect.SetEmpty(); + + maBitmap.ReleaseAccess( pBmpAcc ); + maMask.ReleaseAccess( pMskAcc ); +} + +// ----------------------------------------------------------------------------- + +void ImageConsumer::SetPixelsByLongs( ULONG nConsX, ULONG nConsY, + ULONG nConsWidth, ULONG nConsHeight, + const ULONG* pData, ULONG nOffset, ULONG nScanSize ) +{ + DBG_ASSERT( !!maBitmap && !!maMask, "Missing call to ImageConsumer::SetColorModel(...)!" ); + + BitmapWriteAccess* pBmpAcc = maBitmap.AcquireWriteAccess(); + BitmapWriteAccess* pMskAcc = maMask.AcquireWriteAccess(); + + if( pBmpAcc && pMskAcc ) + { + const long nWidth = pBmpAcc->Width(); + const long nHeight = pBmpAcc->Height(); + + maChangedRect = Rectangle( Point(), Size( nWidth, nHeight ) ); + maChangedRect.Intersection( Rectangle( Point( nConsX, nConsY ), Size( nConsWidth, nConsHeight ) ) ); + + if( !maChangedRect.IsEmpty() ) + { + const long nStartX = maChangedRect.Left(); + const long nEndX = maChangedRect.Right(); + const long nStartY = maChangedRect.Top(); + const long nEndY = maChangedRect.Bottom(); + + if( mpMapper && ( pBmpAcc->GetBitCount() > 8 ) ) + { + BitmapColor aCol; + BitmapColor aMskWhite( pMskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); + + for( long nY = nStartY; nY <= nEndY; nY++ ) + { + const ULONG* pTmp = pData + ( nY - nStartY ) * nScanSize + nOffset; + + for( long nX = nStartX; nX <= nEndX; nX++ ) + { + const Color& rCol = mpMapper->ImplGetColor( *pTmp++ ); + + // 0: Transparent; >0: Non-Transparent + if( !rCol.GetTransparency() ) + { + pMskAcc->SetPixel( nY, nX, aMskWhite ); + mbTrans = TRUE; + } + else + { + aCol.SetRed( rCol.GetRed() ); + aCol.SetGreen( rCol.GetGreen() ); + aCol.SetBlue( rCol.GetBlue() ); + pBmpAcc->SetPixel( nY, nX, aCol ); + } + } + } + + DataChanged(); + } + else if( mpPal && ( pBmpAcc->GetBitCount() <= 8 ) ) + { + BitmapColor aIndex( (BYTE) 0 ); + BitmapColor aMskWhite( pMskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); + + for( long nY = nStartY; nY <= nEndY; nY++ ) + { + const ULONG* pTmp = pData + ( nY - nStartY ) * nScanSize + nOffset; + + for( long nX = nStartX; nX <= nEndX; nX++ ) + { + const ULONG nIndex = *pTmp++; + const Color& rCol = mpPal[ nIndex ]; + + // 0: Transparent; >0: Non-Transparent + if( !rCol.GetTransparency() ) + { + pMskAcc->SetPixel( nY, nX, aMskWhite ); + mbTrans = TRUE; + } + else + { + aIndex.SetIndex( (BYTE) nIndex ); + pBmpAcc->SetPixel( nY, nX, aIndex ); + } + } + } + + DataChanged(); + } + else if( mpPal && ( pBmpAcc->GetBitCount() > 8 ) ) + { + BitmapColor aCol; + BitmapColor aMskWhite( pMskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); + + for( long nY = nStartY; nY <= nEndY; nY++ ) + { + const ULONG* pTmp = pData + ( nY - nStartY ) * nScanSize + nOffset; + + for( long nX = nStartX; nX <= nEndX; nX++ ) + { + const ULONG nIndex = *pTmp++; + const Color& rCol = mpPal[ nIndex ]; + + // 0: Transparent; >0: Non-Transparent + if( !rCol.GetTransparency() ) + { + pMskAcc->SetPixel( nY, nX, aMskWhite ); + mbTrans = TRUE; + } + else + { + aCol.SetRed( rCol.GetRed() ); + aCol.SetGreen( rCol.GetGreen() ); + aCol.SetBlue( rCol.GetBlue() ); + pBmpAcc->SetPixel( nY, nX, aCol ); + } + } + } + + DataChanged(); + } + else + { + DBG_ERROR( "Producer format error!" ); + maChangedRect.SetEmpty(); + } + } + } + else + maChangedRect.SetEmpty(); + + maBitmap.ReleaseAccess( pBmpAcc ); + maMask.ReleaseAccess( pMskAcc ); +} + +// ----------------------------------------------------------------------------- + +void ImageConsumer::Completed( ULONG nStatus /*, ImageProducer& rProducer */ ) +{ + delete mpMapper; + mpMapper = NULL; + delete[] mpPal; + mpPal = NULL; + maSize = Size(); + mnStatus = nStatus; + + switch( nStatus ) + { + case( SINGLEFRAMEDONE ): + case( STATICIMAGEDONE ): + { + if( !mbTrans ) + maMask = Bitmap(); + } + break; + + case( IMAGEERROR ): + case( IMAGEABORTED ): + maBitmap = maMask = Bitmap(); + break; + + default: + break; + } + +// rProducer.RemoveConsumer( *this ); + + if( maDoneLink.IsSet() ) + maDoneLink.Call( this ); +} + +// ----------------------------------------------------------------------------- + +void ImageConsumer::DataChanged() +{ + if( maChgLink.IsSet() ) + maChgLink.Call( this ); +} + +// ----------------------------------------------------------------------------- + +ULONG ImageConsumer::GetStatus() const +{ + return mnStatus; +} + +// ----------------------------------------------------------------------------- + +BOOL ImageConsumer::GetData( BitmapEx& rBmpEx ) const +{ + const BOOL bRet = ( SINGLEFRAMEDONE == mnStatus || STATICIMAGEDONE == mnStatus ); + + if( bRet ) + { + if( !!maMask ) + rBmpEx = BitmapEx( maBitmap, maMask ); + else + rBmpEx = BitmapEx( maBitmap ); + } + + return bRet; +} + +// ----------------------------------------------------------------------------- + +BOOL ImageConsumer::GetData( Image& rImage ) const +{ + const BOOL bRet = ( SINGLEFRAMEDONE == mnStatus || STATICIMAGEDONE == mnStatus ); + + if( bRet ) + { + if( !!maMask ) + rImage = Image( maBitmap, maMask ); + else + rImage = Image( maBitmap ); + } + + return bRet; +} diff --git a/vcl/source/gdi/impanmvw.cxx b/vcl/source/gdi/impanmvw.cxx new file mode 100644 index 000000000000..fc3a943c0471 --- /dev/null +++ b/vcl/source/gdi/impanmvw.cxx @@ -0,0 +1,392 @@ +/************************************************************************* + * + * $RCSfile: impanmvw.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_IMPANMVW_CXX + +#define private public + +#include "impanmvw.hxx" +#include "virdev.hxx" +#include "window.hxx" +#include "salbtype.hxx" + +// ---------------- +// - ImplAnimView - +// ---------------- + +ImplAnimView::ImplAnimView( Animation* pParent, OutputDevice* pOut, + const Point& rPt, const Size& rSz, + ULONG nExtraData, + OutputDevice* pFirstFrameOutDev ) : + mpParent ( pParent ), + mpOut ( pFirstFrameOutDev ? pFirstFrameOutDev : pOut ), + maPt ( rPt ), + maSz ( rSz ), + maClip ( mpOut->GetClipRegion() ), + maSzPix ( mpOut->LogicToPixel( maSz ) ), + mnExtraData ( nExtraData ), + mpBackground ( new VirtualDevice ), + mpRestore ( new VirtualDevice ), + meLastDisposal ( DISPOSE_BACK ), + mbPause ( FALSE ), + mbMarked ( FALSE ), + mbHMirr ( maSz.Width() < 0L ), + mbVMirr ( maSz.Height() < 0L ) +{ + mpParent->ImplIncAnimCount(); + + // mirrored horizontically? + if( mbHMirr ) + { + maDispPt.X() = maPt.X() + maSz.Width() + 1L; + maDispSz.Width() = -maSz.Width(); + maSzPix.Width() = -maSzPix.Width(); + } + else + { + maDispPt.X() = maPt.X(); + maDispSz.Width() = maSz.Width(); + } + + // mirrored vertically? + if( mbVMirr ) + { + maDispPt.Y() = maPt.Y() + maSz.Height() + 1L; + maDispSz.Height() = -maSz.Height(); + maSzPix.Height() = -maSzPix.Height(); + } + else + { + maDispPt.Y() = maPt.Y(); + maDispSz.Height() = maSz.Height(); + } + + // save background + mpBackground->SetOutputSizePixel( maSzPix ); + + if( mpOut->GetOutDevType() == OUTDEV_WINDOW ) + { + MapMode aTempMap( mpOut->GetMapMode() ); + aTempMap.SetOrigin( Point() ); + mpBackground->SetMapMode( aTempMap ); + ( (Window*) mpOut )->SaveBackground( maDispPt, maDispSz, Point(), *mpBackground ); + mpBackground->SetMapMode( MapMode() ); + } + else + mpBackground->DrawOutDev( Point(), maSzPix, maDispPt, maDispSz, *mpOut ); + + // initial drawing to actual position + ImplDrawToPos( mpParent->ImplGetCurPos() ); + + // if first frame OutputDevice is set, update variables now for real OutputDevice + if( pFirstFrameOutDev ) + maClip = ( mpOut = pOut )->GetClipRegion(); +} + +// ------------------------------------------------------------------------ + +ImplAnimView::~ImplAnimView() +{ + delete mpBackground; + delete mpRestore; + + mpParent->ImplDecAnimCount(); +} + +// ------------------------------------------------------------------------ + +BOOL ImplAnimView::ImplMatches( OutputDevice* pOut, long nExtraData ) const +{ + BOOL bRet = FALSE; + + if( nExtraData ) + { + if( ( mnExtraData == nExtraData ) && ( !pOut || ( pOut == mpOut ) ) ) + bRet = TRUE; + } + else if( !pOut || ( pOut == mpOut ) ) + bRet = TRUE; + + return bRet; +} + +// ------------------------------------------------------------------------ + +void ImplAnimView::ImplGetPosSize( const AnimationBitmap& rAnm, Point& rPosPix, Size& rSizePix ) +{ + const Size& rAnmSize = mpParent->GetDisplaySizePixel(); + Point aPt2( rAnm.aPosPix.X() + rAnm.aSizePix.Width() - 1L, + rAnm.aPosPix.Y() + rAnm.aSizePix.Height() - 1L ); + double fFactX, fFactY; + + // calculate x scaling + if( rAnmSize.Width() > 1L ) + fFactX = (double) ( maSzPix.Width() - 1L ) / ( rAnmSize.Width() - 1L ); + else + fFactX = 1.0; + + // calculate y scaling + if( rAnmSize.Height() > 1L ) + fFactY = (double) ( maSzPix.Height() - 1L ) / ( rAnmSize.Height() - 1L ); + else + fFactY = 1.0; + + rPosPix.X() = FRound( rAnm.aPosPix.X() * fFactX ); + rPosPix.Y() = FRound( rAnm.aPosPix.Y() * fFactY ); + + aPt2.X() = FRound( aPt2.X() * fFactX ); + aPt2.Y() = FRound( aPt2.Y() * fFactY ); + + rSizePix.Width() = aPt2.X() - rPosPix.X() + 1L; + rSizePix.Height() = aPt2.Y() - rPosPix.Y() + 1L; + + // mirrored horizontically? + if( mbHMirr ) + rPosPix.X() = maSzPix.Width() - 1L - aPt2.X(); + + // mirrored vertically? + if( mbVMirr ) + rPosPix.Y() = maSzPix.Height() - 1L - aPt2.Y(); +} + +// ------------------------------------------------------------------------ + +void ImplAnimView::ImplDrawToPos( ULONG nPos ) +{ + VirtualDevice aVDev; + Region* pOldClip = !maClip.IsNull() ? new Region( mpOut->GetClipRegion() ) : NULL; + + aVDev.SetOutputSizePixel( maSzPix, FALSE ); + nPos = Min( nPos, (ULONG) mpParent->Count() - 1UL ); + + for( ULONG i = 0UL; i <= nPos; i++ ) + ImplDraw( i, &aVDev ); + + if( pOldClip ) + mpOut->SetClipRegion( maClip ); + + mpOut->DrawOutDev( maDispPt, maDispSz, Point(), maSzPix, aVDev ); + + if( pOldClip ) + { + mpOut->SetClipRegion( *pOldClip ); + delete pOldClip; + } +} + +// ------------------------------------------------------------------------ + +void ImplAnimView::ImplDraw( ULONG nPos ) +{ + ImplDraw( nPos, NULL ); +} + +// ------------------------------------------------------------------------ + +void ImplAnimView::ImplDraw( ULONG nPos, VirtualDevice* pVDev ) +{ + Rectangle aOutRect( mpOut->PixelToLogic( Point() ), mpOut->GetOutputSize() ); + + // check, if output lies out of display + if( aOutRect.Intersection( Rectangle( maDispPt, maDispSz ) ).IsEmpty() ) + ImplSetMarked( TRUE ); + else if( !mbPause ) + { + VirtualDevice* pDev; + Point aPosPix; + Point aBmpPosPix; + Size aSizePix; + Size aBmpSizePix; + const ULONG nLastPos = mpParent->Count() - 1; + const AnimationBitmap& rAnm = mpParent->Get( (USHORT) ( mnActPos = Min( nPos, nLastPos ) ) ); + + ImplGetPosSize( rAnm, aPosPix, aSizePix ); + + // mirrored horizontically? + if( mbHMirr ) + { + aBmpPosPix.X() = aPosPix.X() + aSizePix.Width() - 1L; + aBmpSizePix.Width() = -aSizePix.Width(); + } + else + { + aBmpPosPix.X() = aPosPix.X(); + aBmpSizePix.Width() = aSizePix.Width(); + } + + // mirrored vertically? + if( mbVMirr ) + { + aBmpPosPix.Y() = aPosPix.Y() + aSizePix.Height() - 1L; + aBmpSizePix.Height() = -aSizePix.Height(); + } + else + { + aBmpPosPix.Y() = aPosPix.Y(); + aBmpSizePix.Height() = aSizePix.Height(); + } + + // get output device + if( !pVDev ) + { + pDev = new VirtualDevice; + pDev->SetOutputSizePixel( maSzPix, FALSE ); + pDev->DrawOutDev( Point(), maSzPix, maDispPt, maDispSz, *mpOut ); + } + else + pDev = pVDev; + + // restore background after each run + if( !nPos ) + { + meLastDisposal = DISPOSE_BACK; + maRestPt = Point(); + maRestSz = maSzPix; + } + + // restore + if( ( DISPOSE_NOT != meLastDisposal ) && maRestSz.Width() && maRestSz.Height() ) + { + if( DISPOSE_BACK == meLastDisposal ) + pDev->DrawOutDev( maRestPt, maRestSz, maRestPt, maRestSz, *mpBackground ); + else + pDev->DrawOutDev( maRestPt, maRestSz, Point(), maRestSz, *mpRestore ); + } + + meLastDisposal = rAnm.eDisposal; + maRestPt = aPosPix; + maRestSz = aSizePix; + + // Was muessen wir beim naechsten Mal restaurieren ? + // ==> ggf. in eine Bitmap stecken, ansonsten SaveBitmap + // aus Speichergruenden loeschen + if( ( meLastDisposal == DISPOSE_BACK ) || ( meLastDisposal == DISPOSE_NOT ) ) + mpRestore->SetOutputSizePixel( Size( 1, 1 ), FALSE ); + else + { + mpRestore->SetOutputSizePixel( maRestSz, FALSE ); + mpRestore->DrawOutDev( Point(), maRestSz, aPosPix, aSizePix, *pDev ); + } + + pDev->DrawBitmapEx( aBmpPosPix, aBmpSizePix, rAnm.aBmpEx ); + + if( !pVDev ) + { + Region* pOldClip = !maClip.IsNull() ? new Region( mpOut->GetClipRegion() ) : NULL; + + if( pOldClip ) + mpOut->SetClipRegion( maClip ); + + mpOut->DrawOutDev( maDispPt, maDispSz, Point(), maSzPix, *pDev ); + + if( pOldClip ) + { + mpOut->SetClipRegion( *pOldClip ); + delete pOldClip; + } + + delete pDev; + +#ifndef REMOTE_APPSERVER + if( mpOut->GetOutDevType() == OUTDEV_WINDOW ) + ( (Window*) mpOut )->Sync(); +#endif + } + } +} + +// ------------------------------------------------------------------------ + +void ImplAnimView::ImplRepaint() +{ + const BOOL bOldPause = mbPause; + + if( mpOut->GetOutDevType() == OUTDEV_WINDOW ) + { + MapMode aTempMap( mpOut->GetMapMode() ); + aTempMap.SetOrigin( Point() ); + mpBackground->SetMapMode( aTempMap ); + ( (Window*) mpOut )->SaveBackground( maDispPt, maDispSz, Point(), *mpBackground ); + mpBackground->SetMapMode( MapMode() ); + } + else + mpBackground->DrawOutDev( Point(), maSzPix, maDispPt, maDispSz, *mpOut ); + + mbPause = FALSE; + ImplDrawToPos( mnActPos ); + mbPause = bOldPause; +} + +// ------------------------------------------------------------------------ + +AInfo* ImplAnimView::ImplCreateAInfo() const +{ + AInfo* pAInfo = new AInfo; + + pAInfo->aStartOrg = maPt; + pAInfo->aStartSize = maSz; + pAInfo->pOutDev = mpOut; + pAInfo->pViewData = (void*) this; + pAInfo->nExtraData = mnExtraData; + pAInfo->bPause = mbPause; + + return pAInfo; +} diff --git a/vcl/source/gdi/impanmvw.hxx b/vcl/source/gdi/impanmvw.hxx new file mode 100644 index 000000000000..fdefa420cc62 --- /dev/null +++ b/vcl/source/gdi/impanmvw.hxx @@ -0,0 +1,130 @@ +/************************************************************************* + * + * $RCSfile: impanmvw.hxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _SV_IMPANMVW_HXX +#define _SV_IMPANMVW_HXX + +#include "animate.hxx" + +// ---------------- +// - ImplAnimView - +// ---------------- + +class Animation; +class OutputDevice; +class VirtualDevice; +struct AnimationBitmap; + +class ImplAnimView +{ +private: + + Animation* mpParent; + OutputDevice* mpOut; + long mnExtraData; + Point maPt; + Point maDispPt; + Point maRestPt; + Size maSz; + Size maSzPix; + Size maDispSz; + Size maRestSz; + MapMode maMap; + Region maClip; + VirtualDevice* mpBackground; + VirtualDevice* mpRestore; + ULONG mnActPos; + Disposal meLastDisposal; + BOOL mbPause; + BOOL mbFirst; + BOOL mbMarked; + BOOL mbHMirr; + BOOL mbVMirr; + + void ImplGetPosSize( const AnimationBitmap& rAnm, Point& rPosPix, Size& rSizePix ); + void ImplDraw( ULONG nPos, VirtualDevice* pVDev ); + +public: + + ImplAnimView( Animation* pParent, OutputDevice* pOut, + const Point& rPt, const Size& rSz, ULONG nExtraData, + OutputDevice* pFirstFrameOutDev = NULL ); + ~ImplAnimView(); + + BOOL ImplMatches( OutputDevice* pOut, long nExtraData ) const; + void ImplDrawToPos( ULONG nPos ); + void ImplDraw( ULONG nPos ); + void ImplRepaint(); + AInfo* ImplCreateAInfo() const; + + const Point& ImplGetOutPos() const { return maPt; } + + const Size& ImplGetOutSize() const { return maSz; } + const Size& ImplGetOutSizePix() const { return maSzPix; } + + void ImplPause( BOOL bPause ) { mbPause = bPause; } + BOOL ImplIsPause() const { return mbPause; } + + void ImplSetMarked( BOOL bMarked ) { mbMarked = bMarked; } + BOOL ImplIsMarked() const { return mbMarked; } +}; + +#endif diff --git a/vcl/source/gdi/impbmp.cxx b/vcl/source/gdi/impbmp.cxx new file mode 100644 index 000000000000..3cb648163026 --- /dev/null +++ b/vcl/source/gdi/impbmp.cxx @@ -0,0 +1,309 @@ +/************************************************************************* + * + * $RCSfile: impbmp.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_IMPBMP_CXX + +#ifndef REMOTE_APPSERVER +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#ifndef _SV_SALBMP_HXX +#include <salbmp.hxx> +#endif +#else +#include <indbmp.hxx> +#ifndef _SV_RMBITMAP_HXX +#include <rmbitmap.hxx> +#endif +#endif +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#include <impbmp.hxx> +#include <bitmap.hxx> + +// -------------- +// - ImpBitmap - +// -------------- + +ImpBitmap::ImpBitmap() : + mnRefCount ( 1UL ), + mnChecksum ( 0UL ), + mpRMBitmap ( NULL ), +#ifndef REMOTE_APPSERVER + mpSalBitmap ( new SalBitmap ) +#else + mpSalBitmap ( new ImplServerBitmap ) +#endif +{ +} + +// ----------------------------------------------------------------------- + +ImpBitmap::~ImpBitmap() +{ +#ifdef REMOTE_APPSERVER + ImplReleaseRemoteBmp(); +#endif + delete mpSalBitmap; +} + +// ----------------------------------------------------------------------- +#ifndef REMOTE_APPSERVER +void ImpBitmap::ImplSetSalBitmap( SalBitmap* pBitmap ) +#else +void ImpBitmap::ImplSetSalBitmap( ImplServerBitmap* pBitmap ) +#endif +{ + delete mpSalBitmap, mpSalBitmap = pBitmap; +} + +// ----------------------------------------------------------------------- + +BOOL ImpBitmap::ImplCreate( const Size& rSize, USHORT nBitCount, const BitmapPalette& rPal ) +{ + return mpSalBitmap->Create( rSize, nBitCount, rPal ); +} + +// ----------------------------------------------------------------------- + +BOOL ImpBitmap::ImplCreate( const ImpBitmap& rImpBitmap ) +{ + mnChecksum = rImpBitmap.mnChecksum; + return mpSalBitmap->Create( *rImpBitmap.mpSalBitmap ); +} + +// ----------------------------------------------------------------------- + +BOOL ImpBitmap::ImplCreate( const ImpBitmap& rImpBitmap, SalGraphics* pGraphics ) +{ + return mpSalBitmap->Create( *rImpBitmap.mpSalBitmap, pGraphics ); +} + +// ----------------------------------------------------------------------- + +BOOL ImpBitmap::ImplCreate( const ImpBitmap& rImpBitmap, USHORT nNewBitCount ) +{ + return mpSalBitmap->Create( *rImpBitmap.mpSalBitmap, nNewBitCount ); +} + +// ----------------------------------------------------------------------- + +void ImpBitmap::ImplDestroy() +{ + mpSalBitmap->Destroy(); +} + +// ----------------------------------------------------------------------- + +Size ImpBitmap::ImplGetSize() const +{ +#ifdef REMOTE_APPSERVER + if( ImplIsGetPrepared() ) + return mpRMBitmap->GetSize(); + else +#endif + return mpSalBitmap->GetSize(); +} + +// ----------------------------------------------------------------------- + +USHORT ImpBitmap::ImplGetBitCount() const +{ + USHORT nBitCount; + +#ifdef REMOTE_APPSERVER + if( ImplIsGetPrepared() ) + nBitCount = mpRMBitmap->GetBitCount(); + else +#endif + nBitCount = mpSalBitmap->GetBitCount(); + + return( ( nBitCount <= 1 ) ? 1 : ( nBitCount <= 4 ) ? 4 : ( nBitCount <= 8 ) ? 8 : 24 ); +} + +// ----------------------------------------------------------------------- + +BitmapBuffer* ImpBitmap::ImplAcquireBuffer( BOOL bReadOnly ) +{ + return mpSalBitmap->AcquireBuffer( bReadOnly ); +} + +// ----------------------------------------------------------------------- + +void ImpBitmap::ImplReleaseBuffer( BitmapBuffer* pBuffer, BOOL bReadOnly ) +{ + mpSalBitmap->ReleaseBuffer( pBuffer, bReadOnly ); + + if( !bReadOnly ) + mnChecksum = 0; +} + +#ifdef REMOTE_APPSERVER + +RMBitmap* ImpBitmap::ImplGetRemoteBmp() +{ + return mpRMBitmap; +} + +// ----------------------------------------------------------------------- + +void ImpBitmap::ImplCreateRemoteBmp( const Bitmap& rBitmap ) +{ + DBG_ASSERT( !mpRMBitmap, "ImplCreateRemoteBmp( Bitmap& rBitmap )???" ); + + mpRMBitmap = new RMBitmap( &(Bitmap&) rBitmap ); + mpRMBitmap->Create(); +} + +// ----------------------------------------------------------------------- + +void ImpBitmap::ImplCreateRemoteBmp( const Bitmap& rBitmap, + OutputDevice* pOut, + const Point& rPt, const Size& rSz ) +{ + DBG_ASSERT( !mpRMBitmap, "ImplCreateRemoteBmp( Bitmap& rBitmap )???" ); + + mpRMBitmap = new RMBitmap( &(Bitmap&) rBitmap ); + mpRMBitmap->CreateGet( pOut, rPt, rSz ); +} + +// ----------------------------------------------------------------------- + +void ImpBitmap::ImplReleaseRemoteBmp() +{ + delete mpRMBitmap; + mpRMBitmap = NULL; +} + +// ----------------------------------------------------------------------- + +void ImpBitmap::ImplDrawRemoteBmp( OutputDevice* pOut, + const Point& rSrcPt, const Size& rSrcSz, + const Point& rDestPt, const Size& rDestSz ) +{ + if( mpRMBitmap ) + mpRMBitmap->Draw( pOut, rSrcPt, rSrcSz, rDestPt, rDestSz ); +} + +// ----------------------------------------------------------------------- + +void ImpBitmap::ImplDrawRemoteBmpEx( OutputDevice* pOut, + const Point& rSrcPt, const Size& rSrcSz, + const Point& rDestPt, const Size& rDestSz, + const Bitmap& rMask ) +{ + if( mpRMBitmap ) + mpRMBitmap->DrawEx( pOut, rSrcPt, rSrcSz, rDestPt, rDestSz, rMask ); +} + +// ----------------------------------------------------------------------- + +void ImpBitmap::ImplDrawRemoteBmpAlpha( OutputDevice* pOut, + const Point& rSrcPt, const Size& rSrcSz, + const Point& rDestPt, const Size& rDestSz, + const AlphaMask& rAlpha ) +{ + if( mpRMBitmap ) + mpRMBitmap->DrawAlpha( pOut, rSrcPt, rSrcSz, rDestPt, rDestSz, rAlpha ); +} + +// ----------------------------------------------------------------------- + +void ImpBitmap::ImplDrawRemoteBmpMask( OutputDevice* pOut, + const Point& rSrcPt, const Size& rSrcSz, + const Point& rDestPt, const Size& rDestSz, + const Color& rColor ) +{ + if( mpRMBitmap ) + mpRMBitmap->DrawMask( pOut, rSrcPt, rSrcSz, rDestPt, rDestSz, rColor ); +} + +// ----------------------------------------------------------------------- + +BOOL ImpBitmap::ImplIsGetPrepared() const +{ + return( mpRMBitmap ? mpRMBitmap->IsGetPrepared() : FALSE ); +} + +// ----------------------------------------------------------------------- + +void ImpBitmap::ImplResolveGet() +{ + if( mpRMBitmap ) + { + Bitmap aBmp; + mpRMBitmap->Get( aBmp ); + ImpBitmap* pGetImpBmp = aBmp.ImplGetImpBitmap(); + + if( pGetImpBmp ) + { + // wir nehmen der gegetteten Bitmap einfach + // die SalBitmap weg; Null-Setzen nicht vergessen, + // da die Bitmap die SalBitmap sonst abraeumt + delete mpSalBitmap; + mpSalBitmap = pGetImpBmp->mpSalBitmap; + pGetImpBmp->mpSalBitmap = NULL; + } + } +} + +#endif diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx new file mode 100644 index 000000000000..a53739ec6041 --- /dev/null +++ b/vcl/source/gdi/impgraph.cxx @@ -0,0 +1,1571 @@ +/************************************************************************* + * + * $RCSfile: impgraph.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_IMPGRAPH_CXX + +#ifndef _VCOMPAT_HXX +#include <tools/vcompat.hxx> +#endif +#ifndef _URLOBJ_HXX +#include <tools/urlobj.hxx> +#endif +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _TOOLS_TEMPFILE_HXX +#include <tools/tempfile.hxx> +#endif +#ifndef _UCBHELPER_CONTENT_HXX +#include <ucbhelper/content.hxx> +#endif +#ifndef _SV_OUTDEV_HXX +#include <outdev.hxx> +#endif +#ifndef _SV_VIRDEV_HXX +#include <virdev.hxx> +#endif +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif +#ifndef _NEW_HXX +#include <tools/new.hxx> +#endif +#include <impgraph.hxx> +#ifndef _GFXLINK_HXX +#include <gfxlink.hxx> +#endif +#ifndef _SV_CVTGRF_HXX +#include <cvtgrf.hxx> +#endif +#ifndef _SV_SALBTYPE_HXX +#include <salbtype.hxx> +#endif +#ifndef _SV_GRAPH_HXX +#include <graph.hxx> +#endif + +// ----------- +// - Defines - +// ----------- + +#define GRAPHIC_MAXPARTLEN 256000L +#define GRAPHIC_MTFTOBMP_MAXEXT 2048 +#define GRAPHIC_STREAMBUFSIZE 8192UL + +#define SYS_WINMETAFILE 0x00000003UL +#define SYS_WNTMETAFILE 0x00000004UL +#define SYS_OS2METAFILE 0x00000005UL +#define SYS_MACMETAFILE 0x00000006UL + +#define GRAPHIC_FORMAT_50 COMPAT_FORMAT( 'G', 'R', 'F', '5' ) +#define NATIVE_FORMAT_50 COMPAT_FORMAT( 'N', 'A', 'T', '5' ) + +// --------------- +// - ImpSwapFile - +// --------------- + +struct ImpSwapFile +{ + String aSwapFileName; + USHORT nRefCount; +}; + +// ----------------- +// - Graphicreader - +// ----------------- + +GraphicReader::~GraphicReader() +{ +} + +// -------------- +// - ImpGraphic - +// -------------- + +ImpGraphic::ImpGraphic() : + mpAnimation ( NULL ), + mpContext ( NULL ), + mpSwapFile ( NULL ), + mpGfxLink ( NULL ), + meType ( GRAPHIC_NONE ), + mnDocFilePos ( 0UL ), + mnRefCount ( 1UL ), + mbSwapOut ( FALSE ), + mbSwapUnderway ( FALSE ) +{ +} + +// ------------------------------------------------------------------------ + +ImpGraphic::ImpGraphic( const ImpGraphic& rImpGraphic ) : + maEx ( rImpGraphic.maEx ), + maMetaFile ( rImpGraphic.maMetaFile ), + mpContext ( NULL ), + mpSwapFile ( rImpGraphic.mpSwapFile ), + meType ( rImpGraphic.meType ), + maDocFileName ( rImpGraphic.maDocFileName ), + mnDocFilePos ( rImpGraphic.mnDocFilePos ), + mnRefCount ( 1UL ), + mbSwapOut ( rImpGraphic.mbSwapOut ), + mbSwapUnderway ( FALSE ) +{ + if( mpSwapFile ) + mpSwapFile->nRefCount++; + + if( rImpGraphic.mpGfxLink ) + mpGfxLink = new GfxLink( *rImpGraphic.mpGfxLink ); + else + mpGfxLink = NULL; + + if( rImpGraphic.mpAnimation ) + { + mpAnimation = new Animation( *rImpGraphic.mpAnimation ); + maEx = mpAnimation->GetBitmapEx(); + } + else + mpAnimation = NULL; +} + +// ------------------------------------------------------------------------ + +ImpGraphic::ImpGraphic( const Bitmap& rBitmap ) : + maEx ( rBitmap ), + mpAnimation ( NULL ), + mpContext ( NULL ), + mpSwapFile ( NULL ), + mpGfxLink ( NULL ), + meType ( !rBitmap ? GRAPHIC_NONE : GRAPHIC_BITMAP ), + mnDocFilePos ( 0UL ), + mnRefCount ( 1UL ), + mbSwapOut ( FALSE ), + mbSwapUnderway ( FALSE ) +{ +} + +// ------------------------------------------------------------------------ + +ImpGraphic::ImpGraphic( const BitmapEx& rBitmapEx ) : + maEx ( rBitmapEx ), + mpAnimation ( NULL ), + mpContext ( NULL ), + mpSwapFile ( NULL ), + mpGfxLink ( NULL ), + meType ( !rBitmapEx ? GRAPHIC_NONE : GRAPHIC_BITMAP ), + mnDocFilePos ( 0UL ), + mnRefCount ( 1UL ), + mbSwapOut ( FALSE ), + mbSwapUnderway ( FALSE ) +{ +} + +// ------------------------------------------------------------------------ + +ImpGraphic::ImpGraphic( const Animation& rAnimation ) : + maEx ( rAnimation.GetBitmapEx() ), + mpAnimation ( new Animation( rAnimation ) ), + mpContext ( NULL ), + mpSwapFile ( NULL ), + mpGfxLink ( NULL ), + meType ( GRAPHIC_BITMAP ), + mnDocFilePos ( 0UL ), + mnRefCount ( 1UL ), + mbSwapOut ( FALSE ), + mbSwapUnderway ( FALSE ) +{ +} + +// ------------------------------------------------------------------------ + +ImpGraphic::ImpGraphic( const GDIMetaFile& rMtf ) : + maMetaFile ( rMtf ), + mpAnimation ( NULL ), + mpContext ( NULL ), + mpSwapFile ( NULL ), + mpGfxLink ( NULL ), + meType ( GRAPHIC_GDIMETAFILE ), + mnDocFilePos ( 0UL ), + mnRefCount ( 1UL ), + mbSwapOut ( FALSE ), + mbSwapUnderway ( FALSE ) +{ +} + +// ------------------------------------------------------------------------ + +ImpGraphic::~ImpGraphic() +{ + ImplClear(); + + if( (ULONG) mpContext > 1UL ) + delete mpContext; +} + +// ------------------------------------------------------------------------ + +ImpGraphic& ImpGraphic::operator=( const ImpGraphic& rImpGraphic ) +{ + if( &rImpGraphic != this ) + { + if( !mbSwapUnderway ) + ImplClear(); + + maMetaFile = rImpGraphic.maMetaFile; + meType = rImpGraphic.meType; + + delete mpAnimation; + + if ( rImpGraphic.mpAnimation ) + { + mpAnimation = new Animation( *rImpGraphic.mpAnimation ); + maEx = mpAnimation->GetBitmapEx(); + } + else + { + mpAnimation = NULL; + maEx = rImpGraphic.maEx; + } + + if( !mbSwapUnderway ) + { + maDocFileName = rImpGraphic.maDocFileName; + mnDocFilePos = rImpGraphic.mnDocFilePos; + mbSwapOut = rImpGraphic.mbSwapOut; + mpSwapFile = rImpGraphic.mpSwapFile; + + if( mpSwapFile ) + mpSwapFile->nRefCount++; + } + + delete mpGfxLink; + + if( rImpGraphic.mpGfxLink ) + mpGfxLink = new GfxLink( *rImpGraphic.mpGfxLink ); + else + mpGfxLink = NULL; + } + + return *this; +} + +// ------------------------------------------------------------------------ + +BOOL ImpGraphic::operator==( const ImpGraphic& rImpGraphic ) const +{ + BOOL bRet = FALSE; + + if( this == &rImpGraphic ) + bRet = TRUE; + else if( !ImplIsSwapOut() && ( rImpGraphic.meType == meType ) ) + { + switch( meType ) + { + case( GRAPHIC_NONE ): + bRet = TRUE; + break; + + case( GRAPHIC_GDIMETAFILE ): + { + if( rImpGraphic.maMetaFile == maMetaFile ) + bRet = TRUE; + } + break; + + case( GRAPHIC_BITMAP ): + { + if( mpAnimation ) + { + if( rImpGraphic.mpAnimation && ( *rImpGraphic.mpAnimation == *mpAnimation ) ) + bRet = TRUE; + } + else if( !rImpGraphic.mpAnimation && ( rImpGraphic.maEx == maEx ) ) + bRet = TRUE; + } + break; + + default: + break; + } + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +void ImpGraphic::ImplClearGraphics( BOOL bCreateSwapInfo ) +{ + if( bCreateSwapInfo && !ImplIsSwapOut() ) + { + maSwapInfo.maPrefMapMode = ImplGetPrefMapMode(); + maSwapInfo.maPrefSize = ImplGetPrefSize(); + } + + maEx.Clear(); + maMetaFile.Clear(); + + if( mpAnimation ) + { + mpAnimation->Clear(); + delete mpAnimation; + mpAnimation = NULL; + } + + if( mpGfxLink ) + { + delete mpGfxLink; + mpGfxLink = NULL; + } +} + +// ------------------------------------------------------------------------ + +void ImpGraphic::ImplClear() +{ + if( mpSwapFile ) + { + if( mpSwapFile->nRefCount > 1 ) + mpSwapFile->nRefCount--; + else + { + try + { + ::ucb::Content aCnt( INetURLObject( mpSwapFile->aSwapFileName, INET_PROT_FILE ).GetMainURL(), + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); + + aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ), + ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) ); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + DBG_ERRORFILE( "CommandAbortedException" ); + } + catch( ... ) + { + DBG_ERRORFILE( "Any other exception" ); + } + + delete mpSwapFile; + } + + mpSwapFile = NULL; + } + + mbSwapOut = FALSE; + mnDocFilePos = 0UL; + maDocFileName.Erase(); + + // cleanup + ImplClearGraphics( FALSE ); + meType = GRAPHIC_NONE; +} + +// ------------------------------------------------------------------------ + +GraphicType ImpGraphic::ImplGetType() const +{ + return meType; +} + +// ------------------------------------------------------------------------ + +void ImpGraphic::ImplSetDefaultType() +{ + ImplClear(); + meType = GRAPHIC_DEFAULT; +} + +// ------------------------------------------------------------------------ + +BOOL ImpGraphic::ImplIsSupportedGraphic() const +{ + return( meType != GRAPHIC_NONE ); +} + +// ------------------------------------------------------------------------ + +BOOL ImpGraphic::ImplIsTransparent() const +{ + BOOL bRet; + + if( meType == GRAPHIC_BITMAP ) + bRet = ( mpAnimation ? mpAnimation->IsTransparent() : maEx.IsTransparent() ); + else + bRet = TRUE; + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL ImpGraphic::ImplIsAlpha() const +{ + BOOL bRet; + + if( meType == GRAPHIC_BITMAP ) + bRet = ( NULL == mpAnimation ) && maEx.IsAlpha(); + else + bRet = FALSE; + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL ImpGraphic::ImplIsAnimated() const +{ + return( mpAnimation != NULL ); +} + +// ------------------------------------------------------------------------ + +Bitmap ImpGraphic::ImplGetBitmap() const +{ + Bitmap aRetBmp; + + if( meType == GRAPHIC_BITMAP ) + { + const BitmapEx& rRetBmpEx = ( mpAnimation ? mpAnimation->GetBitmapEx() : maEx ); + const Color aReplaceColor( COL_WHITE ); + + aRetBmp = rRetBmpEx.GetBitmap( &aReplaceColor ); + } + else if( ( meType != GRAPHIC_DEFAULT ) && ImplIsSupportedGraphic() ) + { + VirtualDevice aVDev; + Size aSizePix( aVDev.LogicToPixel( maMetaFile.GetPrefSize(), + maMetaFile.GetPrefMapMode() ) ); + + if( aSizePix.Width() && aSizePix.Height() && + ( aSizePix.Width() > GRAPHIC_MTFTOBMP_MAXEXT || aSizePix.Height() > GRAPHIC_MTFTOBMP_MAXEXT ) ) + { + double fWH = (double) aSizePix.Width() / aSizePix.Height(); + + if( fWH <= 1.0 ) + { + aSizePix.Width() = FRound( fWH * GRAPHIC_MTFTOBMP_MAXEXT ); + aSizePix.Height() = GRAPHIC_MTFTOBMP_MAXEXT; + } + else + { + aSizePix.Width() = GRAPHIC_MTFTOBMP_MAXEXT; + aSizePix.Height() = FRound( GRAPHIC_MTFTOBMP_MAXEXT / fWH ); + } + } + + if( aVDev.SetOutputSizePixel( aSizePix ) ) + { + const Point aPt; + ImplDraw( &aVDev, aPt, aSizePix ); + aRetBmp = aVDev.GetBitmap( aPt, aSizePix ); + } + } + + if( !!aRetBmp ) + { + aRetBmp.SetPrefMapMode( ImplGetPrefMapMode() ); + aRetBmp.SetPrefSize( ImplGetPrefSize() ); + } + + return aRetBmp; +} + +// ------------------------------------------------------------------------ + +BitmapEx ImpGraphic::ImplGetBitmapEx() const +{ + BitmapEx aRetBmpEx; + + if( meType == GRAPHIC_BITMAP ) + aRetBmpEx = ( mpAnimation ? mpAnimation->GetBitmapEx() : maEx ); + else if( ( meType != GRAPHIC_DEFAULT ) && ImplIsSupportedGraphic() ) + { + const ImpGraphic aMonoMask( maMetaFile.GetMonochromeMtf( COL_BLACK ) ); + aRetBmpEx = BitmapEx( ImplGetBitmap(), aMonoMask.ImplGetBitmap() ); + } + + return aRetBmpEx; +} + +// ------------------------------------------------------------------------ + +Animation ImpGraphic::ImplGetAnimation() const +{ + Animation aAnimation; + + if( mpAnimation ) + aAnimation = *mpAnimation; + + return aAnimation; +} + +// ------------------------------------------------------------------------ + +const GDIMetaFile& ImpGraphic::ImplGetGDIMetaFile() const +{ + return maMetaFile; +} + +// ------------------------------------------------------------------------ + +Size ImpGraphic::ImplGetPrefSize() const +{ + Size aSize; + + if( ImplIsSwapOut() ) + aSize = maSwapInfo.maPrefSize; + else + { + switch( meType ) + { + case( GRAPHIC_NONE ): + case( GRAPHIC_DEFAULT ): + break; + + case( GRAPHIC_BITMAP ): + { + aSize = maEx.GetPrefSize(); + + if( !aSize.Width() || !aSize.Height() ) + aSize = maEx.GetSizePixel(); + } + break; + + default: + { + if( ImplIsSupportedGraphic() ) + aSize = maMetaFile.GetPrefSize(); + } + break; + } + } + + return aSize; +} + +// ------------------------------------------------------------------------ + +void ImpGraphic::ImplSetPrefSize( const Size& rPrefSize ) +{ + switch( meType ) + { + case( GRAPHIC_NONE ): + case( GRAPHIC_DEFAULT ): + break; + + case( GRAPHIC_BITMAP ): + maEx.SetPrefSize( rPrefSize ); + break; + + default: + { + if( ImplIsSupportedGraphic() ) + maMetaFile.SetPrefSize( rPrefSize ); + } + break; + } +} + +// ------------------------------------------------------------------------ + +MapMode ImpGraphic::ImplGetPrefMapMode() const +{ + MapMode aMapMode; + + if( ImplIsSwapOut() ) + aMapMode = maSwapInfo.maPrefMapMode; + else + { + switch( meType ) + { + case( GRAPHIC_NONE ): + case( GRAPHIC_DEFAULT ): + break; + + case( GRAPHIC_BITMAP ): + { + const Size aSize( maEx.GetPrefSize() ); + + if ( aSize.Width() && aSize.Height() ) + aMapMode = maEx.GetPrefMapMode(); + } + break; + + default: + { + if( ImplIsSupportedGraphic() ) + return maMetaFile.GetPrefMapMode(); + } + break; + } + } + + return aMapMode; +} + +// ------------------------------------------------------------------------ + +void ImpGraphic::ImplSetPrefMapMode( const MapMode& rPrefMapMode ) +{ + switch( meType ) + { + case( GRAPHIC_NONE ): + case( GRAPHIC_DEFAULT ): + break; + + case( GRAPHIC_BITMAP ): + maEx.SetPrefMapMode( rPrefMapMode ); + break; + + default: + { + if( ImplIsSupportedGraphic() ) + maMetaFile.SetPrefMapMode( rPrefMapMode ); + } + break; + } +} + +// ------------------------------------------------------------------------ + +ULONG ImpGraphic::ImplGetSizeBytes() const +{ + ULONG nSizeBytes; + + if( meType == GRAPHIC_BITMAP ) + { + if( mpAnimation ) + nSizeBytes = mpAnimation->GetSizeBytes(); + else + nSizeBytes = maEx.GetSizeBytes(); + } + else + nSizeBytes = 0UL; + + return nSizeBytes; +} + +// ------------------------------------------------------------------------ + +void ImpGraphic::ImplDraw( OutputDevice* pOutDev, const Point& rDestPt ) const +{ + if( ImplIsSupportedGraphic() && !ImplIsSwapOut() ) + { + switch( meType ) + { + case( GRAPHIC_DEFAULT ): + break; + + case( GRAPHIC_BITMAP ): + { + if ( mpAnimation ) + mpAnimation->Draw( pOutDev, rDestPt ); + else + maEx.Draw( pOutDev, rDestPt ); + } + break; + + default: + ImplDraw( pOutDev, rDestPt, maMetaFile.GetPrefSize() ); + break; + } + } +} + +// ------------------------------------------------------------------------ + +void ImpGraphic::ImplDraw( OutputDevice* pOutDev, + const Point& rDestPt, const Size& rDestSize ) const +{ + if( ImplIsSupportedGraphic() && !ImplIsSwapOut() ) + { + switch( meType ) + { + case( GRAPHIC_DEFAULT ): + break; + + case( GRAPHIC_BITMAP ): + { + if( mpAnimation ) + mpAnimation->Draw( pOutDev, rDestPt, rDestSize ); + else + maEx.Draw( pOutDev, rDestPt, rDestSize ); + } + break; + + default: + { + ( (ImpGraphic*) this )->maMetaFile.WindStart(); + ( (ImpGraphic*) this )->maMetaFile.Play( pOutDev, rDestPt, rDestSize ); + ( (ImpGraphic*) this )->maMetaFile.WindStart(); + } + break; + } + } +} + +// ------------------------------------------------------------------------ + +void ImpGraphic::ImplStartAnimation( OutputDevice* pOutDev, + const Point& rDestPt, + long nExtraData, + OutputDevice* pFirstFrameOutDev ) +{ + if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation ) + mpAnimation->Start( pOutDev, rDestPt, nExtraData, pFirstFrameOutDev ); +} + +// ------------------------------------------------------------------------ + +void ImpGraphic::ImplStartAnimation( OutputDevice* pOutDev, const Point& rDestPt, + const Size& rDestSize, long nExtraData, + OutputDevice* pFirstFrameOutDev ) +{ + if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation ) + mpAnimation->Start( pOutDev, rDestPt, rDestSize, nExtraData, pFirstFrameOutDev ); +} + +// ------------------------------------------------------------------------ + +void ImpGraphic::ImplStopAnimation( OutputDevice* pOutDev, long nExtraData ) +{ + if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation ) + mpAnimation->Stop( pOutDev, nExtraData ); +} + +// ------------------------------------------------------------------------ + +void ImpGraphic::ImplSetAnimationNotifyHdl( const Link& rLink ) +{ + if( mpAnimation ) + mpAnimation->SetNotifyHdl( rLink ); +} + +// ------------------------------------------------------------------------ + +Link ImpGraphic::ImplGetAnimationNotifyHdl() const +{ + Link aLink; + + if( mpAnimation ) + aLink = mpAnimation->GetNotifyHdl(); + + return aLink; +} + +// ------------------------------------------------------------------------ + +ULONG ImpGraphic::ImplGetAnimationLoopCount() const +{ + return( mpAnimation ? mpAnimation->GetLoopCount() : 0UL ); +} + +// ------------------------------------------------------------------------ + +void ImpGraphic::ImplResetAnimationLoopCount() +{ + if( mpAnimation ) + mpAnimation->ResetLoopCount(); +} + +// ------------------------------------------------------------------------ + +List* ImpGraphic::ImplGetAnimationInfoList() const +{ + return( mpAnimation ? mpAnimation->GetAInfoList() : NULL ); +} + +// ------------------------------------------------------------------------ + +GraphicReader* ImpGraphic::ImplGetContext() +{ + return mpContext; +} + +// ------------------------------------------------------------------------ + +void ImpGraphic::ImplSetContext( GraphicReader* pReader ) +{ + mpContext = pReader; +} + +// ------------------------------------------------------------------------ + +void ImpGraphic::ImplSetDocFileName( const String& rName, ULONG nFilePos ) +{ + maDocFileName = rName; + mnDocFilePos = nFilePos; +} + +// ------------------------------------------------------------------------ + +const String& ImpGraphic::ImplGetDocFileName() const +{ + return maDocFileName; +} + +// ------------------------------------------------------------------------ + +ULONG ImpGraphic::ImplGetDocFilePos() const +{ + return mnDocFilePos; +} + +// ------------------------------------------------------------------------ + +BOOL ImpGraphic::ImplReadEmbedded( SvStream& rIStm, BOOL bSwap ) +{ + MapMode aMapMode; + Size aSize; + const ULONG nStartPos = rIStm.Tell(); + ULONG nId; + ULONG nHeaderLen; + long nType; + long nLen; + const USHORT nOldFormat = rIStm.GetNumberFormatInt(); + BOOL bRet = FALSE; + + if( !mbSwapUnderway ) + { + const String aTempName( maDocFileName ); + const ULONG nTempPos = mnDocFilePos; + + ImplClear(); + + maDocFileName = aTempName; + mnDocFilePos = nTempPos; + } + + rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + rIStm >> nId; + + // check version + if( GRAPHIC_FORMAT_50 == nId ) + { + // read new style header + VersionCompat* pCompat = new VersionCompat( rIStm, STREAM_READ ); + + rIStm >> nType; + rIStm >> nLen; + rIStm >> aSize; + rIStm >> aMapMode; + + delete pCompat; + } + else + { + // read old style header + long nWidth, nHeight; + long nMapMode, nScaleNumX, nScaleDenomX; + long nScaleNumY, nScaleDenomY, nOffsX, nOffsY; + + rIStm.SeekRel( -4L ); + + rIStm >> nType >> nLen >> nWidth >> nHeight; + rIStm >> nMapMode >> nScaleNumX >> nScaleDenomX >> nScaleNumY; + rIStm >> nScaleDenomY >> nOffsX >> nOffsY; + + // swapped + if( nType > 100L ) + { + nType = SWAPLONG( nType ); + nLen = SWAPLONG( nLen ); + nWidth = SWAPLONG( nWidth ); + nHeight = SWAPLONG( nHeight ); + nMapMode = SWAPLONG( nMapMode ); + nScaleNumX = SWAPLONG( nScaleNumX ); + nScaleDenomX = SWAPLONG( nScaleDenomX ); + nScaleNumY = SWAPLONG( nScaleNumY ); + nScaleDenomY = SWAPLONG( nScaleDenomY ); + nOffsX = SWAPLONG( nOffsX ); + nOffsY = SWAPLONG( nOffsY ); + } + + aSize = Size( nWidth, nHeight ); + aMapMode = MapMode( (MapUnit) nMapMode, Point( nOffsX, nOffsY ), + Fraction( nScaleNumX, nScaleDenomX ), + Fraction( nScaleNumY, nScaleDenomY ) ); + } + + nHeaderLen = rIStm.Tell() - nStartPos; + meType = (GraphicType) nType; + + if( meType ) + { + if( meType == GRAPHIC_BITMAP ) + { + maEx.aBitmapSize = aSize; + + if( aMapMode != MapMode() ) + { + maEx.SetPrefMapMode( aMapMode ); + maEx.SetPrefSize( aSize ); + } + } + else + { + maMetaFile.SetPrefMapMode( aMapMode ); + maMetaFile.SetPrefSize( aSize ); + } + + if( bSwap ) + { + if( maDocFileName.Len() ) + { + rIStm.Seek( nStartPos + nHeaderLen + nLen ); + bRet = mbSwapOut = TRUE; + } + else + { + const String aTmpName( TempFile::CreateTempName() ); + + if( aTmpName.Len() ) + { + SvFileStream aOStm( aTmpName, STREAM_WRITE | STREAM_SHARE_DENYWRITE ); + + aOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + + if( !aOStm.GetError() ) + { + ULONG nFullLen = nHeaderLen + nLen; + ULONG nPartLen = Min( nFullLen, (ULONG) GRAPHIC_MAXPARTLEN ); + BYTE* pBuffer = (BYTE*) SvMemAlloc( nPartLen ); + + if( pBuffer ) + { + rIStm.Seek( nStartPos ); + + while( nFullLen ) + { + rIStm.Read( (char*) pBuffer, nPartLen ); + aOStm.Write( (char*) pBuffer, nPartLen ); + + nFullLen -= nPartLen; + + if( nFullLen < GRAPHIC_MAXPARTLEN ) + nPartLen = nFullLen; + } + + SvMemFree( pBuffer ); + + ULONG nReadErr = rIStm.GetError(); + ULONG nWriteErr = aOStm.GetError(); + + aOStm.Close(); + + if( !nReadErr && !nWriteErr ) + { + bRet = mbSwapOut = TRUE; + mpSwapFile = new ImpSwapFile; + mpSwapFile->nRefCount = 1; + mpSwapFile->aSwapFileName = aTmpName; + } + else + { + try + { + ::ucb::Content aCnt( INetURLObject( aTmpName, INET_PROT_FILE ).GetMainURL(), + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); + + aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ), + ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) ); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + DBG_ERRORFILE( "CommandAbortedException" ); + } + catch( ... ) + { + DBG_ERRORFILE( "Any other exception" ); + } + } + } + } + } + } + } + else if( meType == GRAPHIC_BITMAP || meType == GRAPHIC_GDIMETAFILE ) + { + rIStm >> *this; + bRet = ( rIStm.GetError() == 0UL ); + } + else if( meType >= SYS_WINMETAFILE && meType <= SYS_MACMETAFILE ) + { + Graphic aSysGraphic; + ULONG nCvtType; + + switch( (ULONG) meType ) + { + case( SYS_WINMETAFILE ): + case( SYS_WNTMETAFILE ): nCvtType = CVT_WMF; break; + case( SYS_OS2METAFILE ): nCvtType = CVT_MET; break; + case( SYS_MACMETAFILE ): nCvtType = CVT_PCT; break; + + default: + nCvtType = CVT_UNKNOWN; + break; + } + + if( nType && GraphicConverter::Import( rIStm, aSysGraphic, nCvtType ) == ERRCODE_NONE ) + { + *this = ImpGraphic( aSysGraphic.GetGDIMetaFile() ); + bRet = ( rIStm.GetError() == 0UL ); + } + else + meType = GRAPHIC_DEFAULT; + } + + if( bRet ) + { + ImplSetPrefMapMode( aMapMode ); + ImplSetPrefSize( aSize ); + } + } + else + bRet = TRUE; + + rIStm.SetNumberFormatInt( nOldFormat ); + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL ImpGraphic::ImplWriteEmbedded( SvStream& rOStm ) +{ + BOOL bRet = FALSE; + + if( ( meType != GRAPHIC_NONE ) && ( meType != GRAPHIC_DEFAULT ) && !ImplIsSwapOut() ) + { + const MapMode aMapMode( ImplGetPrefMapMode() ); + const Size aSize( ImplGetPrefSize() ); + const USHORT nOldFormat = rOStm.GetNumberFormatInt(); + const ULONG nStmPos1 = rOStm.Tell(); + ULONG nDataFieldPos; + + rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + + // write correct version ( old style/new style header ) + if( rOStm.GetVersion() >= SOFFICE_FILEFORMAT_50 ) + { + // write ID for new format (5.0) + rOStm << GRAPHIC_FORMAT_50; + + // write new style header + VersionCompat* pCompat = new VersionCompat( rOStm, STREAM_WRITE, 1 ); + + rOStm << (long) meType; + + // data size is updated later + nDataFieldPos = rOStm.Tell(); + rOStm << (long) 0; + + rOStm << aSize; + rOStm << aMapMode; + + delete pCompat; + } + else + { + // write old style (<=4.0) header + rOStm << (long) meType; + + // data size is updated later + nDataFieldPos = rOStm.Tell(); + rOStm << (long) 0; + + rOStm << (long) aSize.Width(); + rOStm << (long) aSize.Height(); + rOStm << (long) aMapMode.GetMapUnit(); + rOStm << (long) aMapMode.GetScaleX().GetNumerator(); + rOStm << (long) aMapMode.GetScaleX().GetDenominator(); + rOStm << (long) aMapMode.GetScaleY().GetNumerator(); + rOStm << (long) aMapMode.GetScaleY().GetDenominator(); + rOStm << (long) aMapMode.GetOrigin().X(); + rOStm << (long) aMapMode.GetOrigin().Y(); + } + + // write data block + if( !rOStm.GetError() ) + { + const ULONG nDataStart = rOStm.Tell(); + + if( ImplIsSupportedGraphic() ) + rOStm << *this; + + if( !rOStm.GetError() ) + { + const ULONG nStmPos2 = rOStm.Tell(); + rOStm.Seek( nDataFieldPos ); + rOStm << (long) ( nStmPos2 - nDataStart ); + rOStm.Seek( nStmPos2 ); + bRet = TRUE; + } + } + + rOStm.SetNumberFormatInt( nOldFormat ); + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL ImpGraphic::ImplSwapOut() +{ + BOOL bRet = FALSE; + + if( !ImplIsSwapOut() ) + { + if( !maDocFileName.Len() ) + { + const String aTmpName( TempFile::CreateTempName() ); + + if( aTmpName.Len() ) + { + SvFileStream aOStm( aTmpName, STREAM_WRITE | STREAM_SHARE_DENYWRITE ); + + aOStm.SetVersion( SOFFICE_FILEFORMAT_NOW ); + aOStm.SetCompressMode( COMPRESSMODE_NATIVE ); + + if( ( bRet = ImplSwapOut( &aOStm ) ) == TRUE ) + { + mpSwapFile = new ImpSwapFile; + mpSwapFile->nRefCount = 1; + mpSwapFile->aSwapFileName = aTmpName; + } + else + { + try + { + ::ucb::Content aCnt( INetURLObject( aTmpName, INET_PROT_FILE ).GetMainURL(), + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); + + aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ), + ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) ); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + DBG_ERRORFILE( "CommandAbortedException" ); + } + catch( ... ) + { + DBG_ERRORFILE( "Any other exception" ); + } + } + } + } + else + { + ImplClearGraphics( TRUE ); + bRet = mbSwapOut = TRUE; + } + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL ImpGraphic::ImplSwapOut( SvStream* pOStm ) +{ + BOOL bRet = FALSE; + + if( pOStm ) + { + pOStm->SetBufferSize( GRAPHIC_STREAMBUFSIZE ); + + if( !pOStm->GetError() && ImplWriteEmbedded( *pOStm ) ) + { + pOStm->Flush(); + + if( !pOStm->GetError() ) + { + ImplClearGraphics( TRUE ); + bRet = mbSwapOut = TRUE; + } + } + } + else + { + ImplClearGraphics( TRUE ); + bRet = mbSwapOut = TRUE; + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL ImpGraphic::ImplSwapIn() +{ + BOOL bRet = FALSE; + + if( ImplIsSwapOut() ) + { + const String aFileName = ( mpSwapFile ? mpSwapFile->aSwapFileName : maDocFileName ); + SvFileStream aIStm( aFileName, STREAM_READ | STREAM_SHARE_DENYWRITE ); + + aIStm.SetVersion( SOFFICE_FILEFORMAT_NOW ); + aIStm.SetCompressMode( COMPRESSMODE_NATIVE ); + + if( !mpSwapFile ) + aIStm.Seek( mnDocFilePos ); + + bRet = ImplSwapIn( &aIStm ); + aIStm.Close(); + + if( mpSwapFile ) + { + if( mpSwapFile->nRefCount > 1 ) + mpSwapFile->nRefCount--; + else + { + try + { + ::ucb::Content aCnt( INetURLObject( mpSwapFile->aSwapFileName, INET_PROT_FILE ).GetMainURL(), + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); + + aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ), + ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) ); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + DBG_ERRORFILE( "CommandAbortedException" ); + } + catch( ... ) + { + DBG_ERRORFILE( "Any other exception" ); + } + + delete mpSwapFile; + } + + mpSwapFile = NULL; + } + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL ImpGraphic::ImplSwapIn( SvStream* pIStm ) +{ + BOOL bRet = FALSE; + + if( pIStm ) + { + pIStm->SetBufferSize( GRAPHIC_STREAMBUFSIZE ); + + if( !pIStm->GetError() ) + { + mbSwapUnderway = TRUE; + bRet = ImplReadEmbedded( *pIStm ); + mbSwapUnderway = FALSE; + + if( !bRet ) + ImplClear(); + else + mbSwapOut = FALSE; + } + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL ImpGraphic::ImplIsSwapOut() const +{ + return mbSwapOut; +} + +// ------------------------------------------------------------------------ + +void ImpGraphic::ImplSetLink( const GfxLink& rGfxLink ) +{ + delete mpGfxLink; + mpGfxLink = new GfxLink( rGfxLink ); + + if( mpGfxLink->IsNative() ) + mpGfxLink->SwapOut(); +} + +// ------------------------------------------------------------------------ + +GfxLink ImpGraphic::ImplGetLink() +{ + return( mpGfxLink ? *mpGfxLink : GfxLink() ); +} + +// ------------------------------------------------------------------------ + +BOOL ImpGraphic::ImplIsLink() const +{ + return ( mpGfxLink != NULL ) ? TRUE : FALSE; +} + +// ------------------------------------------------------------------------ + +ULONG ImpGraphic::ImplGetChecksum() const +{ + ULONG nRet = 0; + + if( ImplIsSupportedGraphic() && !ImplIsSwapOut() ) + { + switch( meType ) + { + case( GRAPHIC_DEFAULT ): + break; + + case( GRAPHIC_BITMAP ): + { + if( mpAnimation ) + nRet = mpAnimation->GetChecksum(); + else + nRet = maEx.GetChecksum(); + } + break; + + default: + nRet = maMetaFile.GetChecksum(); + break; + } + } + + return nRet; +} + +// ------------------------------------------------------------------------ + +BOOL ImpGraphic::ImplCopy() const +{ + DBG_ERROR( "Missing implementation!" ); + return FALSE; +} + +// ------------------------------------------------------------------------ + +BOOL ImpGraphic::ImplPaste() +{ + DBG_ERROR( "Missing implementation!" ); + return FALSE; +} + +// ------------------------------------------------------------------------ + +SvStream& operator>>( SvStream& rIStm, ImpGraphic& rImpGraphic ) +{ + if( !rIStm.GetError() ) + { + const ULONG nStmPos1 = rIStm.Tell(); + ULONG nTmp; + + if ( !rImpGraphic.mbSwapUnderway ) + rImpGraphic.ImplClear(); + + // read Id + rIStm >> nTmp; + + if( NATIVE_FORMAT_50 == nTmp ) + { + Graphic aGraphic; + GfxLink aLink; + VersionCompat* pCompat; + + // read compat info + pCompat = new VersionCompat( rIStm, STREAM_READ ); + delete pCompat; + + rIStm >> aLink; + + // set dummy link to avoid creation of additional link after filtering; + // we set a default link to avoid unnecessary swapping of native data + aGraphic.SetLink( GfxLink() ); + + if( !rIStm.GetError() && aLink.LoadNative( aGraphic ) ) + { + // set link only, if no other link was set + const BOOL bSetLink = ( rImpGraphic.mpGfxLink == NULL ); + + // assign graphic + rImpGraphic = *aGraphic.ImplGetImpGraphic(); + + if( bSetLink ) + rImpGraphic.ImplSetLink( aLink ); + } + else + { + rIStm.Seek( nStmPos1 ); + rIStm.SetError( ERRCODE_IO_WRONGFORMAT ); + } + } + else + { + BitmapEx aBmpEx; + const USHORT nOldFormat = rIStm.GetNumberFormatInt(); + + rIStm.SeekRel( -4 ); + rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + rIStm >> aBmpEx; + + if( !rIStm.GetError() ) + { + UINT32 nMagic1, nMagic2; + ULONG nActPos = rIStm.Tell(); + + rIStm >> nMagic1 >> nMagic2; + rIStm.Seek( nActPos ); + + rImpGraphic = ImpGraphic( aBmpEx ); + + if( ( 0x5344414e == nMagic1 ) && ( 0x494d4931 == nMagic2 ) && !rIStm.GetError() ) + { + delete rImpGraphic.mpAnimation; + rImpGraphic.mpAnimation = new Animation; + rIStm >> *rImpGraphic.mpAnimation; + } + } + else + { + GDIMetaFile aMtf; + + rIStm.Seek( nStmPos1 ); + rIStm.ResetError(); + rIStm >> aMtf; + + if( !rIStm.GetError() ) + rImpGraphic = aMtf; + else + rIStm.Seek( nStmPos1 ); + } + + rIStm.SetNumberFormatInt( nOldFormat ); + } + } + + return rIStm; +} + +// ------------------------------------------------------------------------ + +SvStream& operator<<( SvStream& rOStm, const ImpGraphic& rImpGraphic ) +{ + if( !rOStm.GetError() ) + { + if( !rImpGraphic.ImplIsSwapOut() ) + { + if( ( rOStm.GetVersion() >= SOFFICE_FILEFORMAT_50 ) && + ( rOStm.GetCompressMode() & COMPRESSMODE_NATIVE ) && + rImpGraphic.mpGfxLink && rImpGraphic.mpGfxLink->IsNative() ) + { + VersionCompat* pCompat; + + // native format + rOStm << NATIVE_FORMAT_50; + + // write compat info + pCompat = new VersionCompat( rOStm, STREAM_WRITE, 1 ); + delete pCompat; + + rOStm << *rImpGraphic.mpGfxLink; + } + else + { + // own format + const USHORT nOldFormat = rOStm.GetNumberFormatInt(); + rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + + switch( rImpGraphic.ImplGetType() ) + { + case( GRAPHIC_NONE ): + case( GRAPHIC_DEFAULT ): + break; + + case GRAPHIC_BITMAP: + { + if ( rImpGraphic.ImplIsAnimated() ) + rOStm << *rImpGraphic.mpAnimation; + else + rOStm << rImpGraphic.maEx; + } + break; + + default: + { + if( rImpGraphic.ImplIsSupportedGraphic() ) + rOStm << rImpGraphic.maMetaFile; + } + break; + } + + rOStm.SetNumberFormatInt( nOldFormat ); + } + } + else + rOStm.SetError( SVSTREAM_GENERALERROR ); + } + + return rOStm; +} diff --git a/vcl/source/gdi/impimage.cxx b/vcl/source/gdi/impimage.cxx new file mode 100644 index 000000000000..1dcebb60009a --- /dev/null +++ b/vcl/source/gdi/impimage.cxx @@ -0,0 +1,744 @@ +/************************************************************************* + * + * $RCSfile: impimage.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_IMPIMAGE_CXX + +#include <string.h> + +#ifndef _SV_OUTDEV_HXX +#include <outdev.hxx> +#endif +#ifndef _SV_BITMAPEX_HXX +#include <bitmapex.hxx> +#endif +#ifndef _SV_WINDOW_HXX +#include <window.hxx> +#endif +#ifndef _SV_BMPACC_HXX +#include <bmpacc.hxx> +#endif +#ifndef _SV_VIRDEV_HXX +#include <virdev.hxx> +#endif +#ifndef _SV_IMAGE_H +#include <image.h> +#endif + +// ------------- +// - FASTIMAGE - +// ------------- + +#ifndef REMOTE_APPSERVER +#if defined WIN || defined WNT || defined OS2 +#undef FASTTRANSPARENT +extern BOOL bFastTransparent; +#else +#undef FASTTRANSPARENT +#endif +#else +#undef FASTTRANSPARENT +#endif + +// ----------- +// - Defines - +// ----------- + +#define IPOS( nPos ) ( Point( (nPos) * aSize.Width(), 0L ) ) +#define IMPSYSIMAGEITEM_NOTFREE ( 0x01 ) +#define IMPSYSIMAGEITEM_MASK ( 0x02 ) +#define DISA_ALL ( 0xffff ) +#define PAINT_ALL ( 0xffff ) + +// ---------------- +// - ImplImageBmp - +// ---------------- + +ImplImageBmp::ImplImageBmp() : + pInfoAry ( NULL ), + nCount ( 0 ), + nSize ( 0 ) +{ +} + +// ----------------------------------------------------------------------- + +ImplImageBmp::~ImplImageBmp() +{ + delete[] pInfoAry; +} + +// ----------------------------------------------------------------------- + +void ImplImageBmp::Create( long nItemWidth, long nItemHeight, USHORT nInitSize ) +{ + const Size aTotalSize( nInitSize * nItemWidth, nItemHeight ); + + nCount = 0; + aSize = Size( nItemWidth, nItemHeight ); + nSize = nInitSize; + + aBmp = Bitmap( aTotalSize, 4 ); + aMask = Bitmap( aTotalSize, 1 ); + + delete[] pInfoAry; + pInfoAry = new BYTE[ nSize ]; + memset( pInfoAry, 0, nSize ); + ImplClearCaches(); +} + +// ----------------------------------------------------------------------- + +void ImplImageBmp::Create( const Bitmap& rBmp, const Bitmap& rMaskBmp, + const Color& rColor, BOOL bColor, + long nItemWidth, long nItemHeight, USHORT nInitSize ) +{ + BYTE nStyle = IMPSYSIMAGEITEM_NOTFREE; + + ImplClearCaches(); + + if ( bColor || !!rMaskBmp ) + nStyle |= IMPSYSIMAGEITEM_MASK; + + aSize = Size( nItemWidth, nItemHeight ); + nCount = 0; + nSize = nInitSize; + + delete[] pInfoAry; + pInfoAry = new BYTE[ nSize ]; + memset( pInfoAry, nStyle, nSize ); + + aBmp = rBmp; + + if( !!rMaskBmp ) + aMask = rMaskBmp; + else if( bColor ) + aMask = aBmp.CreateMask( rColor ); + +#ifdef FASTTRANSPARENT + if( nStyle & IMPSYSIMAGEITEM_MASK ) + ImplUpdatePaintBmp( DISA_ALL ); +#endif +} + +// ----------------------------------------------------------------------- + +void ImplImageBmp::Expand( USHORT nGrowSize ) +{ + const ULONG nDX = nGrowSize * aSize.Width(); + const USHORT nOldSize = nSize; + BYTE* pNewAry = new BYTE[ nSize += nGrowSize ]; + + ImplClearCaches(); + + aBmp.Expand( nDX, 0UL ); + aMask.Expand( nDX, 0UL ); + + if( !!aDisa ) + aDisa.Expand( nDX, 0UL ); + + memset( pNewAry, 0, nSize ); + memcpy( pNewAry, pInfoAry, nOldSize ); + delete[] pInfoAry; + pInfoAry = pNewAry; +} + +// ----------------------------------------------------------------------- + +void ImplImageBmp::Replace( USHORT nPos, USHORT nSrcPos ) +{ + const Rectangle aSrcRect( IPOS( nSrcPos ), aSize ); + const Rectangle aDstRect( IPOS( nPos ), aSize ); + + ImplClearCaches(); + + aBmp.CopyPixel( aDstRect, aSrcRect ); + + if ( pInfoAry[ nSrcPos ] & IMPSYSIMAGEITEM_MASK ) + { + aMask.CopyPixel( aDstRect, aSrcRect ); + + if( !!aDisa ) + aDisa.CopyPixel( aDstRect, aSrcRect ); + } + + pInfoAry[ nPos ] = pInfoAry[ nSrcPos ]; +} + +// ----------------------------------------------------------------------- + +void ImplImageBmp::Replace( USHORT nPos, const ImplImageBmp& rImageBmp, USHORT nSrcPos ) +{ + const Rectangle aSrcRect( IPOS( nSrcPos ), aSize ); + const Rectangle aDstRect( IPOS( nPos ), aSize ); + + ImplClearCaches(); + + aBmp.CopyPixel( aDstRect, aSrcRect, &rImageBmp.aBmp ); + + if ( rImageBmp.pInfoAry[ nSrcPos ] & IMPSYSIMAGEITEM_MASK ) + { + aMask.CopyPixel( aDstRect, aSrcRect, &rImageBmp.aMask ); + + if( !!aDisa ) + aDisa.CopyPixel( aDstRect, aSrcRect, &rImageBmp.aDisa ); + } + + pInfoAry[ nPos ] = rImageBmp.pInfoAry[ nSrcPos ]; +} + +// ----------------------------------------------------------------------- + +void ImplImageBmp::Replace( USHORT nPos, const Bitmap& rBmp ) +{ + Point aPoint; + const Rectangle aSrcRect( aPoint, aSize ); + const Rectangle aDstRect( IPOS( nPos ), aSize ); + + ImplClearCaches(); + + aBmp.CopyPixel( aDstRect, aSrcRect, &rBmp ); + pInfoAry[ nPos ] &= ~IMPSYSIMAGEITEM_MASK; +} + +// ----------------------------------------------------------------------- + +void ImplImageBmp::Replace( USHORT nPos, const Bitmap& rBmp, const Bitmap& rMaskBmp ) +{ + Point aPoint; + const Rectangle aSrcRect( aPoint, aSize ); + const Rectangle aDstRect( IPOS( nPos ), aSize ); + + ImplClearCaches(); + + aBmp.CopyPixel( aDstRect, aSrcRect, &rBmp ); + aMask.CopyPixel( aDstRect, aSrcRect, &rMaskBmp ); + + if( !!aDisa ) + ImplUpdateDisaBmp( nPos ); + + pInfoAry[ nPos ] |= IMPSYSIMAGEITEM_MASK; + +#ifdef FASTTRANSPARENT + ImplUpdatePaintBmp( nPos ); +#endif +} + +// ----------------------------------------------------------------------- + +void ImplImageBmp::Replace( USHORT nPos, const Bitmap& rBmp, const Color& rColor ) +{ + Replace( nPos, rBmp, rBmp.CreateMask( rColor ) ); +} + +// ----------------------------------------------------------------------- + +void ImplImageBmp::Merge( USHORT nPos, USHORT nSrcPos ) +{ + if ( !( pInfoAry[ nSrcPos ] & IMPSYSIMAGEITEM_MASK ) ) + Replace( nPos, nSrcPos ); + else + { + ImplClearCaches(); + + const Rectangle aSrcRect( IPOS( nSrcPos ), aSize ); + const Rectangle aDstRect( IPOS( nPos ), aSize ); + BitmapWriteAccess* pBmp = aBmp.AcquireWriteAccess(); + BitmapWriteAccess* pMsk = aMask.AcquireWriteAccess(); + + if ( pBmp && pMsk ) + { + const BitmapColor aMskBlack( pMsk->GetBestMatchingColor( Color( COL_BLACK ) ) ); + BitmapColor aDstCol, aSrcCol; + long nDstLeft = aDstRect.Left(); + long nDstRight = aDstRect.Right(); + long nDstBottom = aDstRect.Bottom(); + long nSrcLeft = aSrcRect.Left(); + long nSrcRight = aSrcRect.Right(); + long nSrcTop = aSrcRect.Bottom(); + + for( long nDstY = aDstRect.Top(), nSrcY = aSrcRect.Top(); nDstY <= nDstBottom; nDstY++, nSrcY++ ) + { + for( long nDstX = nDstLeft, nSrcX = nSrcLeft; nDstX <= nDstRight; nDstX++, nSrcX++ ) + { + aDstCol = pMsk->GetPixel( nDstY, nDstX ); + aSrcCol = pMsk->GetPixel( nSrcY, nSrcX ); + + if( aMskBlack == aDstCol ) + { + if( aMskBlack == aSrcCol ) + pBmp->SetPixel( nDstY, nDstX, pBmp->GetPixel( nSrcY, nSrcX ) ); + } + else if( aMskBlack == aSrcCol ) + { + pBmp->SetPixel( nDstY, nDstX, pBmp->GetPixel( nSrcY, nSrcX ) ); + pMsk->SetPixel( nDstY, nDstX, aMskBlack ); + } + } + } + } + + aBmp.ReleaseAccess( pBmp ); + aMask.ReleaseAccess( pMsk ); + + if( !!aDisa ) + ImplUpdateDisaBmp( nPos ); + + pInfoAry[ nPos ] |= IMPSYSIMAGEITEM_MASK; + +#ifdef FASTTRANSPARENT + ImplUpdatePaintBmp( nPos ); +#endif + } +} + +// ----------------------------------------------------------------------- + +Bitmap ImplImageBmp::GetBitmap( USHORT nPosCount, USHORT* pPosAry ) const +{ + Bitmap aNewBmp( Size( nPosCount * aSize.Width(), aSize.Height() ), aBmp.GetBitCount() ); + + for( USHORT i = 0; i < nPosCount; i++ ) + { + const Rectangle aSrcRect( IPOS( pPosAry[ i ] ), aSize ); + const Rectangle aDstRect( IPOS( i ), aSize ); + + aNewBmp.CopyPixel( aDstRect, aSrcRect, &aBmp ); + } + + return aNewBmp; +} + +// ----------------------------------------------------------------------- + +BOOL ImplImageBmp::HasMaskBitmap() const +{ + return( !!aMask ); +} + +// ----------------------------------------------------------------------- + +Bitmap ImplImageBmp::GetMaskBitmap( USHORT nPosCount, USHORT* pPosAry ) const +{ + Bitmap aNewMask( Size( nPosCount * aSize.Width(), aSize.Height() ), aMask.GetBitCount() ); + + for( USHORT i = 0; i < nPosCount; i++ ) + { + const Rectangle aSrcRect( IPOS( pPosAry[ i ] ), aSize ); + const Rectangle aDstRect( IPOS( i ), aSize ); + + aNewMask.CopyPixel( aDstRect, aSrcRect, &aMask ); + } + + return aNewMask; +} + +// ----------------------------------------------------------------------- + +BOOL ImplImageBmp::HasMaskColor() const +{ + return FALSE; +} + +// ----------------------------------------------------------------------- + +Color ImplImageBmp::GetMaskColor() const +{ + return Color(); +} + +// ----------------------------------------------------------------------- + +void ImplImageBmp::Draw( USHORT nPos, OutputDevice* pOutDev, + const Point& rPos, USHORT nStyle, + const Size* pSize ) +{ + if( pOutDev->IsDeviceOutputNecessary() ) + { +#ifndef REMOTE_APPSERVER + + if( !aBmpDisp && !!aBmp ) + aBmpDisp = aBmp.CreateDisplayBitmap( pOutDev ); + + if( !aMaskDisp && !!aMask ) + aMaskDisp = aMask.CreateDisplayBitmap( pOutDev ); + +#else // REMOTE_APPSERVER + + if( !aBmpDisp && !!aBmp ) + aBmpDisp = aBmp; + + if( !aMaskDisp && !!aMask ) + aMaskDisp = aMask; + + if( !aDisaDisp && !!aDisa ) + aDisaDisp = aDisa; + +#endif // REMOTE_APPSERVER + + if( !aBmpEx ) + aBmpEx = BitmapEx( aBmpDisp, aMaskDisp ); + + if( pInfoAry[ nPos ] & IMPSYSIMAGEITEM_MASK ) + { +#ifdef FASTTRANSPARENT + BOOL bTmp = bFastTransparent; + bFastTransparent = TRUE; +#endif + + Point aOutPos = pOutDev->LogicToPixel( rPos ); + Size aOutSize; + BOOL bOldMap = pOutDev->mbMap; + + if( pSize ) + aOutSize = pOutDev->LogicToPixel( *pSize ); + else + aOutSize = aSize; + + pOutDev->mbMap = FALSE; + + if ( nStyle & IMAGE_DRAW_DISABLE ) + { + Point aOutPos1( aOutPos.X()+1, aOutPos.Y()+1 ); + const Point aPos( IPOS( nPos) ); + const StyleSettings& rSettings = pOutDev->GetSettings().GetStyleSettings(); + + if( !aDisa ) + { + aDisa = Bitmap( aBmpEx.GetSizePixel(), 1 ); + ImplUpdateDisaBmp( DISA_ALL ); +#ifndef REMOTE_APPSERVER + aDisaDisp = aDisa.CreateDisplayBitmap( pOutDev ); +#else // REMOTE_APPSERVER + aDisaDisp = aDisa; +#endif // REMOTE_APPSERVER + } + + if( !aDisaDisp && !!aDisa ) + aDisaDisp = aDisa.CreateDisplayBitmap( pOutDev ); + + pOutDev->DrawMask( aOutPos1, aOutSize, aPos, aSize, + aDisaDisp, rSettings.GetLightColor() ); + pOutDev->DrawMask( aOutPos, aOutSize, aPos, aSize, + aDisaDisp, rSettings.GetShadowColor() ); + } + else + { + BOOL bDrawn = FALSE; + + if( nStyle & ( IMAGE_DRAW_HIGHLIGHT | IMAGE_DRAW_DEACTIVE ) ) + { + Bitmap aTmpBmp( aBmp ); + BitmapWriteAccess* pAcc; + + aTmpBmp.Crop( Rectangle( IPOS( nPos ), aSize ) ); + pAcc = aTmpBmp.AcquireWriteAccess(); + + if( pAcc ) + { + const StyleSettings& rSettings = pOutDev->GetSettings().GetStyleSettings(); + Color aColor; + BitmapColor aCol; + const long nW = pAcc->Width(); + const long nH = pAcc->Height(); + BYTE* pMapR = new BYTE[ 256 ]; + BYTE* pMapG = new BYTE[ 256 ]; + BYTE* pMapB = new BYTE[ 256 ]; + long nX, nY; + + if( nStyle & IMAGE_DRAW_HIGHLIGHT ) + aColor = rSettings.GetHighlightColor(); + else + aColor = rSettings.GetDeactiveColor(); + + const BYTE cR = aColor.GetRed(); + const BYTE cG = aColor.GetGreen(); + const BYTE cB = aColor.GetBlue(); + + for( nX = 0L; nX < 256L; nX++ ) + { + pMapR[ nX ] = (BYTE) ( ( ( nY = ( nX + cR ) >> 1 ) > 255 ) ? 255 : nY ); + pMapG[ nX ] = (BYTE) ( ( ( nY = ( nX + cG ) >> 1 ) > 255 ) ? 255 : nY ); + pMapB[ nX ] = (BYTE) ( ( ( nY = ( nX + cB ) >> 1 ) > 255 ) ? 255 : nY ); + } + + if( pAcc->HasPalette() ) + { + for( USHORT i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ ) + { + const BitmapColor& rCol = pAcc->GetPaletteColor( i ); + aCol.SetRed( pMapR[ rCol.GetRed() ] ); + aCol.SetGreen( pMapG[ rCol.GetGreen() ] ); + aCol.SetBlue( pMapB[ rCol.GetBlue() ] ); + pAcc->SetPaletteColor( i, aCol ); + } + } + else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR ) + { + for( nY = 0L; nY < nH; nY++ ) + { + Scanline pScan = pAcc->GetScanline( nY ); + + for( nX = 0L; nX < nW; nX++ ) + { + *pScan = pMapB[ *pScan ]; pScan++; + *pScan = pMapG[ *pScan ]; pScan++; + *pScan = pMapR[ *pScan ]; pScan++; + } + } + } + else + { + for( nY = 0L; nY < nH; nY++ ) + { + for( nX = 0L; nX < nW; nX++ ) + { + aCol = pAcc->GetPixel( nY, nX ); + aCol.SetRed( pMapR[ aCol.GetRed() ] ); + aCol.SetGreen( pMapG[ aCol.GetGreen() ] ); + aCol.SetBlue( pMapB[ aCol.GetBlue() ] ); + pAcc->SetPixel( nY, nX, aCol ); + } + } + } + + delete[] pMapR; + delete[] pMapG; + delete[] pMapB; + aTmpBmp.ReleaseAccess( pAcc ); + + Bitmap aTmpMsk( aMask ); + aTmpMsk.Crop( Rectangle( IPOS( nPos), aSize ) ); + pOutDev->DrawBitmapEx( aOutPos, BitmapEx( aTmpBmp, aTmpMsk ) ); + bDrawn = TRUE; + } + } + + if( !bDrawn ) + pOutDev->DrawBitmapEx( aOutPos, aOutSize, IPOS( nPos), aSize, aBmpEx ); + } + + pOutDev->mbMap = bOldMap; + +#ifdef FASTTRANSPARENT + bFastTransparent = bTmp; +#endif + } + else if( pSize ) + pOutDev->DrawBitmap( rPos, *pSize, + IPOS( nPos), aSize, aBmpEx.GetBitmap() ); + else + pOutDev->DrawBitmap( rPos, pOutDev->PixelToLogic( aSize ), + IPOS( nPos), aSize, aBmpEx.GetBitmap() ); + } +} + +// ----------------------------------------------------------------------- + +void ImplImageBmp::ImplUpdateDisaBmp( USHORT nPos ) +{ + BitmapReadAccess* pAcc = aBmp.AcquireReadAccess(); + BitmapReadAccess* pMsk = aMask.AcquireReadAccess(); + BitmapWriteAccess* pDis = aDisa.AcquireWriteAccess(); + + if( pAcc && pMsk && pDis ) + { + const Color aWhite( COL_WHITE ); + const Color aBlack( COL_BLACK ); + const BitmapColor aAccWhite( pAcc->GetBestMatchingColor( aWhite ) ); + const BitmapColor aMskWhite( pMsk->GetBestMatchingColor( aWhite ) ); + const BitmapColor aDisWhite( pDis->GetBestMatchingColor( aWhite ) ); + const BitmapColor aDisBlack( pDis->GetBestMatchingColor( aBlack ) ); + long nLeft; + long nTop; + long nRight; + long nBottom; + + if( DISA_ALL != nPos ) + { + const Point aPos( IPOS( nPos ) ); + + nLeft = aPos.X(); + nTop = aPos.Y(); + nRight = nLeft + aSize.Width(); + nBottom = nTop + aSize.Height(); + } + else + { + nLeft = nTop = 0L; + nRight = pDis->Width(); + nBottom = pDis->Height(); + } + + if( pAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_MSN_PAL && + pMsk->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL ) + { + // optimized version + const BYTE cAccTest = aAccWhite.GetIndex(); + const BYTE cMskTest = aMskWhite.GetIndex(); + + for( long nY = nTop; nY < nBottom; nY++ ) + { + Scanline pAccScan = pAcc->GetScanline( nY ); + Scanline pMskScan = pMsk->GetScanline( nY ); + + for( long nX = nLeft; nX < nRight; nX++ ) + { + if( ( cMskTest == ( pMskScan[ nX >> 3 ] & ( 1 << ( 7 - ( nX & 7 ) ) ) ? 1 : 0 ) ) || + ( cAccTest == ( ( pAccScan[ nX >> 1 ] >> ( nX & 1 ? 0 : 4 ) ) & 0x0f ) ) ) + { + pDis->SetPixel( nY, nX, aDisWhite ); + } + else + pDis->SetPixel( nY, nX, aDisBlack ); + } + } + } + else if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL && + pMsk->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL ) + { + // optimized version + const BYTE cAccTest = aAccWhite.GetIndex(); + const BYTE cMskTest = aMskWhite.GetIndex(); + + for( long nY = nTop; nY < nBottom; nY++ ) + { + Scanline pAccScan = pAcc->GetScanline( nY ); + Scanline pMskScan = pMsk->GetScanline( nY ); + + for( long nX = nLeft; nX < nRight; nX++ ) + { + if( ( cMskTest == ( pMskScan[ nX >> 3 ] & ( 1 << ( 7 - ( nX & 7 ) ) ) ? 1 : 0 ) ) || + ( cAccTest == pAccScan[ nX ] ) ) + { + pDis->SetPixel( nY, nX, aDisWhite ); + } + else + pDis->SetPixel( nY, nX, aDisBlack ); + } + } + } + else + { + for( long nY = nTop; nY < nBottom; nY++ ) + { + for( long nX = nLeft; nX < nRight; nX++ ) + { + if( ( aMskWhite == pMsk->GetPixel( nY, nX ) ) || ( aAccWhite == pAcc->GetPixel( nY, nX ) ) ) + pDis->SetPixel( nY, nX, aDisWhite ); + else + pDis->SetPixel( nY, nX, aDisBlack ); + } + } + } + } + + aBmp.ReleaseAccess( pAcc ); + aMask.ReleaseAccess( pMsk ); + aDisa.ReleaseAccess( pDis ); +} + +// ----------------------------------------------------------------------- + +void ImplImageBmp::ImplUpdatePaintBmp( USHORT nPos ) +{ + BitmapWriteAccess* pBmp = aBmp.AcquireWriteAccess(); + BitmapReadAccess* pMsk = aMask.AcquireReadAccess(); + + if ( pBmp && pMsk ) + { + const Color aBlack( COL_BLACK ); + const BitmapColor aBmpBlack( pBmp->GetBestMatchingColor( aBlack ) ); + const BitmapColor aMskBlack( pMsk->GetBestMatchingColor( aBlack ) ); + long nLeft, nTop, nRight, nBottom; + + if( PAINT_ALL != nPos ) + { + const Point aPos( IPOS( nPos ) ); + + nLeft = aPos.X(); + nTop = aPos.Y(); + nRight = nLeft + aSize.Width(); + nBottom = nTop + aSize.Height(); + } + else + { + nLeft = nTop = 0L; + nRight = pBmp->Width(); + nBottom = pBmp->Height(); + } + + for( long nY = nTop; nY < nBottom; nY++ ) + for( long nX = nLeft; nX < nRight; nX++ ) + if( aMskBlack != pMsk->GetPixel( nY, nX ) ) + pBmp->SetPixel( nY, nX, aBmpBlack ); + } + + aBmp.ReleaseAccess( pBmp ); + aMask.ReleaseAccess( pMsk ); +} + +// ----------------------------------------------------------------------- + +void ImplImageBmp::ImplClearCaches() +{ + aBmpEx.Clear(); + aBmpDisp = aMaskDisp = aDisaDisp = Bitmap(); +} diff --git a/vcl/source/gdi/implncvt.cxx b/vcl/source/gdi/implncvt.cxx new file mode 100644 index 000000000000..98a428d36380 --- /dev/null +++ b/vcl/source/gdi/implncvt.cxx @@ -0,0 +1,605 @@ +/************************************************************************* + * + * $RCSfile: implncvt.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _SV_SALBTYPE_HXX +#include "salbtype.hxx" +#endif +#ifndef _SV_IMPLNCVT_HXX +#include "implncvt.hxx" +#endif + +// ----------- +// - Defines - +// ----------- + +#define CURVE_LEFT 1 +#define CURVE_RIGHT 2 +#define CURVE_STRAIGHTON 3 + +// ----------------- +// - ImplFloatPoint +// ----------------- + +struct ImplFloatPoint +{ + double fX; + double fY; + + inline ImplFloatPoint() {} + inline ImplFloatPoint( const Point& rPoint ) { fX = rPoint.X(); fY = rPoint.Y(); } + inline ImplFloatPoint( double _fX, double _fY ) { fX = _fX; fY = _fY; } + inline ImplFloatPoint( const ImplFloatPoint& rPoint ) { fX = rPoint.fX; fY = rPoint.fY; } + inline ~ImplFloatPoint() {} + + void operator+=( const ImplFloatPoint& rPoint ) { fX += rPoint.fX; fY += rPoint.fY; } + void operator-=( const ImplFloatPoint& rPoint ) { fX -= rPoint.fX; fY -= rPoint.fY; } + void operator*=( const double& rD ) { fX *= rD; fY *= rD; } + BOOL operator==( const ImplFloatPoint& rPoint ) const { return ( ( rPoint.fX == fX ) && ( rPoint.fY == fY ) ); } const + void operator=( const Point rPoint ) { fX = rPoint.X(); fY = rPoint.Y(); } + + ImplFloatPoint GetOVec( const ImplFloatPoint& rPoint ) const; + ImplFloatPoint GetNVec( const ImplFloatPoint& rPoint ) const; +}; + +// ----------------------------------------------------------------------------- + +ImplFloatPoint ImplFloatPoint::GetOVec( const ImplFloatPoint& rPoint ) const +{ + double fxt = rPoint.fX - fX; + double fyt = rPoint.fY - fY; + double fL; + + if( fyt != 0.0 ) + { + fyt = -fxt / fyt; + fL = sqrt( 1 + fyt * fyt ); + + return ImplFloatPoint( 1.0 / fL, fyt / fL ); + } + else + return ImplFloatPoint( fyt, ( fxt > 0.0 ) ? 1.0 : -1.0 ); +}; + +// ----------------------------------------------------------------------------- + +ImplFloatPoint ImplFloatPoint::GetNVec( const ImplFloatPoint& rPoint ) const +{ + const double fxt = rPoint.fX - fX; + const double fyt = rPoint.fY - fY; + const double fL = hypot( fxt, fyt ); + + return ImplFloatPoint( fxt / fL, fyt / fL ); +}; + +// -------------------- +// - ImplLineConverter +// -------------------- + +ImplLineConverter::ImplLineConverter( const Polygon& rPolygon, const LineInfo& rLineInfo, const Point* pRefPoint ) : + maLineInfo ( rLineInfo ), + mfWidthHalf ( rLineInfo.GetWidth() >> 1 ), + mpFloatPoint ( NULL ), + mpFloat0 ( new ImplFloatPoint[ 6 ] ), + mpFloat1 ( new ImplFloatPoint[ 6 ] ), + mnLines ( 0 ) +{ + UINT16 nIndex, nPolySize = rPolygon.GetSize(); + if ( nPolySize ) + { + if( rPolygon.GetFlags( 0 ) == POLY_NORMAL ) + { + mpFloatPoint = new ImplFloatPoint[ nPolySize ]; + mpFloatPoint[ 0 ] = rPolygon[ 0 ]; + + nIndex = 0; + + while( ++nIndex < nPolySize ) // doppelte Punkte eliminieren und ein FloatPointArray anlegen + { + if( rPolygon.GetFlags( nIndex ) == POLY_NORMAL ) + { + double nxt = mpFloatPoint[ mnLines ].fX; + double nyt = mpFloatPoint[ mnLines ].fY; + + if ( ( nxt == rPolygon[ nIndex ].X() ) && ( nyt == rPolygon[ nIndex ].Y() ) ) + continue; + + mpFloatPoint[ ++mnLines ] = rPolygon[ nIndex ]; + } + else + { + DBG_ERROR( "Bezier points not supported!" ); + } + } + mbClosed = ( mpFloatPoint[ 0 ] == mpFloatPoint[ mnLines ] ) ; + + if ( ( mnLines == 1 ) && ( maLineInfo.GetStyle() == LINE_DASH ) ) + { + BOOL bX = mpFloatPoint[ 0 ].fY == mpFloatPoint[ 1 ].fY; + BOOL bY = mpFloatPoint[ 0 ].fX == mpFloatPoint[ 1 ].fX; + mbRefPoint = pRefPoint && ( bX || bY ); + if ( mbRefPoint ) + { + if ( !maLineInfo.GetDashCount() ) + { + maLineInfo.SetDashCount( maLineInfo.GetDotCount() ); + maLineInfo.SetDashLen( maLineInfo.GetDotLen() ); + maLineInfo.SetDotCount( 0 ); + } + INT32 nDistance = maLineInfo.GetDistance(); + INT32 nDashLen = maLineInfo.GetDashCount() * ( maLineInfo.GetDashLen() + nDistance ); + INT32 nDotLen = maLineInfo.GetDotCount() * ( maLineInfo.GetDotLen() + nDistance ); + if ( bX ) + { + if ( mpFloatPoint[ 1 ].fX > mpFloatPoint[ 0 ].fX ) + { + ImplFloatPoint aFloat = mpFloatPoint[ 0 ]; + mpFloatPoint[ 0 ] = mpFloatPoint[ 1 ]; + mpFloatPoint[ 1 ] = aFloat; + } + mnRefDistance = (INT32)mpFloatPoint[ mnLines ].fX - pRefPoint->X(); + } + else + { + if ( mpFloatPoint[ 1 ].fY > mpFloatPoint[ 0 ].fY ) + { + ImplFloatPoint aFloat = mpFloatPoint[ 0 ]; + mpFloatPoint[ 0 ] = mpFloatPoint[ 1 ]; + mpFloatPoint[ 1 ] = aFloat; + } + mnRefDistance = (INT32)mpFloatPoint[ mnLines ].fY - pRefPoint->Y(); + } + +// mnRefDistance = ( (INT32)mpFloatPoint[ mnLines ].fX - pRefPoint->X() ) + +// ( (INT32)mpFloatPoint[ mnLines ].fY - pRefPoint->Y() ); + + mnRefDistance = mnRefDistance % ( nDashLen + nDotLen ); + if ( mnRefDistance < 0 ) + mnRefDistance = ( nDashLen + nDotLen ) + mnRefDistance; + } + } + } + } +}; + +//------------------------------------------------------------------------ + +ImplLineConverter::~ImplLineConverter() +{ + delete[] mpFloat0; + delete[] mpFloat1; + delete[] mpFloatPoint; +}; + +//------------------------------------------------------------------------ + +const Polygon* ImplLineConverter::ImplGetFirst() +{ + mnFloat1Points = 0; + mnLinesAvailable = mnLines; + + if ( mnLines ) + { + if ( maLineInfo.GetStyle() == LINE_DASH ) + { + mnDashCount = maLineInfo.GetDashCount(); + mnDotCount = maLineInfo.GetDotCount(); + mfDashDotLenght = mnDashCount ? maLineInfo.GetDashLen() : maLineInfo.GetDotLen(); + + if ( mbRefPoint ) + { + INT32 nDistance = maLineInfo.GetDistance(); + INT32 nDashLen = maLineInfo.GetDashLen() + nDistance; + INT32 nDashesLen = maLineInfo.GetDashCount() * nDashLen; + INT32 nDotLen = maLineInfo.GetDotLen() + nDistance; + INT32 nDotsLen = maLineInfo.GetDotCount() * nDotLen; + + if ( mnRefDistance >= nDashesLen ) + { + // get dotcount + if ( nDotLen ) + { + INT32 nLen = ( mnRefDistance - nDashesLen ) % nDotLen; + if ( nLen >= maLineInfo.GetDotLen() ) + { + mnDotCount -= 1 + ( mnRefDistance - nDashesLen ) / nDotLen; + if ( mnDotCount ) + mnDashCount = 0; + else + mnDotCount = maLineInfo.GetDotCount(); + mfDashDotLenght = 0.0; + mfDistanceLenght = ( maLineInfo.GetDotLen() + nDistance ) - nLen; + } + else + { + mnDashCount = 0; + mfDashDotLenght = maLineInfo.GetDotLen() - nLen; + mnDotCount -= ( mnRefDistance - nDashesLen ) / nDotLen; + } + } + } + else + { + if ( nDashLen ) + { + // get dashcount + INT32 nLen = mnRefDistance % nDashLen; + if ( nLen >= maLineInfo.GetDashLen() ) + { + mfDashDotLenght = 0.0; + mfDistanceLenght = ( maLineInfo.GetDashLen() + nDistance ) - nLen; + mnDashCount -= 1 + ( mnRefDistance / nDashLen ); + } + else + { + mfDashDotLenght = maLineInfo.GetDashLen() - nLen; + mnDashCount -= ( mnRefDistance / nDashLen ); + } + } + } + if ( ! ( mnDashCount | mnDotCount ) ) + { + mnDashCount = maLineInfo.GetDashCount(); + mnDotCount = maLineInfo.GetDotCount(); + } + if ( ( mfDashDotLenght == 0.0 ) && ( mfDistanceLenght == 0.0 ) ) + mfDistanceLenght = maLineInfo.GetDistance(); + } + } + } + return ImplGetNext(); +}; + +//------------------------------------------------------------------------ + +const Polygon* ImplLineConverter::ImplGetNext() +{ + while( mnFloat1Points || mnLinesAvailable ) + { + if ( maLineInfo.GetWidth() > 1 ) + { + if ( !mnFloat1Points ) + { + ImplFloatPoint aPointA( mpFloatPoint[ mnLinesAvailable-- ] ); + ImplFloatPoint aPointB( mpFloatPoint[ mnLinesAvailable ] ); + ImplFloatPoint aOVecAB( aPointA.GetOVec( aPointB ) ); + ImplFloatPoint aN1Vec( aPointA.GetNVec( aPointB ) ); + aN1Vec *= mfWidthHalf; + + if ( !mbClosed && ( ( mnLinesAvailable + 1 ) == mnLines ) ) + aPointA -= aN1Vec; + + aOVecAB *= mfWidthHalf; + mpFloat0[ 0 ] = aPointA; + mpFloat0[ 0 ] -= aOVecAB; + mpFloat0[ 3 ] = aPointA; + mpFloat0[ 3 ] += aOVecAB; + mpFloat0[ 1 ] = aPointB; + mpFloat0[ 1 ] -= aOVecAB; + mpFloat0[ 2 ] = aPointB; + mpFloat0[ 2 ] += aOVecAB; + + double f1D = ( aN1Vec.fX == 0 ) ? 1 : ( aN1Vec.fY / aN1Vec.fX ); + double f2D = -f1D; + + mnFloat0Points = 4; + + int nDirection; + + BOOL bContinues = ( mnLinesAvailable || mbClosed ); + if ( bContinues ) + { + ImplFloatPoint aPointC; + + if ( mnLinesAvailable ) + aPointC = mpFloatPoint[ mnLinesAvailable - 1 ]; + else + aPointC = mpFloatPoint[ mnLines - 1 ]; + + ImplFloatPoint aOVecBC( aPointB.GetOVec( aPointC ) ); + aOVecBC *= mfWidthHalf; + ImplFloatPoint aPointR0( aPointB ); + aPointR0 -= aOVecBC; + ImplFloatPoint aPointR1( aPointB ); + aPointR1 += aOVecBC; + ImplFloatPoint aN2Vec( aPointB.GetNVec( aPointC ) ); + aN2Vec *= mfWidthHalf; + + f2D = ( aN2Vec.fX == 0 ) ? 1 : ( aN2Vec.fY / aN2Vec.fX ); + if ( f1D == f2D ) + nDirection = CURVE_STRAIGHTON; + else + { + if ( ( aN1Vec.fX * aN2Vec.fY - aN1Vec.fY * aN2Vec.fX ) > 0 ) + nDirection = CURVE_LEFT; + else + nDirection = CURVE_RIGHT; + } + if ( nDirection != CURVE_STRAIGHTON ) + { + double fWidth; + ImplFloatPoint aDestPoint; + if ( hypot( aPointR0.fX - aPointA.fX, aPointR0.fY - aPointA.fY ) > hypot( aPointR1.fX - aPointA.fX, aPointR1.fY - aPointA.fY ) ) + aDestPoint = aPointR0; + else + aDestPoint = aPointR1; + + UINT16 nFirst = 0; + if ( aN1Vec.fY > 0 ) + { + if ( nDirection != CURVE_RIGHT ) + nFirst++; + } + else + { + if ( nDirection == CURVE_RIGHT ) + nFirst++; + } + fWidth = hypot( mpFloat0[ 1 + nFirst ].fX - aDestPoint.fX, mpFloat0[ 1 + nFirst ].fY - aDestPoint.fY ); + fWidth = sqrt( fWidth * fWidth / 2 ); + if ( fWidth > mfWidthHalf ) + { + // Spitzer Winkel : + mnFloat0Points = 6; + mpFloat0[ 4 + nFirst ^ 1 ] = aDestPoint; + aDestPoint -= aN2Vec; + mpFloat0[ 4 + nFirst ] = aDestPoint; + mpFloat0[ 1 + nFirst ] += aN1Vec; + } + else + { + // Stumpferwinkel : Schnittpunkt wird berechnet + mnFloat0Points = 5; + ImplFloatPoint aSourcePoint; + double fX, fY, fBDest, fBSource; + aSourcePoint = mpFloat0[ 1 + nFirst ]; + + int nValid = 0; + + if ( ( aN2Vec.fX ) == 0 ) + { + fX = aDestPoint.fX; + nValid = 1; + } + else + fBDest = aDestPoint.fY - ( aN2Vec.fY / aN2Vec.fX * aDestPoint.fX ); + + if ( ( aN1Vec.fX ) == 0 ) + { + fX = aSourcePoint.fX; + nValid = 2; + } + else + fBSource = aSourcePoint.fY - ( aN1Vec.fY / aN1Vec.fX * aSourcePoint.fX ); + + if ( !nValid ) + fX = ( fBSource - fBDest ) / ( aN2Vec.fY / aN2Vec.fX - aN1Vec.fY / aN1Vec.fX ); + if ( nValid < 2 ) + fY = aN1Vec.fY / aN1Vec.fX * fX + fBSource; + else + fY = aN2Vec.fY / aN2Vec.fX * fX + fBDest; + + mpFloat0[ 1 + nFirst ].fX = fX; + mpFloat0[ 1 + nFirst ].fY = fY; + mpFloat0[ 4 ] = aDestPoint; + } + } + else if ( ( aN1Vec.fX - aN2Vec.fX + aN1Vec.fY - aN2Vec.fY ) != 0 ) // besitzt zweiter Richtungsvektor die gleiche Steigung aber andere + bContinues = FALSE; // Richtung, dann wird hinten noch eine halbe Linienbreite angehaengt + } + if ( !bContinues ) + { + mpFloat0[ 1 ] += aN1Vec; + mpFloat0[ 2 ] += aN1Vec; + } + } + else + { + mnFloat0Points = mnFloat1Points; + ImplFloatPoint* pTemp = mpFloat1; + mpFloat1 = mpFloat0; + mpFloat0 = pTemp; + } + if ( maLineInfo.GetStyle() == LINE_DASH ) + { + double fLenghtDone = 0; + double fLenght = ( mfDashDotLenght > 0.0 ) ? mfDashDotLenght : mfDistanceLenght; + + double fDistance; + + fDistance = hypot( mpFloat0[ 0 ].fX - mpFloat0[ 1 ].fX, mpFloat0[ 0 ].fY - mpFloat0[ 1 ].fY ); + if ( mnFloat0Points == 5 ) + { + double fDist = hypot( mpFloat0[ 2 ].fX - mpFloat0[ 3 ].fX, mpFloat0[ 2 ].fY - mpFloat0[ 3 ].fY ); + if ( fDist < fDistance ) + fDistance = fDist; + } + + if ( fDistance > fLenght ) + { + fLenghtDone = fLenght; + + ImplFloatPoint aNVec( mpFloat0[ 0 ].GetNVec( mpFloat0[ 1 ] ) ); + aNVec *= fLenght; + mnFloat1Points = mnFloat0Points; + ImplFloatPoint* pTemp = mpFloat1; + mpFloat1 = mpFloat0; + mpFloat0 = pTemp; + mnFloat0Points = 4; + mpFloat0[ 0 ] = mpFloat0[ 1 ] = mpFloat1[ 0 ]; + mpFloat0[ 1 ] += aNVec; + mpFloat0[ 2 ] = mpFloat0[ 3 ] = mpFloat1[ 3 ]; + mpFloat0[ 2 ] += aNVec; + + mpFloat1[ 0 ] = mpFloat0[ 1 ]; + mpFloat1[ 3 ] = mpFloat0[ 2 ]; + } + else + { + mnFloat1Points = 0; + fLenghtDone = fDistance; + } + + if ( mfDashDotLenght > 0.0 ) + { // Ein Dash oder Dot wurde erzeugt + mfDashDotLenght -= fLenghtDone; + if ( mfDashDotLenght == 0.0 ) + { // Komplett erzeugt + if ( mnDashCount ) + mnDashCount--; + else + mnDotCount--; + + if ( ! ( mnDashCount | mnDotCount ) ) + { + mnDashCount = maLineInfo.GetDashCount(); + mnDotCount = maLineInfo.GetDotCount(); + } + mfDistanceLenght = maLineInfo.GetDistance(); + } + } + else + { // Das erzeugte Polygon muessen wir ignorieren + mfDistanceLenght -= fLenghtDone; + if ( mfDistanceLenght == 0.0 ) + mfDashDotLenght = ( mnDashCount ) ? maLineInfo.GetDashLen() : maLineInfo.GetDotLen(); + continue; + } + } + maPolygon.SetSize( (UINT16)mnFloat0Points ); + UINT16 i = 0; + maPolygon[ i++ ] = Point( FRound( mpFloat0[ 0 ].fX ), FRound( mpFloat0[ 0 ].fY ) ); + maPolygon[ i++ ] = Point( FRound( mpFloat0[ 1 ].fX ), FRound( mpFloat0[ 1 ].fY ) ); + if ( mnFloat0Points > 4 ) + maPolygon[ i++ ] = Point( FRound( mpFloat0[ 4 ].fX ), FRound( mpFloat0[ 4 ].fY ) ); + if ( mnFloat0Points > 5 ) + maPolygon[ i++ ] = Point( FRound( mpFloat0[ 5 ].fX ), FRound( mpFloat0[ 5 ].fY ) ); + maPolygon[ i++ ] = Point( FRound( mpFloat0[ 2 ].fX ), FRound( mpFloat0[ 2 ].fY ) ); + maPolygon[ i ] = Point( FRound( mpFloat0[ 3 ].fX ), FRound( mpFloat0[ 3 ].fY ) ); + + } + else + { + if ( !mnFloat1Points ) + { + mpFloat0[ 0 ] = mpFloatPoint[ mnLinesAvailable-- ]; + mpFloat0[ 1 ] = mpFloatPoint[ mnLinesAvailable ]; + } + else + { + mpFloat0[ 0 ] = mpFloat1[ 0 ]; + mpFloat0[ 1 ] = mpFloat1[ 1 ]; + } + if ( maLineInfo.GetStyle() == LINE_DASH ) + { + double fLenghtDone = 0; + double fLenght = ( mfDashDotLenght > 0.0 ) ? mfDashDotLenght : mfDistanceLenght; + double fDistance; + fDistance = hypot( mpFloat0[ 0 ].fX - mpFloat0[ 1 ].fX, mpFloat0[ 0 ].fY - mpFloat0[ 1 ].fY ); + if ( fDistance > fLenght ) + { + fLenghtDone = fLenght; + ImplFloatPoint aNVec( mpFloat0[ 0 ].GetNVec( mpFloat0[ 1 ] ) ); + aNVec *= fLenght; + mpFloat1[ 1 ] = mpFloat0[ 1 ]; + mpFloat0[ 1 ] = mpFloat0[ 0 ]; + mpFloat0[ 1 ] += aNVec; + mpFloat1[ 0 ] = mpFloat0[ 1 ]; + mnFloat1Points = 2; + } + else + { + mnFloat1Points = 0; + fLenghtDone = fDistance; + } + if ( mfDashDotLenght > 0.0 ) + { // Ein Dash oder Dot wurde erzeugt + mfDashDotLenght -= fLenghtDone; + if ( mfDashDotLenght == 0.0 ) + { // Komplett erzeugt + if ( mnDashCount ) + mnDashCount--; + else + mnDotCount--; + + if ( ! ( mnDashCount | mnDotCount ) ) + { + mnDashCount = maLineInfo.GetDashCount(); + mnDotCount = maLineInfo.GetDotCount(); + } + mfDistanceLenght = maLineInfo.GetDistance(); + } + } + else + { // Das erzeugte Polygon muessen wir ignorieren + mfDistanceLenght -= fLenghtDone; + if ( mfDistanceLenght == 0.0 ) + mfDashDotLenght = ( mnDashCount ) ? maLineInfo.GetDashLen() : maLineInfo.GetDotLen(); + continue; + } + } + maPolygon.SetSize( 2 ); + maPolygon[ 0 ] = Point( (long)mpFloat0[ 0 ].fX, (long)mpFloat0[ 0 ].fY ); + maPolygon[ 1 ] = Point( (long)mpFloat0[ 1 ].fX, (long)mpFloat0[ 1 ].fY ); + } + return &maPolygon; + } + return NULL; +}; diff --git a/vcl/source/gdi/implncvt.hxx b/vcl/source/gdi/implncvt.hxx new file mode 100644 index 000000000000..5b4aa5bcee6e --- /dev/null +++ b/vcl/source/gdi/implncvt.hxx @@ -0,0 +1,113 @@ +/************************************************************************* + * + * $RCSfile: implncvt.hxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _SV_LINECONV_HXX +#define _SV_LINECONV_HXX + +#ifndef _SV_POLY_HXX +#include <poly.hxx> +#endif +#ifndef _SV_LINEINFO_HXX +#include <lineinfo.hxx> +#endif + +// -------------------- +// - ImplLineConverter +// -------------------- + +struct ImplFloatPoint; + +class ImplLineConverter +{ + BOOL mbClosed; + BOOL mbRefPoint; + INT32 mnRefDistance; + + double mfWidthHalf; + LineInfo maLineInfo; + + double mfDashDotLenght; + double mfDistanceLenght; + + UINT32 mnDashCount; + UINT32 mnDotCount; + + Polygon maPolygon; + UINT32 mnFloat0Points; + ImplFloatPoint* mpFloat0; + UINT32 mnFloat1Points; + ImplFloatPoint* mpFloat1; + + UINT32 mnLinesAvailable; + UINT32 mnLines; + + ImplFloatPoint* mpFloatPoint; + + public: + + ImplLineConverter( const Polygon& rPoly, const LineInfo& rLineInfo, const Point* pRefPoint ); + ~ImplLineConverter(); + + const Polygon* ImplGetFirst(); + const Polygon* ImplGetNext(); +}; + +#endif diff --git a/vcl/source/gdi/impprn.cxx b/vcl/source/gdi/impprn.cxx new file mode 100644 index 000000000000..ce41b8cce763 --- /dev/null +++ b/vcl/source/gdi/impprn.cxx @@ -0,0 +1,256 @@ +/************************************************************************* + * + * $RCSfile: impprn.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef REMOTE_APPSERVER + +#define _SV_IMPPRN_CXX +#define _SPOOLPRINTER_EXT + +#ifndef _QUEUE_HXX +#include <tools/queue.hxx> +#endif + +#ifndef _SV_SVAPP_HXX +#include <svapp.hxx> +#endif +#ifndef _SV_METAACT_HXX +#include <metaact.hxx> +#endif +#ifndef _SV_GDIMTF_HXX +#include <gdimtf.hxx> +#endif +#ifndef _SV_TIMER_HXX +#include <timer.hxx> +#endif +#ifndef _SV_IMPPRN_HXX +#include <impprn.hxx> +#endif + +// ======================================================================= + +struct QueuePage +{ + GDIMetaFile* mpMtf; + JobSetup* mpSetup; + USHORT mnPage; + BOOL mbEndJob; + + QueuePage() { mpMtf = NULL; mpSetup = NULL; } + ~QueuePage() { delete mpMtf; if ( mpSetup ) delete mpSetup; } +}; + +// ======================================================================= + +ImplQPrinter::ImplQPrinter( Printer* pParent ) : + Printer( pParent->GetName() ) +{ + SetSelfAsQueuePrinter( TRUE ); + SetPrinterProps( pParent ); + SetPageQueueSize( 0 ); + mpParent = pParent; + mnCopyCount = pParent->mnCopyCount; + mbCollateCopy = pParent->mbCollateCopy; + mpQueue = new Queue( mpParent->GetPageQueueSize() ); + mbAborted = FALSE; + mbUserCopy = FALSE; + mbDestroyAllowed= TRUE; + mbDestroyed = FALSE; +} + +// ----------------------------------------------------------------------- + +ImplQPrinter::~ImplQPrinter() +{ + QueuePage* pQueuePage = (QueuePage*)mpQueue->Get(); + while ( pQueuePage ) + { + delete pQueuePage; + pQueuePage = (QueuePage*)mpQueue->Get(); + } + + delete mpQueue; +} + +// ----------------------------------------------------------------------------- + +void ImplQPrinter::Destroy() +{ + if( mbDestroyAllowed ) + delete this; + else + mbDestroyed = TRUE; +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( ImplQPrinter, ImplPrintHdl, Timer*, EMPTYARG ) +{ + // Ist Drucken abgebrochen wurden? + if ( !IsPrinting() ) + return 0; + + // Nur drucken, wenn genuegend Seiten im Cache stehen + if ( mpParent->IsJobActive() && (mpQueue->Count() < (ULONG)mpParent->GetPageQueueSize()) ) + return 0; + + // Druck-Job zuende? + QueuePage* pActPage = (QueuePage*) mpQueue->Get(); + + if ( pActPage->mbEndJob ) + { + maTimer.Stop(); + delete pActPage; + EndJob(); + mpParent->ImplEndPrint(); + } + else + { + USHORT nCopyCount = 1; + GDIMetaFile aMtf; + + mbDestroyAllowed = FALSE; + GetPreparedMetaFile( *pActPage->mpMtf, aMtf ); + + if ( mbUserCopy && !mbCollateCopy ) + nCopyCount = mnCopyCount; + + for ( USHORT i = 0; i < nCopyCount; i++ ) + { + ULONG nActionPos = 0UL; + + if ( pActPage->mpSetup ) + { + SetJobSetup( *pActPage->mpSetup ); + if ( mbAborted ) + break; + } + + StartPage(); + + if ( mbAborted ) + break; + + for( MetaAction* pAct = aMtf.FirstAction(); pAct; pAct = aMtf.NextAction() ) + { + pAct->Execute( this ); + Application::Reschedule(); + + if( mbAborted ) + break; + } + + if( !mbAborted ) + EndPage(); + else + break; + } + + delete pActPage; + mbDestroyAllowed = TRUE; + + if( mbDestroyed ) + Destroy(); + } + + return 0; +} + +// ----------------------------------------------------------------------- + +void ImplQPrinter::StartQueuePrint() +{ + maTimer.SetTimeout( 50 ); + maTimer.SetTimeoutHdl( LINK( this, ImplQPrinter, ImplPrintHdl ) ); + maTimer.Start(); +} + +// ----------------------------------------------------------------------- + +void ImplQPrinter::EndQueuePrint() +{ + QueuePage* pQueuePage = new QueuePage; + pQueuePage->mbEndJob = TRUE; + mpQueue->Put( pQueuePage ); +} + +// ----------------------------------------------------------------------- + +void ImplQPrinter::AbortQueuePrint() +{ + maTimer.Stop(); + mbAborted = TRUE; + AbortJob(); +} + +// ----------------------------------------------------------------------- + +void ImplQPrinter::AddQueuePage( GDIMetaFile* pPage, USHORT nPage, BOOL bNewJobSetup ) +{ + QueuePage* pQueuePage = new QueuePage; + pQueuePage->mpMtf = pPage; + pQueuePage->mnPage = nPage; + pQueuePage->mbEndJob = FALSE; + if ( bNewJobSetup ) + pQueuePage->mpSetup = new JobSetup( mpParent->GetJobSetup() ); + mpQueue->Put( pQueuePage ); +} + +#endif diff --git a/vcl/source/gdi/impvect.cxx b/vcl/source/gdi/impvect.cxx new file mode 100644 index 000000000000..2a3e27ebf2c5 --- /dev/null +++ b/vcl/source/gdi/impvect.cxx @@ -0,0 +1,1267 @@ +/************************************************************************* + * + * $RCSfile: impvect.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_IMPVECT_CXX + +#include <stdlib.h> +#include <tools/new.hxx> +#ifndef _SV_BMPACC_HXX +#include <bmpacc.hxx> +#endif +#ifndef _SV_POLY_HXX +#include <poly.hxx> +#endif +#ifndef _SV_GDIMTF_HXX +#include <gdimtf.hxx> +#endif +#ifndef _SV_METAACT_HXX +#include <metaact.hxx> +#endif +#ifndef _SV_SVAPP_HXX +#include <svapp.hxx> +#endif +#ifndef _SV_WRKWIN_HXX +#include <wrkwin.hxx> +#endif +#ifndef _SV_VIRDEV_HXX +#include <virdev.hxx> +#endif +#ifndef _SV_VECTORIZ_HXX +#include <impvect.hxx> +#endif + +// !!! ggf. einkommentieren, um Bitmaps zu erzeugen (nur, wenn File mit Debug uebersetzt wurde) +// #define DEBUG_BMPOUTPUT + +#if defined DEBUG && defined DEBUG_BMPOUTPUT +#define DBG_BMP 1 +#else +#undef DBG_BMP +#endif + +#ifdef DBG_BMP +#include <tools/stream.hxx> +#endif + +// ----------- +// - Defines - +// ----------- + +#define VECT_POLY_MAX 8192 + +// ----------------------------------------------------------------------------- + +#define VECT_FREE_INDEX 0 +#define VECT_CONT_INDEX 1 +#define VECT_DONE_INDEX 2 + +// ----------------------------------------------------------------------------- + +#define VECT_POLY_INLINE_INNER 1UL +#define VECT_POLY_INLINE_OUTER 2UL +#define VECT_POLY_OUTLINE_INNER 4UL +#define VECT_POLY_OUTLINE_OUTER 8UL + +// ----------------------------------------------------------------------------- + +#define VECT_MAP( _def_pIn, _def_pOut, _def_nVal ) _def_pOut[_def_nVal]=(_def_pIn[_def_nVal]=((_def_nVal)*4L)+1L)+5L; +#define BACK_MAP( _def_nVal ) ((((_def_nVal)+2)>>2)-1) +#define VECT_PROGRESS( _def_pProgress, _def_nVal ) if(_def_pProgress&&_def_pProgress->IsSet())(_def_pProgress->Call((void*)_def_nVal)); + +// ----------- +// - statics - +// ----------- + +struct ChainMove { long nDX; long nDY; }; + +static ChainMove aImplMove[ 8 ] = { + { 1L, 0L }, + { 0L, -1L }, + { -1L, 0L }, + { 0L, 1L }, + { 1L, -1L }, + { -1, -1L }, + { -1L, 1L }, + { 1L, 1L } + }; + +static ChainMove aImplMoveInner[ 8 ] = { + { 0L, 1L }, + { 1L, 0L }, + { 0L, -1L }, + { -1L, 0L }, + { 0L, 1L }, + { 1L, 0L }, + { 0L, -1L }, + { -1L, 0L } + }; + +static ChainMove aImplMoveOuter[ 8 ] = { + { 0L, -1L }, + { -1L, 0L }, + { 0L, 1L }, + { 1L, 0L }, + { -1L, 0L }, + { 0L, 1L }, + { 1L, 0L }, + { 0L, -1L } + }; + +// ---------------- +// - ImplColorSet - +// ---------------- + +struct ImplColorSet +{ + BitmapColor maColor; + USHORT mnIndex; + BOOL mbSet; + + BOOL operator<( const ImplColorSet& rSet ) const; + BOOL operator>( const ImplColorSet& rSet ) const; +}; + +// ---------------------------------------------------------------------------- + +inline BOOL ImplColorSet::operator<( const ImplColorSet& rSet ) const +{ + return( mbSet && ( !rSet.mbSet || ( maColor.GetLuminance() > rSet.maColor.GetLuminance() ) ) ); +} + +// ---------------------------------------------------------------------------- + +inline BOOL ImplColorSet::operator>( const ImplColorSet& rSet ) const +{ + return( !mbSet || ( rSet.mbSet && maColor.GetLuminance() < rSet.maColor.GetLuminance() ) ); +} + +// ---------------------------------------------------------------------------- + +extern "C" int __LOADONCALLAPI ImplColorSetCmpFnc( const void* p1, const void* p2 ) +{ + ImplColorSet* pSet1 = (ImplColorSet*) p1; + ImplColorSet* pSet2 = (ImplColorSet*) p2; + int nRet; + + if( pSet1->mbSet && pSet2->mbSet ) + { + const BYTE cLum1 = pSet1->maColor.GetLuminance(); + const BYTE cLum2 = pSet2->maColor.GetLuminance(); + nRet = ( ( cLum1 > cLum2 ) ? -1 : ( ( cLum1 == cLum2 ) ? 0 : 1 ) ); + } + else if( pSet1->mbSet ) + nRet = -1; + else if( pSet2->mbSet ) + nRet = 1; + else + nRet = 0; + + return nRet; +} + +// ------------------ +// - ImplPointArray - +// ------------------ + +#ifdef WIN +typedef Point* huge HPPoint; +#else +typedef Point* HPPoint; +#endif + +class ImplPointArray +{ + HPPoint mpArray; + ULONG mnSize; + ULONG mnRealSize; + +public: + + ImplPointArray(); + ~ImplPointArray(); + + void ImplSetSize( ULONG nSize ); + + ULONG ImplGetRealSize() const { return mnRealSize; } + void ImplSetRealSize( ULONG nRealSize ) { mnRealSize = nRealSize; } + + inline Point& operator[]( ULONG nPos ); + inline const Point& operator[]( ULONG nPos ) const; + + void ImplCreatePoly( Polygon& rPoly ) const; +}; + +// ----------------------------------------------------------------------------- + +ImplPointArray::ImplPointArray() : + mnSize ( 0UL ), + mnRealSize ( 0UL ), + mpArray ( NULL ) + +{ +} + +// ----------------------------------------------------------------------------- + +ImplPointArray::~ImplPointArray() +{ + if( mpArray ) + SvMemFree( mpArray ); +} + +// ----------------------------------------------------------------------------- + +void ImplPointArray::ImplSetSize( ULONG nSize ) +{ + const ULONG nTotal = nSize * sizeof( Point ); + + mnSize = nSize; + mnRealSize = 0UL; + + if( mpArray ) + SvMemFree( mpArray ); + + mpArray = (HPPoint) SvMemAlloc( nTotal ); + HMEMSET( (HPBYTE) mpArray, 0, nTotal ); +} + +// ----------------------------------------------------------------------------- + +inline Point& ImplPointArray::operator[]( ULONG nPos ) +{ + DBG_ASSERT( nPos < mnSize, "ImplPointArray::operator[]: nPos out of range!" ); + return mpArray[ nPos ]; +} + +// ----------------------------------------------------------------------------- + +inline const Point& ImplPointArray::operator[]( ULONG nPos ) const +{ + DBG_ASSERT( nPos < mnSize, "ImplPointArray::operator[]: nPos out of range!" ); + return mpArray[ nPos ]; +} + +// ----------------------------------------------------------------------------- + +void ImplPointArray::ImplCreatePoly( Polygon& rPoly ) const +{ + rPoly.SetSize( (USHORT) mnRealSize ); + HMEMCPY( rPoly.ImplGetPointAry(), mpArray, mnRealSize * sizeof( Point ) ); +} + +// --------------- +// - ImplVectMap - +// --------------- + +class ImplVectMap +{ +private: + + Scanline mpBuf; + Scanline* mpScan; + long mnWidth; + long mnHeight; + + ImplVectMap() {}; + +public: + + ImplVectMap( long nWidth, long nHeight ); + ~ImplVectMap(); + + inline long Width() const { return mnWidth; } + inline long Height() const { return mnHeight; } + + inline void Set( long nY, long nX, BYTE cVal ); + inline BYTE Get( long nY, long nX ) const; + + inline BOOL IsFree( long nY, long nX ) const; + inline BOOL IsCont( long nY, long nX ) const; + inline BOOL IsDone( long nY, long nX ) const; + +#ifdef DBG_BMP + Bitmap GetBitmap() const; +#endif // DBG_BMP +}; + +// ----------------------------------------------------------------------------- + +ImplVectMap::ImplVectMap( long nWidth, long nHeight ) : + mnWidth ( nWidth ), + mnHeight( nHeight ) +{ + const long nWidthAl = ( nWidth >> 2L ) + 1L; + const long nSize = nWidthAl * nHeight; + Scanline pTmp = mpBuf = (Scanline) SvMemAlloc( nSize ); + + HMEMSET( mpBuf, 0, nSize ); + mpScan = (Scanline*) SvMemAlloc( nHeight * sizeof( Scanline ) ); + + for( long nY = 0L; nY < nHeight; pTmp += nWidthAl ) + mpScan[ nY++ ] = pTmp; +} + +// ----------------------------------------------------------------------------- + + +ImplVectMap::~ImplVectMap() +{ + SvMemFree( mpBuf ); + SvMemFree( mpScan ); +} + +// ----------------------------------------------------------------------------- + +inline void ImplVectMap::Set( long nY, long nX, BYTE cVal ) +{ + const BYTE cShift = 6 - ( ( nX & 3 ) << 1 ); + ( ( mpScan[ nY ][ nX >> 2 ] ) &= ~( 3 << cShift ) ) |= ( cVal << cShift ); +} + +// ----------------------------------------------------------------------------- + +inline BYTE ImplVectMap::Get( long nY, long nX ) const +{ + return( ( ( mpScan[ nY ][ nX >> 2 ] ) >> ( 6 - ( ( nX & 3 ) << 1 ) ) ) & 3 ); +} + +// ----------------------------------------------------------------------------- + +inline BOOL ImplVectMap::IsFree( long nY, long nX ) const +{ + return( VECT_FREE_INDEX == Get( nY, nX ) ); +} + +// ----------------------------------------------------------------------------- + +inline BOOL ImplVectMap::IsCont( long nY, long nX ) const +{ + return( VECT_CONT_INDEX == Get( nY, nX ) ); +} + +// ----------------------------------------------------------------------------- + +inline BOOL ImplVectMap::IsDone( long nY, long nX ) const +{ + return( VECT_DONE_INDEX == Get( nY, nX ) ); +} + +// ----------------------------------------------------------------------------- + +#ifdef DBG_BMP +Bitmap ImplVectMap::GetBitmap() const +{ + Bitmap aBmp( Size( mnWidth, mnHeight ), 4 ); + BitmapWriteAccess* pAcc = aBmp.AcquireWriteAccess(); + + if( pAcc ) + { + for( long nY = 0L; nY < mnHeight; nY++ ) + { + for( long nX = 0L; nX < mnWidth; nX++ ) + { + switch( Get( nY, nX ) ) + { + case( VECT_FREE_INDEX ): pAcc->SetPixel( nY, nX, 15 ); break; + case( VECT_CONT_INDEX ): pAcc->SetPixel( nY, nX, 0 ); break; + case( VECT_DONE_INDEX ): pAcc->SetPixel( nY, nX, 2); break; + } + } + } + + aBmp.ReleaseAccess( pAcc ); + } + + return aBmp; +} +#endif // DBG_BMP + +// ------------- +// - ImplChain - +// ------------- + +class ImplChain +{ +private: + + Polygon maPoly; + Point maStartPt; + ULONG mnArraySize; + ULONG mnCount; + long mnResize; + BYTE* mpCodes; + + void ImplGetSpace(); + + void ImplCreate(); + void ImplCreateInner(); + void ImplCreateOuter(); + void ImplPostProcess( const ImplPointArray& rArr ); + +public: + + ImplChain( ULONG nInitCount = 1024UL, long nResize = -1L ); + ~ImplChain(); + + void ImplBeginAdd( const Point& rStartPt ); + inline void ImplAdd( BYTE nCode ); + void ImplEndAdd( ULONG nTypeFlag ); + + const Polygon& ImplGetPoly() { return maPoly; } +}; + +// ----------------------------------------------------------------------------- + +ImplChain::ImplChain( ULONG nInitCount, long nResize ) : + mnCount ( 0UL ), + mnArraySize ( nInitCount ), + mnResize ( nResize ) +{ + DBG_ASSERT( nInitCount && nResize, "ImplChain::ImplChain(): invalid parameters!" ); + mpCodes = new BYTE[ mnArraySize ]; +} + +// ----------------------------------------------------------------------------- + +ImplChain::~ImplChain() +{ + delete[] mpCodes; +} + +// ----------------------------------------------------------------------------- + +void ImplChain::ImplGetSpace() +{ + const ULONG nOldArraySize = mnArraySize; + BYTE* pNewCodes; + + mnArraySize = ( mnResize < 0L ) ? ( mnArraySize << 1UL ) : ( mnArraySize + (ULONG) mnResize ); + pNewCodes = new BYTE[ mnArraySize ]; + HMEMCPY( pNewCodes, mpCodes, nOldArraySize ); + delete[] mpCodes; + mpCodes = pNewCodes; +} + +// ----------------------------------------------------------------------------- + +void ImplChain::ImplBeginAdd( const Point& rStartPt ) +{ + maPoly = Polygon(); + maStartPt = rStartPt; + mnCount = 0UL; +} + +// ----------------------------------------------------------------------------- + +inline void ImplChain::ImplAdd( BYTE nCode ) +{ + if( mnCount == mnArraySize ) + ImplGetSpace(); + + mpCodes[ mnCount++ ] = nCode; +} + +// ----------------------------------------------------------------------------- + +void ImplChain::ImplEndAdd( ULONG nFlag ) +{ + if( mnCount ) + { + ImplPointArray aArr; + + if( nFlag & VECT_POLY_INLINE_INNER ) + { + long nFirstX, nFirstY; + long nLastX, nLastY; + + nFirstX = nLastX = maStartPt.X(); + nFirstY = nLastY = maStartPt.Y(); + aArr.ImplSetSize( mnCount << 1 ); + + USHORT i, nPolyPos; + for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ ) + { + const BYTE cMove = mpCodes[ i ]; + const BYTE cNextMove = mpCodes[ i + 1 ]; + const ChainMove& rMove = aImplMove[ cMove ]; + const ChainMove& rMoveInner = aImplMoveInner[ cMove ]; + Point& rPt = aArr[ nPolyPos ]; + BOOL bDone = TRUE; + + nLastX += rMove.nDX; + nLastY += rMove.nDY; + + if( cMove < 4 ) + { + if( ( cMove == 0 && cNextMove == 3 ) || + ( cMove == 3 && cNextMove == 2 ) || + ( cMove == 2 && cNextMove == 1 ) || + ( cMove == 1 && cNextMove == 0 ) ) + { + } + else if( cMove == 2 && cNextMove == 3 ) + { + aArr[ nPolyPos ].X() = nLastX; + aArr[ nPolyPos++ ].Y() = nLastY - 1; + + aArr[ nPolyPos ].X() = nLastX - 1; + aArr[ nPolyPos++ ].Y() = nLastY - 1; + + aArr[ nPolyPos ].X() = nLastX - 1; + aArr[ nPolyPos++ ].Y() = nLastY; + } + else if( cMove == 3 && cNextMove == 0 ) + { + aArr[ nPolyPos ].X() = nLastX - 1; + aArr[ nPolyPos++ ].Y() = nLastY; + + aArr[ nPolyPos ].X() = nLastX - 1; + aArr[ nPolyPos++ ].Y() = nLastY + 1; + + aArr[ nPolyPos ].X() = nLastX; + aArr[ nPolyPos++ ].Y() = nLastY + 1; + } + else if( cMove == 0 && cNextMove == 1 ) + { + aArr[ nPolyPos ].X() = nLastX; + aArr[ nPolyPos++ ].Y() = nLastY + 1; + + aArr[ nPolyPos ].X() = nLastX + 1; + aArr[ nPolyPos++ ].Y() = nLastY + 1; + + aArr[ nPolyPos ].X() = nLastX + 1; + aArr[ nPolyPos++ ].Y() = nLastY; + } + else if( cMove == 1 && cNextMove == 2 ) + { + aArr[ nPolyPos ].X() = nLastX + 1; + aArr[ nPolyPos++ ].Y() = nLastY + 1; + + aArr[ nPolyPos ].X() = nLastX + 1; + aArr[ nPolyPos++ ].Y() = nLastY - 1; + + aArr[ nPolyPos ].X() = nLastX; + aArr[ nPolyPos++ ].Y() = nLastY - 1; + } + else + bDone = FALSE; + } + else if( cMove == 7 && cNextMove == 0 ) + { + aArr[ nPolyPos ].X() = nLastX - 1; + aArr[ nPolyPos++ ].Y() = nLastY; + + aArr[ nPolyPos ].X() = nLastX; + aArr[ nPolyPos++ ].Y() = nLastY + 1; + } + else if( cMove == 4 && cNextMove == 1 ) + { + aArr[ nPolyPos ].X() = nLastX; + aArr[ nPolyPos++ ].Y() = nLastY + 1; + + aArr[ nPolyPos ].X() = nLastX + 1; + aArr[ nPolyPos++ ].Y() = nLastY; + } + else + bDone = FALSE; + + if( !bDone ) + { + aArr[ nPolyPos ].X() = nLastX + rMoveInner.nDX; + aArr[ nPolyPos++ ].Y() = nLastY + rMoveInner.nDY; + } + } + + aArr[ nPolyPos ].X() = nFirstX + 1L; + aArr[ nPolyPos++ ].Y() = nFirstY + 1L; + aArr.ImplSetRealSize( nPolyPos ); + } + else if( nFlag & VECT_POLY_INLINE_OUTER ) + { + long nFirstX, nFirstY; + long nLastX, nLastY; + + nFirstX = nLastX = maStartPt.X(); + nFirstY = nLastY = maStartPt.Y(); + aArr.ImplSetSize( mnCount << 1 ); + + USHORT i, nPolyPos; + for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ ) + { + const BYTE cMove = mpCodes[ i ]; + const BYTE cNextMove = mpCodes[ i + 1 ]; + const ChainMove& rMove = aImplMove[ cMove ]; + const ChainMove& rMoveOuter = aImplMoveOuter[ cMove ]; + Point& rPt = aArr[ nPolyPos ]; + BOOL bDone = TRUE; + + nLastX += rMove.nDX; + nLastY += rMove.nDY; + + if( cMove < 4 ) + { + if( ( cMove == 0 && cNextMove == 1 ) || + ( cMove == 1 && cNextMove == 2 ) || + ( cMove == 2 && cNextMove == 3 ) || + ( cMove == 3 && cNextMove == 0 ) ) + { + } + else if( cMove == 0 && cNextMove == 3 ) + { + aArr[ nPolyPos ].X() = nLastX; + aArr[ nPolyPos++ ].Y() = nLastY - 1; + + aArr[ nPolyPos ].X() = nLastX + 1; + aArr[ nPolyPos++ ].Y() = nLastY - 1; + + aArr[ nPolyPos ].X() = nLastX + 1; + aArr[ nPolyPos++ ].Y() = nLastY; + } + else if( cMove == 3 && cNextMove == 2 ) + { + aArr[ nPolyPos ].X() = nLastX + 1; + aArr[ nPolyPos++ ].Y() = nLastY; + + aArr[ nPolyPos ].X() = nLastX + 1; + aArr[ nPolyPos++ ].Y() = nLastY + 1; + + aArr[ nPolyPos ].X() = nLastX; + aArr[ nPolyPos++ ].Y() = nLastY + 1; + } + else if( cMove == 2 && cNextMove == 1 ) + { + aArr[ nPolyPos ].X() = nLastX; + aArr[ nPolyPos++ ].Y() = nLastY + 1; + + aArr[ nPolyPos ].X() = nLastX - 1; + aArr[ nPolyPos++ ].Y() = nLastY + 1; + + aArr[ nPolyPos ].X() = nLastX - 1; + aArr[ nPolyPos++ ].Y() = nLastY; + } + else if( cMove == 1 && cNextMove == 0 ) + { + aArr[ nPolyPos ].X() = nLastX - 1; + aArr[ nPolyPos++ ].Y() = nLastY; + + aArr[ nPolyPos ].X() = nLastX - 1; + aArr[ nPolyPos++ ].Y() = nLastY - 1; + + aArr[ nPolyPos ].X() = nLastX; + aArr[ nPolyPos++ ].Y() = nLastY - 1; + } + else + bDone = FALSE; + } + else if( cMove == 7 && cNextMove == 3 ) + { + aArr[ nPolyPos ].X() = nLastX; + aArr[ nPolyPos++ ].Y() = nLastY - 1; + + aArr[ nPolyPos ].X() = nLastX + 1; + aArr[ nPolyPos++ ].Y() = nLastY; + } + else if( cMove == 6 && cNextMove == 2 ) + { + aArr[ nPolyPos ].X() = nLastX + 1; + aArr[ nPolyPos++ ].Y() = nLastY; + + aArr[ nPolyPos ].X() = nLastX; + aArr[ nPolyPos++ ].Y() = nLastY + 1; + } + else + bDone = FALSE; + + if( !bDone ) + { + aArr[ nPolyPos ].X() = nLastX + rMoveOuter.nDX; + aArr[ nPolyPos++ ].Y() = nLastY + rMoveOuter.nDY; + } + } + + aArr[ nPolyPos ].X() = nFirstX - 1L; + aArr[ nPolyPos++ ].Y() = nFirstY - 1L; + aArr.ImplSetRealSize( nPolyPos ); + } + else + { + long nLastX = maStartPt.X(), nLastY = maStartPt.Y(); + + aArr.ImplSetSize( mnCount + 1 ); + aArr[ 0 ] = Point( nLastX, nLastY ); + + for( ULONG i = 0; i < mnCount; ) + { + const ChainMove& rMove = aImplMove[ mpCodes[ i ] ]; + aArr[ ++i ] = Point( nLastX += rMove.nDX, nLastY += rMove.nDY ); + } + + aArr.ImplSetRealSize( mnCount + 1 ); + } + + ImplPostProcess( aArr ); + } + else + maPoly.SetSize( 0 ); +} + +// ----------------------------------------------------------------------------- + +void ImplChain::ImplPostProcess( const ImplPointArray& rArr ) +{ + ImplPointArray aNewArr1; + ImplPointArray aNewArr2; + Point* pLast; + Point* pLeast; + ULONG nNewPos; + ULONG nCount = rArr.ImplGetRealSize(); + ULONG n; + + // pass 1 + aNewArr1.ImplSetSize( nCount ); + pLast = &( aNewArr1[ 0 ] ); + pLast->X() = BACK_MAP( rArr[ 0 ].X() ); + pLast->Y() = BACK_MAP( rArr[ 0 ].Y() ); + + for( n = nNewPos = 1; n < nCount; ) + { + const Point& rPt = rArr[ n++ ]; + const long nX = BACK_MAP( rPt.X() ); + const long nY = BACK_MAP( rPt.Y() ); + + if( nX != pLast->X() || nY != pLast->Y() ) + { + pLast = pLeast = &( aNewArr1[ nNewPos++ ] ); + pLeast->X() = nX; + pLeast->Y() = nY; + } + } + + aNewArr1.ImplSetRealSize( nCount = nNewPos ); + + // pass 2 + aNewArr2.ImplSetSize( nCount ); + pLast = &( aNewArr2[ 0 ] ); + *pLast = aNewArr1[ 0 ]; + + for( n = nNewPos = 1; n < nCount; ) + { + pLeast = &( aNewArr1[ n++ ] ); + + if( pLeast->X() == pLast->X() ) + { + while( n < nCount && aNewArr1[ n ].X() == pLast->X() ) + pLeast = &( aNewArr1[ n++ ] ); + } + else if( pLeast->Y() == pLast->Y() ) + { + while( n < nCount && aNewArr1[ n ].Y() == pLast->Y() ) + pLeast = &( aNewArr1[ n++ ] ); + } + + aNewArr2[ nNewPos++ ] = *( pLast = pLeast ); + } + + aNewArr2.ImplSetRealSize( nNewPos ); + aNewArr2.ImplCreatePoly( maPoly ); +} + +// ------------------ +// - ImplVectorizer - +// ------------------ + +ImplVectorizer::ImplVectorizer() +{ +} + +// ----------------------------------------------------------------------------- + +ImplVectorizer::~ImplVectorizer() +{ +} + +// ----------------------------------------------------------------------------- + +BOOL ImplVectorizer::ImplVectorize( const Bitmap& rColorBmp, GDIMetaFile& rMtf, + BYTE cReduce, ULONG nFlags, const Link* pProgress ) +{ + BOOL bRet = FALSE; + + VECT_PROGRESS( pProgress, 0 ); + + Bitmap* pBmp = new Bitmap( rColorBmp ); + BitmapReadAccess* pRAcc = pBmp->AcquireReadAccess(); + + if( pRAcc ) + { + PolyPolygon aPolyPoly; + double fPercent = 0.0; + double fPercentStep_2 = 0.0; + const long nWidth = pRAcc->Width(); + const long nHeight = pRAcc->Height(); + const USHORT nColorCount = pRAcc->GetPaletteEntryCount(); + USHORT n; + ImplColorSet* pColorSet = (ImplColorSet*) new BYTE[ 256 * sizeof( ImplColorSet ) ]; + + memset( pColorSet, 0, 256 * sizeof( ImplColorSet ) ); + rMtf.Clear(); + + // get used palette colors and sort them from light to dark colors + for( n = 0; n < nColorCount; n++ ) + { + pColorSet[ n ].mnIndex = n; + pColorSet[ n ].maColor = pRAcc->GetPaletteColor( n ); + } + + for( long nY = 0L; nY < nHeight; nY++ ) + for( long nX = 0L; nX < nWidth; nX++ ) + pColorSet[ pRAcc->GetPixel( nY, nX ).GetIndex() ].mbSet = 1; + + qsort( pColorSet, 256, sizeof( ImplColorSet ), ImplColorSetCmpFnc ); + + for( n = 0; n < 256; n++ ) + if( !pColorSet[ n ].mbSet ) + break; + + if( n ) + fPercentStep_2 = 45.0 / n; + + VECT_PROGRESS( pProgress, FRound( fPercent += 10.0 ) ); + + for( USHORT i = 0; i < n; i++ ) + { + const BitmapColor aBmpCol( pRAcc->GetPaletteColor( pColorSet[ i ].mnIndex ) ); + const Color aFindColor( aBmpCol.GetRed(), aBmpCol.GetGreen(), aBmpCol.GetBlue() ); + const BYTE cLum = aFindColor.GetLuminance(); + ImplVectMap* pMap = ImplExpand( pRAcc, aFindColor ); + + VECT_PROGRESS( pProgress, FRound( fPercent += fPercentStep_2 ) ); + + if( pMap ) + { + aPolyPoly.Clear(); + ImplCalculate( pMap, aPolyPoly, cReduce, nFlags ); + delete pMap; + + if( aPolyPoly.Count() ) + { + ImplLimitPolyPoly( aPolyPoly ); + + if( nFlags & BMP_VECTORIZE_REDUCE_EDGES ) + aPolyPoly.Optimize( POLY_OPTIMIZE_EDGES ); + + if( aPolyPoly.Count() ) + { + rMtf.AddAction( new MetaLineColorAction( aFindColor, TRUE ) ); + rMtf.AddAction( new MetaFillColorAction( aFindColor, TRUE ) ); + rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) ); + } + } + } + + VECT_PROGRESS( pProgress, FRound( fPercent += fPercentStep_2 ) ); + } + + delete[] (BYTE*) pColorSet; + + if( rMtf.GetActionCount() ) + { + MapMode aMap( MAP_100TH_MM ); + VirtualDevice aVDev; + const Size aLogSize1( aVDev.PixelToLogic( Size( 1, 1 ), aMap ) ); + + rMtf.SetPrefMapMode( aMap ); + rMtf.SetPrefSize( Size( nWidth + 2, nHeight + 2 ) ); + rMtf.Move( 1, 1 ); + rMtf.Scale( aLogSize1.Width(), aLogSize1.Height() ); + bRet = TRUE; + } + } + + pBmp->ReleaseAccess( pRAcc ); + delete pBmp; + VECT_PROGRESS( pProgress, 100 ); + + return bRet; +} + +// ----------------------------------------------------------------------------- + +BOOL ImplVectorizer::ImplVectorize( const Bitmap& rMonoBmp, + PolyPolygon& rPolyPoly, + ULONG nFlags, const Link* pProgress ) +{ + Bitmap* pBmp = new Bitmap( rMonoBmp ); + BitmapReadAccess* pRAcc; + ImplVectMap* pMap; + BOOL bRet = FALSE; + + VECT_PROGRESS( pProgress, 10 ); + + if( pBmp->GetBitCount() > 1 ) + pBmp->Convert( BMP_CONVERSION_1BIT_THRESHOLD ); + + VECT_PROGRESS( pProgress, 30 ); + + pRAcc = pBmp->AcquireReadAccess(); + pMap = ImplExpand( pRAcc, COL_BLACK ); + pBmp->ReleaseAccess( pRAcc ); + delete pBmp; + + VECT_PROGRESS( pProgress, 60 ); + + if( pMap ) + { + rPolyPoly.Clear(); + ImplCalculate( pMap, rPolyPoly, 0, nFlags ); + delete pMap; + ImplLimitPolyPoly( rPolyPoly ); + + if( nFlags & BMP_VECTORIZE_REDUCE_EDGES ) + rPolyPoly.Optimize( POLY_OPTIMIZE_EDGES ); + + bRet = TRUE; + } + + VECT_PROGRESS( pProgress, 100 ); + + return bRet; +} + +// ----------------------------------------------------------------------------- + +void ImplVectorizer::ImplLimitPolyPoly( PolyPolygon& rPolyPoly ) +{ + if( rPolyPoly.Count() > VECT_POLY_MAX ) + { + PolyPolygon aNewPolyPoly; + long nReduce = 0; + USHORT nNewCount; + + do + { + aNewPolyPoly.Clear(); + nReduce++; + + for( USHORT i = 0, nCount = rPolyPoly.Count(); i < nCount; i++ ) + { + const Rectangle aBound( rPolyPoly[ i ].GetBoundRect() ); + + if( aBound.GetWidth() > nReduce && aBound.GetHeight() > nReduce ) + { + if( rPolyPoly[ i ].GetSize() ) + aNewPolyPoly.Insert( rPolyPoly[ i ] ); + } + } + + nNewCount = aNewPolyPoly.Count(); + } + while( nNewCount > VECT_POLY_MAX ); + + rPolyPoly = aNewPolyPoly; + } +} + +// ----------------------------------------------------------------------------- + +ImplVectMap* ImplVectorizer::ImplExpand( BitmapReadAccess* pRAcc, const Color& rColor ) +{ + ImplVectMap* pMap = NULL; + + if( pRAcc && pRAcc->Width() && pRAcc->Height() ) + { + const long nOldWidth = pRAcc->Width(); + const long nOldHeight = pRAcc->Height(); + const long nNewWidth = ( nOldWidth << 2L ) + 4L; + const long nNewHeight = ( nOldHeight << 2L ) + 4L; + const BitmapColor aTest( pRAcc->GetBestMatchingColor( rColor ) ); + long* pMapIn = new long[ Max( nOldWidth, nOldHeight ) ]; + long* pMapOut = new long[ Max( nOldWidth, nOldHeight ) ]; + long nX, nY, nTmpX, nTmpY; + + pMap = new ImplVectMap( nNewWidth, nNewHeight ); + + for( nX = 0L; nX < nOldWidth; nX++ ) + VECT_MAP( pMapIn, pMapOut, nX ); + + for( nY = 0L, nTmpY = 5L; nY < nOldHeight; nY++, nTmpY += 4L ) + { + for( nX = 0L; nX < nOldWidth; ) + { + if( pRAcc->GetPixel( nY, nX ) == aTest ) + { + nTmpX = pMapIn[ nX++ ]; + nTmpY -= 3L; + + pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); + pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); + pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); + pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX ); + + while( nX < nOldWidth && pRAcc->GetPixel( nY, nX ) == aTest ) + nX++; + + nTmpX = pMapOut[ nX - 1L ]; + nTmpY -= 3L; + + pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); + pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); + pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX ); + pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX ); + } + else + nX++; + } + } + + for( nY = 0L; nY < nOldHeight; nY++ ) + VECT_MAP( pMapIn, pMapOut, nY ); + + for( nX = 0L, nTmpX = 5L; nX < nOldWidth; nX++, nTmpX += 4L ) + { + for( nY = 0L; nY < nOldHeight; ) + { + if( pRAcc->GetPixel( nY, nX ) == aTest ) + { + nTmpX -= 3L; + nTmpY = pMapIn[ nY++ ]; + + pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); + pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); + pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); + pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX ); + + while( nY < nOldHeight && pRAcc->GetPixel( nY, nX ) == aTest ) + nY++; + + nTmpX -= 3L; + nTmpY = pMapOut[ nY - 1L ]; + + pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); + pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); + pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX ); + pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX ); + } + else + nY++; + } + } + + // cleanup + delete[] pMapIn; + delete[] pMapOut; + } + + return pMap; +} + +// ----------------------------------------------------------------------------- + +void ImplVectorizer::ImplCalculate( ImplVectMap* pMap, PolyPolygon& rPolyPoly, BYTE cReduce, ULONG nFlags ) +{ + const long nWidth = pMap->Width(), nHeight= pMap->Height(); + +#ifdef DBG_BMP + if( pMap ) + { + SvFileStream aOStm( "d:\\cont.bmp", STREAM_WRITE | STREAM_TRUNC ); + aOStm << pMap->GetBitmap(); + } +#endif // DBG_BMP + + for( long nY = 0L; nY < nHeight; nY++ ) + { + long nX = 0L; + BOOL bInner = TRUE; + + while( nX < nWidth ) + { + // skip free + while( ( nX < nWidth ) && pMap->IsFree( nY, nX ) ) + nX++; + + if( nX == nWidth ) + break; + + if( pMap->IsCont( nY, nX ) ) + { + // new contour + ImplChain aChain; + const Point aStartPt( nX++, nY ); + + // get chain code + aChain.ImplBeginAdd( aStartPt ); + ImplGetChain( pMap, aStartPt, aChain ); + + if( nFlags & BMP_VECTORIZE_INNER ) + aChain.ImplEndAdd( bInner ? VECT_POLY_INLINE_INNER : VECT_POLY_INLINE_OUTER ); + else + aChain.ImplEndAdd( bInner ? VECT_POLY_OUTLINE_INNER : VECT_POLY_OUTLINE_OUTER ); + + const Polygon& rPoly = aChain.ImplGetPoly(); + + if( rPoly.GetSize() > 2 ) + { + if( cReduce ) + { + const Rectangle aBound( rPoly.GetBoundRect() ); + + if( aBound.GetWidth() > cReduce && aBound.GetHeight() > cReduce ) + rPolyPoly.Insert( rPoly ); + } + else + rPolyPoly.Insert( rPoly ); + } + + // skip rest of detected contour + while( pMap->IsCont( nY, nX ) ) + nX++; + } + else + { + // process done segment + const long nStartSegX = nX++; + + while( pMap->IsDone( nY, nX ) ) + nX++; + + if( ( ( nX - nStartSegX ) == 1L ) || ( ImplIsUp( pMap, nY, nStartSegX ) != ImplIsUp( pMap, nY, nX - 1L ) ) ) + bInner = !bInner; + } + } + } + +#ifdef DBG_BMP + if( pMap ) + { + SvFileStream aOStm( "d:\\vect.bmp", STREAM_WRITE | STREAM_TRUNC ); + aOStm << pMap->GetBitmap(); + } +#endif // DBG_BMP +} + +// ----------------------------------------------------------------------------- + +BOOL ImplVectorizer::ImplGetChain( ImplVectMap* pMap, const Point& rStartPt, ImplChain& rChain ) +{ + long nActX = rStartPt.X(); + long nActY = rStartPt.Y(); + long nTryX; + long nTryY; + ULONG nFound; + ULONG nLastDir = 0UL; + ULONG nDir; + + do + { + nFound = 0UL; + + // first try last direction + nTryX = nActX + aImplMove[ nLastDir ].nDX; + nTryY = nActY + aImplMove[ nLastDir ].nDY; + + if( pMap->IsCont( nTryY, nTryX ) ) + { + rChain.ImplAdd( (BYTE) nLastDir ); + pMap->Set( nActY = nTryY, nActX = nTryX, VECT_DONE_INDEX ); + nFound = 1UL; + } + else + { + // try other directions + for( nDir = 0UL; nDir < 8UL; nDir++ ) + { + // we already tried nLastDir + if( nDir != nLastDir ) + { + nTryX = nActX + aImplMove[ nDir ].nDX; + nTryY = nActY + aImplMove[ nDir ].nDY; + + if( pMap->IsCont( nTryY, nTryX ) ) + { + rChain.ImplAdd( (BYTE) nDir ); + pMap->Set( nActY = nTryY, nActX = nTryX, VECT_DONE_INDEX ); + nFound = 1UL; + nLastDir = nDir; + break; + } + } + } + } + } + while( nFound ); + + return TRUE; +} + +// ----------------------------------------------------------------------------- + +BOOL ImplVectorizer::ImplIsUp( ImplVectMap* pMap, long nY, long nX ) const +{ + if( pMap->IsDone( nY - 1L, nX ) ) + return TRUE; + else if( pMap->IsDone( nY + 1L, nX ) ) + return FALSE; + else if( pMap->IsDone( nY - 1L, nX - 1L ) || pMap->IsDone( nY - 1L, nX + 1L ) ) + return TRUE; + else + return FALSE; +} diff --git a/vcl/source/gdi/impvect.hxx b/vcl/source/gdi/impvect.hxx new file mode 100644 index 000000000000..34750c220109 --- /dev/null +++ b/vcl/source/gdi/impvect.hxx @@ -0,0 +1,101 @@ +/************************************************************************* + * + * $RCSfile: impvect.hxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _SV_IMPVECT_HXX +#define _SV_IMPVECT_HXX + +#ifndef _SV_POLY_HXX +#include <poly.hxx> +#endif +#ifndef _SV_GDIMTF_HXX +#include <gdimtf.hxx> +#endif + +// -------------- +// - Vectorizer - +// -------------- + +class BitmapReadAccess; +class ImplChain; +class ImplVectMap; + +class ImplVectorizer +{ +private: + + ImplVectMap* ImplExpand( BitmapReadAccess* pRAcc, const Color& rColor ); + void ImplCalculate( ImplVectMap* pMap, PolyPolygon& rPolyPoly, BYTE cReduce, ULONG nFlags ); + BOOL ImplGetChain( ImplVectMap* pMap, const Point& rStartPt, ImplChain& rChain ); + BOOL ImplIsUp( ImplVectMap* pMap, long nY, long nX ) const; + void ImplLimitPolyPoly( PolyPolygon& rPolyPoly ); + +public: + + ImplVectorizer(); + ~ImplVectorizer(); + + BOOL ImplVectorize( const Bitmap& rColorBmp, GDIMetaFile& rMtf, + BYTE cReduce, ULONG nFlags, const Link* pProgress ); + BOOL ImplVectorize( const Bitmap& rMonoBmp, PolyPolygon& rPolyPoly, + ULONG nFlags, const Link* pProgress ); +}; + +#endif diff --git a/vcl/source/gdi/jobset.cxx b/vcl/source/gdi/jobset.cxx new file mode 100644 index 000000000000..7edcf104d113 --- /dev/null +++ b/vcl/source/gdi/jobset.cxx @@ -0,0 +1,415 @@ +/************************************************************************* + * + * $RCSfile: jobset.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_JOBSET_CXX + +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif + +#ifndef _SV_JOBSET_HXX +#include <jobset.hxx> +#endif +#ifndef _SV_JOBSET_H +#include <jobset.h> +#endif + +// ======================================================================= + +DBG_NAME( JobSetup ); + +#define JOBSET_FILEFORMAT2 3780 +#define JOBSET_FILE364_SYSTEM ((USHORT)0xFFFF) + +struct ImplOldJobSetupData +{ + char cPrinterName[64]; + char cDeviceName[32]; + char cPortName[32]; + char cDriverName[32]; +}; + +struct Impl364JobSetupData +{ + SVBT16 nSize; + SVBT16 nSystem; + SVBT32 nDriverDataLen; + SVBT16 nOrientation; + SVBT16 nPaperBin; + SVBT16 nPaperFormat; + SVBT32 nPaperWidth; + SVBT32 nPaperHeight; +}; + +// ======================================================================= + +ImplJobSetup::ImplJobSetup() +{ + mnRefCount = 1; + mnSystem = 0; + meOrientation = ORIENTATION_PORTRAIT; + mnPaperBin = 0; + mePaperFormat = PAPER_USER; + mnPaperWidth = 0; + mnPaperHeight = 0; + mnDriverDataLen = 0; + mpDriverData = NULL; +} + +// ----------------------------------------------------------------------- + +ImplJobSetup::ImplJobSetup( const ImplJobSetup& rJobSetup ) : + maPrinterName( rJobSetup.maPrinterName ), + maDriver( rJobSetup.maDriver ) +{ + mnRefCount = 1; + mnSystem = rJobSetup.mnSystem; + meOrientation = rJobSetup.meOrientation; + mnPaperBin = rJobSetup.mnPaperBin; + mePaperFormat = rJobSetup.mePaperFormat; + mnPaperWidth = rJobSetup.mnPaperWidth; + mnPaperHeight = rJobSetup.mnPaperHeight; + mnDriverDataLen = rJobSetup.mnDriverDataLen; + if ( rJobSetup.mpDriverData ) + { + mpDriverData = new BYTE[mnDriverDataLen]; + memcpy( mpDriverData, rJobSetup.mpDriverData, mnDriverDataLen ); + } + else + mpDriverData = NULL; +} + +// ----------------------------------------------------------------------- + +ImplJobSetup::~ImplJobSetup() +{ + delete mpDriverData; +} + +// ======================================================================= + +ImplJobSetup* JobSetup::ImplGetData() +{ + if ( !mpData ) + mpData = new ImplJobSetup; + else if ( mpData->mnRefCount != 1 ) + { + mpData->mnRefCount--; + mpData = new ImplJobSetup( *mpData ); + } + + return mpData; +} + +// ----------------------------------------------------------------------- + +ImplJobSetup* JobSetup::ImplGetConstData() +{ + if ( !mpData ) + mpData = new ImplJobSetup; + return mpData; +} + +// ----------------------------------------------------------------------- + +const ImplJobSetup* JobSetup::ImplGetConstData() const +{ + if ( !mpData ) + ((JobSetup*)this)->mpData = new ImplJobSetup; + return mpData; +} + +// ======================================================================= + +JobSetup::JobSetup() +{ + DBG_CTOR( JobSetup, NULL ); + + mpData = NULL; +} + +// ----------------------------------------------------------------------- + +JobSetup::JobSetup( const JobSetup& rJobSetup ) +{ + DBG_CTOR( JobSetup, NULL ); + DBG_CHKOBJ( &rJobSetup, JobSetup, NULL ); + DBG_ASSERT( !rJobSetup.mpData || (rJobSetup.mpData->mnRefCount < 0xFFFE), "JobSetup: RefCount overflow" ); + + mpData = rJobSetup.mpData; + if ( mpData ) + mpData->mnRefCount++; +} + +// ----------------------------------------------------------------------- + +JobSetup::~JobSetup() +{ + DBG_DTOR( JobSetup, NULL ); + + if ( mpData ) + { + if ( mpData->mnRefCount == 1 ) + delete mpData; + else + mpData->mnRefCount--; + } +} + +// ----------------------------------------------------------------------- + +XubString JobSetup::GetPrinterName() const +{ + if ( mpData ) + return mpData->maPrinterName; + else + { + XubString aName; + return aName; + } +} + +// ----------------------------------------------------------------------- + +XubString JobSetup::GetDriverName() const +{ + if ( mpData ) + return mpData->maDriver; + else + { + XubString aDriver; + return aDriver; + } +} + +// ----------------------------------------------------------------------- + +JobSetup& JobSetup::operator=( const JobSetup& rJobSetup ) +{ + DBG_CHKTHIS( JobSetup, NULL ); + DBG_CHKOBJ( &rJobSetup, JobSetup, NULL ); + DBG_ASSERT( !rJobSetup.mpData || (rJobSetup.mpData->mnRefCount) < 0xFFFE, "JobSetup: RefCount overflow" ); + + // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann + if ( rJobSetup.mpData ) + rJobSetup.mpData->mnRefCount++; + + // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es + // die letzte Referenz ist, sonst Referenzcounter decrementieren + if ( mpData ) + { + if ( mpData->mnRefCount == 1 ) + delete mpData; + else + mpData->mnRefCount--; + } + + mpData = rJobSetup.mpData; + + return *this; +} + +// ----------------------------------------------------------------------- + +BOOL JobSetup::operator==( const JobSetup& rJobSetup ) const +{ + DBG_CHKTHIS( JobSetup, NULL ); + DBG_CHKOBJ( &rJobSetup, JobSetup, NULL ); + + if ( mpData == rJobSetup.mpData ) + return TRUE; + + if ( !mpData || !rJobSetup.mpData ) + return FALSE; + + ImplJobSetup* pData1 = mpData; + ImplJobSetup* pData2 = rJobSetup.mpData; + if ( (pData1->mnSystem == pData2->mnSystem) && + (pData1->maPrinterName == pData2->maPrinterName) && + (pData1->maDriver == pData2->maDriver) && + (pData1->meOrientation == pData2->meOrientation) && + (pData1->mnPaperBin == pData2->mnPaperBin) && + (pData1->mePaperFormat == pData2->mePaperFormat) && + (pData1->mnPaperWidth == pData2->mnPaperWidth) && + (pData1->mnPaperHeight == pData2->mnPaperHeight) && + (pData1->mnDriverDataLen == pData2->mnDriverDataLen) && + (memcmp( pData1->mpDriverData, pData2->mpDriverData, pData1->mnDriverDataLen ) == 0) ) + return TRUE; + + return FALSE; +} + +// ----------------------------------------------------------------------- + +SvStream& operator>>( SvStream& rIStream, JobSetup& rJobSetup ) +{ + DBG_ASSERTWARNING( rIStream.GetVersion(), "JobSetup::>> - Solar-Version not set on rOStream" ); + + // Zur Zeit haben wir noch kein neues FileFormat +// if ( rIStream.GetVersion() < JOBSET_FILEFORMAT2 ) + { + USHORT nLen; + USHORT nSystem; + rIStream >> nLen; + if ( !nLen ) + return rIStream; + rIStream >> nSystem; + char* pTempBuf = new char[nLen]; + rIStream.Read( pTempBuf, nLen - sizeof( nLen ) - sizeof( nSystem ) ); + if ( nLen >= sizeof(ImplOldJobSetupData)+4 ) + { + ImplOldJobSetupData* pData = (ImplOldJobSetupData*)pTempBuf; + if ( rJobSetup.mpData ) + { + if ( rJobSetup.mpData->mnRefCount == 1 ) + delete rJobSetup.mpData; + else + rJobSetup.mpData->mnRefCount--; + } + rJobSetup.mpData = new ImplJobSetup; + ImplJobSetup* pJobData = rJobSetup.mpData; + pJobData->maPrinterName = UniString( pData->cPrinterName, RTL_TEXTENCODING_UTF8 ); + pJobData->maDriver = UniString( pData->cDriverName, RTL_TEXTENCODING_UTF8 ); + + // Sind es unsere neuen JobSetup-Daten? + if ( nSystem == JOBSET_FILE364_SYSTEM ) + { + Impl364JobSetupData* pOldJobData = (Impl364JobSetupData*)(pTempBuf + sizeof( ImplOldJobSetupData )); + USHORT nOldJobDataSize = SVBT16ToShort( pOldJobData->nSize ); + pJobData->mnSystem = SVBT16ToShort( pOldJobData->nSystem ); + pJobData->mnDriverDataLen = SVBT32ToLong( pOldJobData->nDriverDataLen ); + pJobData->meOrientation = (Orientation)SVBT16ToShort( pOldJobData->nOrientation ); + pJobData->mnPaperBin = SVBT16ToShort( pOldJobData->nPaperBin ); + pJobData->mePaperFormat = (Paper)SVBT16ToShort( pOldJobData->nPaperFormat ); + pJobData->mnPaperWidth = (long)SVBT32ToLong( pOldJobData->nPaperWidth ); + pJobData->mnPaperHeight = (long)SVBT32ToLong( pOldJobData->nPaperHeight ); + if ( pJobData->mnDriverDataLen ) + { + BYTE* pDriverData = ((BYTE*)pOldJobData) + nOldJobDataSize; + pJobData->mpDriverData = new BYTE[pJobData->mnDriverDataLen]; + memcpy( pJobData->mpDriverData, pDriverData, pJobData->mnDriverDataLen ); + } + } + } + delete pTempBuf; + } +/* + else + { + } +*/ + + return rIStream; +} + +// ----------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rOStream, const JobSetup& rJobSetup ) +{ + DBG_ASSERTWARNING( rOStream.GetVersion(), "JobSetup::<< - Solar-Version not set on rOStream" ); + + // Zur Zeit haben wir noch kein neues FileFormat +// if ( rOStream.GetVersion() < JOBSET_FILEFORMAT2 ) + { + USHORT nLen = 0; + if ( !rJobSetup.mpData ) + rOStream << nLen; + else + { + USHORT nSystem = JOBSET_FILE364_SYSTEM; + + const ImplJobSetup* pJobData = rJobSetup.ImplGetConstData(); + Impl364JobSetupData aOldJobData; + USHORT nOldJobDataSize = sizeof( aOldJobData ); + ShortToSVBT16( nOldJobDataSize, aOldJobData.nSize ); + ShortToSVBT16( pJobData->mnSystem, aOldJobData.nSystem ); + LongToSVBT32( pJobData->mnDriverDataLen, aOldJobData.nDriverDataLen ); + ShortToSVBT16( (USHORT)(pJobData->meOrientation), aOldJobData.nOrientation ); + ShortToSVBT16( pJobData->mnPaperBin, aOldJobData.nPaperBin ); + ShortToSVBT16( (USHORT)(pJobData->mePaperFormat), aOldJobData.nPaperFormat ); + LongToSVBT32( (ULONG)(pJobData->mnPaperWidth), aOldJobData.nPaperWidth ); + LongToSVBT32( (ULONG)(pJobData->mnPaperHeight), aOldJobData.nPaperHeight ); + + ImplOldJobSetupData aOldData; + memset( &aOldData, 0, sizeof( aOldData ) ); + ByteString aPrnByteName( rJobSetup.GetPrinterName(), RTL_TEXTENCODING_UTF8 ); + strncpy( aOldData.cPrinterName, aPrnByteName.GetBuffer(), 63 ); + ByteString aDriverByteName( rJobSetup.GetDriverName(), RTL_TEXTENCODING_UTF8 ); + strncpy( aOldData.cDriverName, aDriverByteName.GetBuffer(), 31 ); + nLen = sizeof( aOldData ) + 4 + nOldJobDataSize + pJobData->mnDriverDataLen; + rOStream << nLen; + rOStream << nSystem; + rOStream.Write( (char*)&aOldData, sizeof( aOldData ) ); + rOStream.Write( (char*)&aOldJobData, nOldJobDataSize ); + rOStream.Write( (char*)pJobData->mpDriverData, pJobData->mnDriverDataLen ); + } + } +/* + else + { + } +*/ + + return rOStream; +} diff --git a/vcl/source/gdi/lineinfo.cxx b/vcl/source/gdi/lineinfo.cxx new file mode 100644 index 000000000000..fde91e8ee702 --- /dev/null +++ b/vcl/source/gdi/lineinfo.cxx @@ -0,0 +1,300 @@ +/************************************************************************* + * + * $RCSfile: lineinfo.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_LINEINFO_CXX + +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif +#ifndef _VCOMPAT_HXX +#include <tools/vcompat.hxx> +#endif +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _SV_LINEINFO_HXX +#include <lineinfo.hxx> +#endif + +DBG_NAME( LineInfo ); + +// ---------------- +// - ImplLineInfo - +// ---------------- + +ImplLineInfo::ImplLineInfo() : + mnRefCount ( 1 ), + meStyle ( LINE_SOLID ), + mnWidth ( 0 ), + mnDashCount ( 0 ), + mnDashLen ( 0 ), + mnDotCount ( 0 ), + mnDotLen ( 0 ), + mnDistance ( 0 ) +{ +} + +// ----------------------------------------------------------------------- + +ImplLineInfo::ImplLineInfo( const ImplLineInfo& rImplLineInfo ) : + mnRefCount ( 1 ), + meStyle ( rImplLineInfo.meStyle ), + mnWidth ( rImplLineInfo.mnWidth ), + mnDashCount ( rImplLineInfo.mnDashCount ), + mnDashLen ( rImplLineInfo.mnDashLen ), + mnDotCount ( rImplLineInfo.mnDotCount ), + mnDotLen ( rImplLineInfo.mnDotLen ), + mnDistance ( rImplLineInfo.mnDistance ) +{ +} + +// ------------ +// - LineInfo - +// ------------ + +LineInfo::LineInfo( LineStyle eStyle, long nWidth ) +{ + DBG_CTOR( LineInfo, NULL ); + mpImplLineInfo = new ImplLineInfo; + mpImplLineInfo->meStyle = eStyle; + mpImplLineInfo->mnWidth = nWidth; +} + +// ----------------------------------------------------------------------- + +LineInfo::LineInfo( const LineInfo& rLineInfo ) +{ + DBG_CTOR( LineInfo, NULL ); + DBG_CHKOBJ( &rLineInfo, LineInfo, NULL ); + mpImplLineInfo = rLineInfo.mpImplLineInfo; + mpImplLineInfo->mnRefCount++; +} + +// ----------------------------------------------------------------------- + +LineInfo::~LineInfo() +{ + DBG_DTOR( LineInfo, NULL ); + if( !( --mpImplLineInfo->mnRefCount ) ) + delete mpImplLineInfo; +} + +// ----------------------------------------------------------------------- + +LineInfo& LineInfo::operator=( const LineInfo& rLineInfo ) +{ + DBG_CHKTHIS( LineInfo, NULL ); + DBG_CHKOBJ( &rLineInfo, LineInfo, NULL ); + + rLineInfo.mpImplLineInfo->mnRefCount++; + + if( !( --mpImplLineInfo->mnRefCount ) ) + delete mpImplLineInfo; + + mpImplLineInfo = rLineInfo.mpImplLineInfo; + return *this; +} + +// ----------------------------------------------------------------------- + +BOOL LineInfo::operator==( const LineInfo& rLineInfo ) const +{ + DBG_CHKTHIS( LineInfo, NULL ); + DBG_CHKOBJ( &rLineInfo, LineInfo, NULL ); + + return( mpImplLineInfo == rLineInfo.mpImplLineInfo || + ( mpImplLineInfo->meStyle == rLineInfo.mpImplLineInfo->meStyle && + mpImplLineInfo->mnWidth == rLineInfo.mpImplLineInfo->mnWidth && + mpImplLineInfo->mnDashCount == rLineInfo.mpImplLineInfo->mnDashCount && + mpImplLineInfo->mnDashLen == rLineInfo.mpImplLineInfo->mnDashLen && + mpImplLineInfo->mnDotCount == rLineInfo.mpImplLineInfo->mnDotCount && + mpImplLineInfo->mnDotLen == rLineInfo.mpImplLineInfo->mnDotLen && + mpImplLineInfo->mnDistance == rLineInfo.mpImplLineInfo->mnDistance ) ); +} + +// ----------------------------------------------------------------------- + +void LineInfo::ImplMakeUnique() +{ + if( mpImplLineInfo->mnRefCount != 1 ) + { + if( mpImplLineInfo->mnRefCount ) + mpImplLineInfo->mnRefCount--; + + mpImplLineInfo = new ImplLineInfo( *mpImplLineInfo ); + } +} + +// ----------------------------------------------------------------------- + +void LineInfo::SetStyle( LineStyle eStyle ) +{ + DBG_CHKTHIS( LineInfo, NULL ); + ImplMakeUnique(); + mpImplLineInfo->meStyle = eStyle; +} + +// ----------------------------------------------------------------------- + +void LineInfo::SetWidth( long nWidth ) +{ + DBG_CHKTHIS( LineInfo, NULL ); + ImplMakeUnique(); + mpImplLineInfo->mnWidth = nWidth; +} + +// ----------------------------------------------------------------------- + +void LineInfo::SetDashCount( USHORT nDashCount ) +{ + DBG_CHKTHIS( LineInfo, NULL ); + ImplMakeUnique(); + mpImplLineInfo->mnDashCount = nDashCount; +} + +// ----------------------------------------------------------------------- + +void LineInfo::SetDashLen( long nDashLen ) +{ + DBG_CHKTHIS( LineInfo, NULL ); + ImplMakeUnique(); + mpImplLineInfo->mnDashLen = nDashLen; +} + +// ----------------------------------------------------------------------- + +void LineInfo::SetDotCount( USHORT nDotCount ) +{ + DBG_CHKTHIS( LineInfo, NULL ); + ImplMakeUnique(); + mpImplLineInfo->mnDotCount = nDotCount; +} + +// ----------------------------------------------------------------------- + +void LineInfo::SetDotLen( long nDotLen ) +{ + DBG_CHKTHIS( LineInfo, NULL ); + ImplMakeUnique(); + mpImplLineInfo->mnDotLen = nDotLen; +} + +// ----------------------------------------------------------------------- + +void LineInfo::SetDistance( long nDistance ) +{ + DBG_CHKTHIS( LineInfo, NULL ); + ImplMakeUnique(); + mpImplLineInfo->mnDistance = nDistance; +} + +// ----------------------------------------------------------------------- + +SvStream& operator>>( SvStream& rIStm, ImplLineInfo& rImplLineInfo ) +{ + VersionCompat aCompat( rIStm, STREAM_READ ); + UINT16 nTmp16; + + rIStm >> nTmp16; rImplLineInfo.meStyle = (LineStyle) nTmp16; + rIStm >> rImplLineInfo.mnWidth; + + if( aCompat.GetVersion() >= 2 ) + { + // version 2 + rIStm >> rImplLineInfo.mnDashCount >> rImplLineInfo.mnDashLen; + rIStm >> rImplLineInfo.mnDotCount >> rImplLineInfo.mnDotLen; + rIStm >> rImplLineInfo.mnDistance; + } + + return rIStm; +} + +// ----------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rOStm, const ImplLineInfo& rImplLineInfo ) +{ + VersionCompat aCompat( rOStm, STREAM_WRITE, 2 ); + + // version 1 + rOStm << (UINT16) rImplLineInfo.meStyle << rImplLineInfo.mnWidth; + + // since version2 + rOStm << rImplLineInfo.mnDashCount << rImplLineInfo.mnDashLen; + rOStm << rImplLineInfo.mnDotCount << rImplLineInfo.mnDotLen; + rOStm << rImplLineInfo.mnDistance; + + return rOStm; +} + +// ----------------------------------------------------------------------- + +SvStream& operator>>( SvStream& rIStm, LineInfo& rLineInfo ) +{ + rLineInfo.ImplMakeUnique(); + return( rIStm >> *rLineInfo.mpImplLineInfo ); +} + +// ----------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rOStm, const LineInfo& rLineInfo ) +{ + return( rOStm << *rLineInfo.mpImplLineInfo ); +} diff --git a/vcl/source/gdi/makefile.mk b/vcl/source/gdi/makefile.mk new file mode 100644 index 000000000000..cecf617abb1c --- /dev/null +++ b/vcl/source/gdi/makefile.mk @@ -0,0 +1,156 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (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.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=vcl +TARGET=gdi + +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Settings ----------------------------------------------------- + +.INCLUDE : svpre.mk +.INCLUDE : settings.mk +.INCLUDE : sv.mk + +.IF "$(COM)"=="ICC" +CDEFS+=-D_STD_NO_NAMESPACE -D_VOS_NO_NAMESPACE -D_UNO_NO_NAMESPACE +.ENDIF + +# --- Files -------------------------------------------------------- + +SLOFILES= $(SLO)$/salmisc.obj \ + $(SLO)$/animate.obj \ + $(SLO)$/impanmvw.obj \ + $(SLO)$/bitmap.obj \ + $(SLO)$/bitmap2.obj \ + $(SLO)$/bitmap3.obj \ + $(SLO)$/bitmap4.obj \ + $(SLO)$/alpha.obj \ + $(SLO)$/bitmapex.obj \ + $(SLO)$/imgcons.obj \ + $(SLO)$/bmpacc.obj \ + $(SLO)$/bmpacc2.obj \ + $(SLO)$/bmpacc3.obj \ + $(SLO)$/color.obj \ + $(SLO)$/cvtsvm.obj \ + $(SLO)$/cvtgrf.obj \ + $(SLO)$/font.obj \ + $(SLO)$/gdimtf.obj \ + $(SLO)$/gfxlink.obj \ + $(SLO)$/gradient.obj \ + $(SLO)$/hatch.obj \ + $(SLO)$/graph.obj \ + $(SLO)$/image.obj \ + $(SLO)$/impbmp.obj \ + $(SLO)$/impgraph.obj \ + $(SLO)$/impimage.obj \ + $(SLO)$/impprn.obj \ + $(SLO)$/impvect.obj \ + $(SLO)$/implncvt.obj \ + $(SLO)$/jobset.obj \ + $(SLO)$/line.obj \ + $(SLO)$/lineinfo.obj \ + $(SLO)$/mapmod.obj \ + $(SLO)$/metaact.obj \ + $(SLO)$/metric.obj \ + $(SLO)$/octree.obj \ + $(SLO)$/outmap.obj \ + $(SLO)$/outdev.obj \ + $(SLO)$/outdev2.obj \ + $(SLO)$/outdev3.obj \ + $(SLO)$/outdev4.obj \ + $(SLO)$/outdev5.obj \ + $(SLO)$/outdev6.obj \ + $(SLO)$/poly.obj \ + $(SLO)$/poly2.obj \ + $(SLO)$/print.obj \ + $(SLO)$/print2.obj \ + $(SLO)$/regband.obj \ + $(SLO)$/region.obj \ + $(SLO)$/virdev.obj \ + $(SLO)$/wall.obj \ + $(SLO)$/opengl.obj + +.IF "$(remote)"!="" +EXCEPTIONSFILES= $(SLO)$/bitmap.obj \ + $(SLO)$/color.obj \ + $(SLO)$/gfxlink.obj \ + $(SLO)$/impgraph.obj \ + $(SLO)$/impvect.obj \ + $(SLO)$/outdev.obj \ + $(SLO)$/outdev3.obj \ + $(SLO)$/outdev6.obj \ + $(SLO)$/print.obj \ + $(SLO)$/print2.obj \ + $(SLO)$/virdev.obj + +.ELSE +EXCEPTIONSFILES= $(SLO)$/outdev.obj \ + $(SLO)$/gfxlink.obj \ + $(SLO)$/impgraph.obj +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/vcl/source/gdi/mapmod.cxx b/vcl/source/gdi/mapmod.cxx new file mode 100644 index 000000000000..5690e1c7cf0f --- /dev/null +++ b/vcl/source/gdi/mapmod.cxx @@ -0,0 +1,356 @@ +/************************************************************************* + * + * $RCSfile: mapmod.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_MAPMOD_CXX + +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif +#ifndef _VCOMPAT_HXX +#include <tools/vcompat.hxx> +#endif +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#define private public +#ifndef _SV_MAPMOD_HXX +#include <mapmod.hxx> +#endif +#undef private + +// ======================================================================= + +DBG_NAME( MapMode ); + +// ----------------------------------------------------------------------- + +ImplMapMode::ImplMapMode() : + maOrigin( 0, 0 ), + maScaleX( 1, 1 ), + maScaleY( 1, 1 ) +{ + mnRefCount = 1; + meUnit = MAP_PIXEL; + mbSimple = FALSE; +} + +// ----------------------------------------------------------------------- + +ImplMapMode::ImplMapMode( const ImplMapMode& rImplMapMode ) : + maOrigin( rImplMapMode.maOrigin ), + maScaleX( rImplMapMode.maScaleX ), + maScaleY( rImplMapMode.maScaleY ) +{ + mnRefCount = 1; + meUnit = rImplMapMode.meUnit; + mbSimple = FALSE; +} + +// ----------------------------------------------------------------------- + +SvStream& operator>>( SvStream& rIStm, ImplMapMode& rImplMapMode ) +{ + VersionCompat aCompat( rIStm, STREAM_READ ); + UINT16 nTmp16; + + rIStm >> nTmp16; rImplMapMode.meUnit = (MapUnit) nTmp16; + rIStm >> rImplMapMode.maOrigin >> rImplMapMode.maScaleX >> + rImplMapMode.maScaleY >> rImplMapMode.mbSimple; + + return rIStm; +} + +// ----------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rOStm, const ImplMapMode& rImplMapMode ) +{ + VersionCompat aCompat( rOStm, STREAM_WRITE, 1 ); + + rOStm << (UINT16) rImplMapMode.meUnit << + rImplMapMode.maOrigin << + rImplMapMode.maScaleX << + rImplMapMode.maScaleY << + rImplMapMode.mbSimple; + + return rOStm; +} + +// ----------------------------------------------------------------------- + +static ImplMapMode* ImplGetStaticMapMode( MapUnit eUnit ) +{ + // Achtung: Ganz fies und dreckig !!! +#ifdef WIN + static long _near aStaticImplMapModeAry[(MAP_LASTENUMDUMMY)*sizeof(ImplMapMode)/sizeof(long)]; +#else + static long aStaticImplMapModeAry[(MAP_LASTENUMDUMMY)*sizeof(ImplMapMode)/sizeof(long)]; +#endif + + ImplMapMode* pImplMapMode = ((ImplMapMode*)aStaticImplMapModeAry)+eUnit; + if ( !pImplMapMode->mbSimple ) + { + Fraction aDefFraction( 1, 1 ); + pImplMapMode->maScaleX = aDefFraction; + pImplMapMode->maScaleY = aDefFraction; + pImplMapMode->meUnit = eUnit; + pImplMapMode->mbSimple = TRUE; + } + + return pImplMapMode; +} + +// ----------------------------------------------------------------------- + +inline void MapMode::ImplMakeUnique() +{ + // Falls noch andere Referenzen bestehen, dann kopieren + if ( mpImplMapMode->mnRefCount != 1 ) + { + if ( mpImplMapMode->mnRefCount ) + mpImplMapMode->mnRefCount--; + mpImplMapMode = new ImplMapMode( *mpImplMapMode ); + } +} + +// ----------------------------------------------------------------------- + +MapMode::MapMode() +{ + DBG_CTOR( MapMode, NULL ); + + mpImplMapMode = ImplGetStaticMapMode( MAP_PIXEL ); +} + +// ----------------------------------------------------------------------- + +MapMode::MapMode( const MapMode& rMapMode ) +{ + DBG_CTOR( MapMode, NULL ); + DBG_CHKOBJ( &rMapMode, MapMode, NULL ); + DBG_ASSERT( rMapMode.mpImplMapMode->mnRefCount < 0xFFFE, "MapMode: RefCount overflow" ); + + // shared Instance Daten uebernehmen und Referenzcounter erhoehen + mpImplMapMode = rMapMode.mpImplMapMode; + // RefCount == 0 fuer statische Objekte + if ( mpImplMapMode->mnRefCount ) + mpImplMapMode->mnRefCount++; +} + +// ----------------------------------------------------------------------- + +MapMode::MapMode( MapUnit eUnit ) +{ + DBG_CTOR( MapMode, NULL ); + + mpImplMapMode = ImplGetStaticMapMode( eUnit ); +} + +// ----------------------------------------------------------------------- + +MapMode::MapMode( MapUnit eUnit, const Point& rLogicOrg, + const Fraction& rScaleX, const Fraction& rScaleY ) +{ + DBG_CTOR( MapMode, NULL ); + + mpImplMapMode = new ImplMapMode; + mpImplMapMode->meUnit = eUnit; + mpImplMapMode->maOrigin = rLogicOrg; + mpImplMapMode->maScaleX = rScaleX; + mpImplMapMode->maScaleY = rScaleY; +} + +// ----------------------------------------------------------------------- + +MapMode::~MapMode() +{ + DBG_DTOR( MapMode, NULL ); + + // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es + // die letzte Referenz ist, sonst Referenzcounter decrementieren + if ( mpImplMapMode->mnRefCount ) + { + if ( mpImplMapMode->mnRefCount == 1 ) + delete mpImplMapMode; + else + mpImplMapMode->mnRefCount--; + } +} + +// ----------------------------------------------------------------------- + +void MapMode::SetMapUnit( MapUnit eUnit ) +{ + DBG_CHKTHIS( MapMode, NULL ); + + ImplMakeUnique(); + mpImplMapMode->meUnit = eUnit; +} + +// ----------------------------------------------------------------------- + +void MapMode::SetOrigin( const Point& rLogicOrg ) +{ + DBG_CHKTHIS( MapMode, NULL ); + + ImplMakeUnique(); + mpImplMapMode->maOrigin = rLogicOrg; +} + +// ----------------------------------------------------------------------- + +void MapMode::SetScaleX( const Fraction& rScaleX ) +{ + DBG_CHKTHIS( MapMode, NULL ); + + ImplMakeUnique(); + mpImplMapMode->maScaleX = rScaleX; +} + +// ----------------------------------------------------------------------- + +void MapMode::SetScaleY( const Fraction& rScaleY ) +{ + DBG_CHKTHIS( MapMode, NULL ); + + ImplMakeUnique(); + mpImplMapMode->maScaleY = rScaleY; +} + +// ----------------------------------------------------------------------- + +MapMode& MapMode::operator=( const MapMode& rMapMode ) +{ + DBG_CHKTHIS( MapMode, NULL ); + DBG_CHKOBJ( &rMapMode, MapMode, NULL ); + DBG_ASSERT( rMapMode.mpImplMapMode->mnRefCount < 0xFFFE, "MapMode: RefCount overflow" ); + + // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann + // RefCount == 0 fuer statische Objekte + if ( rMapMode.mpImplMapMode->mnRefCount ) + rMapMode.mpImplMapMode->mnRefCount++; + + // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es + // die letzte Referenz ist, sonst Referenzcounter decrementieren + if ( mpImplMapMode->mnRefCount ) + { + if ( mpImplMapMode->mnRefCount == 1 ) + delete mpImplMapMode; + else + mpImplMapMode->mnRefCount--; + } + + mpImplMapMode = rMapMode.mpImplMapMode; + + return *this; +} + +// ----------------------------------------------------------------------- + +BOOL MapMode::operator==( const MapMode& rMapMode ) const +{ + DBG_CHKTHIS( MapMode, NULL ); + DBG_CHKOBJ( &rMapMode, MapMode, NULL ); + + if ( mpImplMapMode == rMapMode.mpImplMapMode ) + return TRUE; + + if ( (mpImplMapMode->meUnit == rMapMode.mpImplMapMode->meUnit) && + (mpImplMapMode->maOrigin == rMapMode.mpImplMapMode->maOrigin) && + (mpImplMapMode->maScaleX == rMapMode.mpImplMapMode->maScaleX) && + (mpImplMapMode->maScaleY == rMapMode.mpImplMapMode->maScaleY) ) + return TRUE; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL MapMode::IsDefault() const +{ + DBG_CHKTHIS( MapMode, NULL ); + + ImplMapMode* pDefMapMode = ImplGetStaticMapMode( MAP_PIXEL ); + if ( mpImplMapMode == pDefMapMode ) + return TRUE; + + if ( (mpImplMapMode->meUnit == pDefMapMode->meUnit) && + (mpImplMapMode->maOrigin == pDefMapMode->maOrigin) && + (mpImplMapMode->maScaleX == pDefMapMode->maScaleX) && + (mpImplMapMode->maScaleY == pDefMapMode->maScaleY) ) + return TRUE; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +SvStream& operator>>( SvStream& rIStm, MapMode& rMapMode ) +{ + rMapMode.ImplMakeUnique(); + return (rIStm >> *rMapMode.mpImplMapMode); +} + +// ----------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rOStm, const MapMode& rMapMode ) +{ + return (rOStm << *rMapMode.mpImplMapMode); +} diff --git a/vcl/source/gdi/metaact.cxx b/vcl/source/gdi/metaact.cxx new file mode 100644 index 000000000000..caa28f1ee856 --- /dev/null +++ b/vcl/source/gdi/metaact.cxx @@ -0,0 +1,3434 @@ +/************************************************************************* + * + * $RCSfile: metaact.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_METAACT_CXX +#define ENABLE_BYTESTRING_STREAM_OPERATORS + +#include <string.h> + +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif +#ifndef _VCOMPAT_HXX +#include <tools/vcompat.hxx> +#endif +#ifndef _SV_OUTDEV_HXX +#include <outdev.hxx> +#endif +#ifndef _SV_SALBTYPE_HXX +#include <salbtype.hxx> +#endif +#ifndef _SV_METAACT_HXX +#include <metaact.hxx> +#endif + +// ======================================================================== + +inline void ImplScalePoint( Point& rPt, double fScaleX, double fScaleY ) +{ + rPt.X() = FRound( fScaleX * rPt.X() ); + rPt.Y() = FRound( fScaleY * rPt.Y() ); +} + +// ------------------------------------------------------------------------ + +inline void ImplScaleSize( Size& rSz, double fScaleX, double fScaleY ) +{ + rSz.Width() = FRound( fScaleX * rSz.Width() ); + rSz.Height() = FRound( fScaleY * rSz.Height() ); +} + +// ------------------------------------------------------------------------ + +inline void ImplScaleRect( Rectangle& rRect, double fScaleX, double fScaleY ) +{ + Point aTL( rRect.TopLeft() ); + Point aBR( rRect.BottomRight() ); + + ImplScalePoint( aTL, fScaleX, fScaleY ); + ImplScalePoint( aBR, fScaleX, fScaleY ); + + rRect = Rectangle( aTL, aBR ); +} + +// ------------------------------------------------------------------------ + +inline void ImplScalePoly( Polygon& rPoly, double fScaleX, double fScaleY ) +{ + for( USHORT i = 0, nCount = rPoly.GetSize(); i < nCount; i++ ) + ImplScalePoint( rPoly[ i ], fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +inline void ImplScaleLineInfo( LineInfo& rLineInfo, double fScaleX, double fScaleY ) +{ + if( !rLineInfo.IsDefault() ) + { + const double fScale = ( fScaleX + fScaleY ) * 0.5; + + rLineInfo.SetWidth( FRound( fScale * rLineInfo.GetWidth() ) ); + rLineInfo.SetDashLen( FRound( fScale * rLineInfo.GetDashLen() ) ); + rLineInfo.SetDotLen( FRound( fScale * rLineInfo.GetDotLen() ) ); + rLineInfo.SetDistance( FRound( fScale * rLineInfo.GetDistance() ) ); + } +} + +// ======================================================================== + +#define COMPAT( _def_rIStm ) VersionCompat aCompat( ( _def_rIStm ), STREAM_READ ); +#define COMPAT_VERSION() aCompat.GetVersion() +#define WRITE_BASE_COMPAT( _def_rOStm, _def_nVer, _pWriteData ) \ + MetaAction::Write( ( _def_rOStm ), _pWriteData ); \ + VersionCompat aCompat( ( _def_rOStm ), STREAM_WRITE, ( _def_nVer ) ); + +// ======================================================================== + +MetaAction::MetaAction() : + mnRefCount( 1 ), + mnType( META_NULL_ACTION ) +{ +} + +// ------------------------------------------------------------------------ + +MetaAction::MetaAction( USHORT nType ) : + mnRefCount( 1 ), + mnType( nType ) +{ +} + +// ------------------------------------------------------------------------ + +MetaAction::~MetaAction() +{ +} + +// ------------------------------------------------------------------------ + +void MetaAction::Execute( OutputDevice* pOut ) +{ +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaAction::Clone() +{ + return new MetaAction; +} + +// ------------------------------------------------------------------------ + +void MetaAction::Move( long nHorzMove, long nVertMove ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaAction::Scale( double fScaleX, double fScaleY ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaAction::Write( SvStream& rOStm, ImplMetaWriteData* ) +{ + rOStm << mnType; +} + +// ------------------------------------------------------------------------ + +void MetaAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + rIStm >> mnType; +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaAction::ReadMetaAction( SvStream& rIStm, ImplMetaReadData* pData ) +{ + MetaAction* pAction = NULL; + UINT16 nType; + + rIStm >> nType; + + switch( nType ) + { + case( META_NULL_ACTION ): pAction = new MetaAction; break; + case( META_PIXEL_ACTION ): pAction = new MetaPixelAction; break; + case( META_POINT_ACTION ): pAction = new MetaPointAction; break; + case( META_LINE_ACTION ): pAction = new MetaLineAction; break; + case( META_RECT_ACTION ): pAction = new MetaRectAction; break; + case( META_ROUNDRECT_ACTION ): pAction = new MetaRoundRectAction; break; + case( META_ELLIPSE_ACTION ): pAction = new MetaEllipseAction; break; + case( META_ARC_ACTION ): pAction = new MetaArcAction; break; + case( META_PIE_ACTION ): pAction = new MetaPieAction; break; + case( META_CHORD_ACTION ): pAction = new MetaChordAction; break; + case( META_POLYLINE_ACTION ): pAction = new MetaPolyLineAction; break; + case( META_POLYGON_ACTION ): pAction = new MetaPolygonAction; break; + case( META_POLYPOLYGON_ACTION ): pAction = new MetaPolyPolygonAction; break; + case( META_TEXT_ACTION ): pAction = new MetaTextAction; break; + case( META_TEXTARRAY_ACTION ): pAction = new MetaTextArrayAction; break; + case( META_STRETCHTEXT_ACTION ): pAction = new MetaStretchTextAction; break; + case( META_TEXTRECT_ACTION ): pAction = new MetaTextRectAction; break; + case( META_TEXTLINE_ACTION ): pAction = new MetaTextLineAction; break; + case( META_BMP_ACTION ): pAction = new MetaBmpAction; break; + case( META_BMPSCALE_ACTION ): pAction = new MetaBmpScaleAction; break; + case( META_BMPSCALEPART_ACTION ): pAction = new MetaBmpScalePartAction; break; + case( META_BMPEX_ACTION ): pAction = new MetaBmpExAction; break; + case( META_BMPEXSCALE_ACTION ): pAction = new MetaBmpExScaleAction; break; + case( META_BMPEXSCALEPART_ACTION ): pAction = new MetaBmpExScalePartAction; break; + case( META_MASK_ACTION ): pAction = new MetaMaskAction; break; + case( META_MASKSCALE_ACTION ): pAction = new MetaMaskScaleAction; break; + case( META_MASKSCALEPART_ACTION ): pAction = new MetaMaskScalePartAction; break; + case( META_GRADIENT_ACTION ): pAction = new MetaGradientAction; break; + case( META_GRADIENTEX_ACTION ): pAction = new MetaGradientExAction; break; + case( META_HATCH_ACTION ): pAction = new MetaHatchAction; break; + case( META_WALLPAPER_ACTION ): pAction = new MetaWallpaperAction; break; + case( META_CLIPREGION_ACTION ): pAction = new MetaClipRegionAction; break; + case( META_ISECTRECTCLIPREGION_ACTION ): pAction = new MetaISectRectClipRegionAction; break; + case( META_ISECTREGIONCLIPREGION_ACTION ): pAction = new MetaISectRegionClipRegionAction; break; + case( META_MOVECLIPREGION_ACTION ): pAction = new MetaMoveClipRegionAction; break; + case( META_LINECOLOR_ACTION ): pAction = new MetaLineColorAction; break; + case( META_FILLCOLOR_ACTION ): pAction = new MetaFillColorAction; break; + case( META_TEXTCOLOR_ACTION ): pAction = new MetaTextColorAction; break; + case( META_TEXTFILLCOLOR_ACTION ): pAction = new MetaTextFillColorAction; break; + case( META_TEXTLINECOLOR_ACTION ): pAction = new MetaTextLineColorAction; break; + case( META_TEXTALIGN_ACTION ): pAction = new MetaTextAlignAction; break; + case( META_MAPMODE_ACTION ): pAction = new MetaMapModeAction; break; + case( META_FONT_ACTION ): pAction = new MetaFontAction; break; + case( META_PUSH_ACTION ): pAction = new MetaPushAction; break; + case( META_POP_ACTION ): pAction = new MetaPopAction; break; + case( META_RASTEROP_ACTION ): pAction = new MetaRasterOpAction; break; + case( META_TRANSPARENT_ACTION ): pAction = new MetaTransparentAction; break; + case( META_FLOATTRANSPARENT_ACTION ): pAction = new MetaFloatTransparentAction; break; + case( META_EPS_ACTION ): pAction = new MetaEPSAction; break; + case( META_REFPOINT_ACTION ): pAction = new MetaRefPointAction; break; + case( META_COMMENT_ACTION ): pAction = new MetaCommentAction; break; + + default: + { + // Action ueberlesen durch Kombination Ctor/Dtor, + // new/delete, weil Compiler sonst vielleicht wegoptimieren + delete ( new VersionCompat( rIStm, STREAM_READ ) ); + } + break; + } + + if( pAction ) + pAction->Read( rIStm, pData ); + + return pAction; +} + +// ======================================================================== + +IMPL_META_ACTION( Pixel, META_PIXEL_ACTION ) + +// ------------------------------------------------------------------------ + +MetaPixelAction::MetaPixelAction( const Point& rPt, const Color& rColor ) : + MetaAction ( META_PIXEL_ACTION ), + maPt ( rPt ), + maColor ( rColor ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaPixelAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawPixel( maPt, maColor ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaPixelAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaPixelAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaPixelAction::Move( long nHorzMove, long nVertMove ) +{ + maPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaPixelAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maPt, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaPixelAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maPt; + maColor.Write( rOStm, TRUE ); +} + +// ------------------------------------------------------------------------ + +void MetaPixelAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maPt; + maColor.Read( rIStm, TRUE ); +} + +// ======================================================================== + +IMPL_META_ACTION( Point, META_POINT_ACTION ) + +// ------------------------------------------------------------------------ + +MetaPointAction::MetaPointAction( const Point& rPt ) : + MetaAction ( META_POINT_ACTION ), + maPt ( rPt ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaPointAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawPixel( maPt ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaPointAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaPointAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaPointAction::Move( long nHorzMove, long nVertMove ) +{ + maPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaPointAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maPt, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaPointAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maPt; +} + +// ------------------------------------------------------------------------ + +void MetaPointAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maPt; +} + +// ======================================================================== + +IMPL_META_ACTION( Line, META_LINE_ACTION ) + +// ------------------------------------------------------------------------ + +MetaLineAction::MetaLineAction( const Point& rStart, const Point& rEnd ) : + MetaAction ( META_LINE_ACTION ), + maStartPt ( rStart ), + maEndPt ( rEnd ) +{ +} + +// ------------------------------------------------------------------------ + +MetaLineAction::MetaLineAction( const Point& rStart, const Point& rEnd, + const LineInfo& rLineInfo ) : + MetaAction ( META_LINE_ACTION ), + maLineInfo ( rLineInfo ), + maStartPt ( rStart ), + maEndPt ( rEnd ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaLineAction::Execute( OutputDevice* pOut ) +{ + if( maLineInfo.IsDefault() ) + pOut->DrawLine( maStartPt, maEndPt ); + else + pOut->DrawLine( maStartPt, maEndPt, maLineInfo ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaLineAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaLineAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaLineAction::Move( long nHorzMove, long nVertMove ) +{ + maStartPt.Move( nHorzMove, nVertMove ); + maEndPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaLineAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maStartPt, fScaleX, fScaleY ); + ImplScalePoint( maEndPt, fScaleX, fScaleY ); + ImplScaleLineInfo( maLineInfo, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaLineAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 2, pData ); + + rOStm << maStartPt << maEndPt; // Version 1 + rOStm << maLineInfo; // Version 2 +} + +// ------------------------------------------------------------------------ + +void MetaLineAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + + // Version 1 + rIStm >> maStartPt >> maEndPt; + + // Version 2 + if( aCompat.GetVersion() >= 2 ) + { + rIStm >> maLineInfo; + } +} + +// ======================================================================== + +IMPL_META_ACTION( Rect, META_RECT_ACTION ) + +// ------------------------------------------------------------------------ + +MetaRectAction::MetaRectAction( const Rectangle& rRect ) : + MetaAction ( META_RECT_ACTION ), + maRect ( rRect ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaRectAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawRect( maRect ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaRectAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaRectAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaRectAction::Move( long nHorzMove, long nVertMove ) +{ + maRect.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaRectAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScaleRect( maRect, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaRectAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maRect; +} + +// ------------------------------------------------------------------------ + +void MetaRectAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maRect; +} + +// ======================================================================== + +IMPL_META_ACTION( RoundRect, META_ROUNDRECT_ACTION ) + +// ------------------------------------------------------------------------ + +MetaRoundRectAction::MetaRoundRectAction( const Rectangle& rRect, + long nHorzRound, long nVertRound ) : + MetaAction ( META_ROUNDRECT_ACTION ), + maRect ( rRect ), + mnHorzRound ( nHorzRound ), + mnVertRound ( nVertRound ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaRoundRectAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawRect( maRect, mnHorzRound, mnVertRound ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaRoundRectAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaRoundRectAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaRoundRectAction::Move( long nHorzMove, long nVertMove ) +{ + maRect.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaRoundRectAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScaleRect( maRect, fScaleX, fScaleY ); + mnHorzRound = FRound( mnHorzRound * fScaleX ); + mnVertRound = FRound( mnVertRound * fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaRoundRectAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maRect << mnHorzRound << mnVertRound; +} + +// ------------------------------------------------------------------------ + +void MetaRoundRectAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maRect >> mnHorzRound >> mnVertRound; +} + +// ======================================================================== + +IMPL_META_ACTION( Ellipse, META_ELLIPSE_ACTION ) + +// ------------------------------------------------------------------------ + +MetaEllipseAction::MetaEllipseAction( const Rectangle& rRect ) : + MetaAction ( META_ELLIPSE_ACTION ), + maRect ( rRect ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaEllipseAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawEllipse( maRect ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaEllipseAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaEllipseAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaEllipseAction::Move( long nHorzMove, long nVertMove ) +{ + maRect.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaEllipseAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScaleRect( maRect, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaEllipseAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maRect; +} + +// ------------------------------------------------------------------------ + +void MetaEllipseAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maRect; +} + +// ======================================================================== + +IMPL_META_ACTION( Arc, META_ARC_ACTION ) + +// ------------------------------------------------------------------------ + +MetaArcAction::MetaArcAction( const Rectangle& rRect, + const Point& rStart, const Point& rEnd ) : + MetaAction ( META_ARC_ACTION ), + maRect ( rRect ), + maStartPt ( rStart ), + maEndPt ( rEnd ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaArcAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawArc( maRect, maStartPt, maEndPt ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaArcAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaArcAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaArcAction::Move( long nHorzMove, long nVertMove ) +{ + maRect.Move( nHorzMove, nVertMove ); + maStartPt.Move( nHorzMove, nVertMove ); + maEndPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaArcAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScaleRect( maRect, fScaleX, fScaleY ); + ImplScalePoint( maStartPt, fScaleX, fScaleY ); + ImplScalePoint( maEndPt, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaArcAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maRect << maStartPt << maEndPt; +} + +// ------------------------------------------------------------------------ + +void MetaArcAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maRect >> maStartPt >> maEndPt; +} + +// ======================================================================== + +IMPL_META_ACTION( Pie, META_PIE_ACTION ) + +// ------------------------------------------------------------------------ + +MetaPieAction::MetaPieAction( const Rectangle& rRect, + const Point& rStart, const Point& rEnd ) : + MetaAction ( META_PIE_ACTION ), + maRect ( rRect ), + maStartPt ( rStart ), + maEndPt ( rEnd ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaPieAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawPie( maRect, maStartPt, maEndPt ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaPieAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaPieAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaPieAction::Move( long nHorzMove, long nVertMove ) +{ + maRect.Move( nHorzMove, nVertMove ); + maStartPt.Move( nHorzMove, nVertMove ); + maEndPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaPieAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScaleRect( maRect, fScaleX, fScaleY ); + ImplScalePoint( maStartPt, fScaleX, fScaleY ); + ImplScalePoint( maEndPt, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaPieAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maRect << maStartPt << maEndPt; +} + +// ------------------------------------------------------------------------ + +void MetaPieAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maRect >> maStartPt >> maEndPt; +} + +// ======================================================================== + +IMPL_META_ACTION( Chord, META_CHORD_ACTION ) + +// ------------------------------------------------------------------------ + +MetaChordAction::MetaChordAction( const Rectangle& rRect, + const Point& rStart, const Point& rEnd ) : + MetaAction ( META_CHORD_ACTION ), + maRect ( rRect ), + maStartPt ( rStart ), + maEndPt ( rEnd ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaChordAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawChord( maRect, maStartPt, maEndPt ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaChordAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaChordAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaChordAction::Move( long nHorzMove, long nVertMove ) +{ + maRect.Move( nHorzMove, nVertMove ); + maStartPt.Move( nHorzMove, nVertMove ); + maEndPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaChordAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScaleRect( maRect, fScaleX, fScaleY ); + ImplScalePoint( maStartPt, fScaleX, fScaleY ); + ImplScalePoint( maEndPt, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaChordAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maRect << maStartPt << maEndPt; +} + +// ------------------------------------------------------------------------ + +void MetaChordAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maRect >> maStartPt >> maEndPt; +} + +// ======================================================================== + +IMPL_META_ACTION( PolyLine, META_POLYLINE_ACTION ) + +// ------------------------------------------------------------------------ + +MetaPolyLineAction::MetaPolyLineAction( const Polygon& rPoly ) : + MetaAction ( META_POLYLINE_ACTION ), + maPoly ( rPoly ) +{ +} + +// ------------------------------------------------------------------------ + +MetaPolyLineAction::MetaPolyLineAction( const Polygon& rPoly, const LineInfo& rLineInfo ) : + MetaAction ( META_POLYLINE_ACTION ), + maLineInfo ( rLineInfo ), + maPoly ( rPoly ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaPolyLineAction::Execute( OutputDevice* pOut ) +{ + if( maLineInfo.IsDefault() ) + pOut->DrawPolyLine( maPoly ); + else + pOut->DrawPolyLine( maPoly, maLineInfo ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaPolyLineAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaPolyLineAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaPolyLineAction::Move( long nHorzMove, long nVertMove ) +{ + maPoly.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaPolyLineAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoly( maPoly, fScaleX, fScaleY ); + ImplScaleLineInfo( maLineInfo, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaPolyLineAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 2, pData ); + + rOStm << maPoly; // Version 1 + rOStm << maLineInfo; // Version 2 +} + +// ------------------------------------------------------------------------ + +void MetaPolyLineAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + + // Version 1 + rIStm >> maPoly; + + // Version 2 + if( aCompat.GetVersion() >= 2 ) + { + rIStm >> maLineInfo; + } +} + +// ======================================================================== + +IMPL_META_ACTION( Polygon, META_POLYGON_ACTION ) + +// ------------------------------------------------------------------------ + +MetaPolygonAction::MetaPolygonAction( const Polygon& rPoly ) : + MetaAction ( META_POLYGON_ACTION ), + maPoly ( rPoly ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaPolygonAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawPolygon( maPoly ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaPolygonAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaPolygonAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaPolygonAction::Move( long nHorzMove, long nVertMove ) +{ + maPoly.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaPolygonAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoly( maPoly, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaPolygonAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maPoly; +} + +// ------------------------------------------------------------------------ + +void MetaPolygonAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maPoly; +} + +// ======================================================================== + +IMPL_META_ACTION( PolyPolygon, META_POLYPOLYGON_ACTION ) + +// ------------------------------------------------------------------------ + +MetaPolyPolygonAction::MetaPolyPolygonAction( const PolyPolygon& rPolyPoly ) : + MetaAction ( META_POLYPOLYGON_ACTION ), + maPolyPoly ( rPolyPoly ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaPolyPolygonAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawPolyPolygon( maPolyPoly ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaPolyPolygonAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaPolyPolygonAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaPolyPolygonAction::Move( long nHorzMove, long nVertMove ) +{ + maPolyPoly.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaPolyPolygonAction::Scale( double fScaleX, double fScaleY ) +{ + for( USHORT i = 0, nCount = maPolyPoly.Count(); i < nCount; i++ ) + ImplScalePoly( maPolyPoly[ i ], fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaPolyPolygonAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maPolyPoly; +} + +// ------------------------------------------------------------------------ + +void MetaPolyPolygonAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maPolyPoly; +} + +// ======================================================================== + +IMPL_META_ACTION( Text, META_TEXT_ACTION ) + +// ------------------------------------------------------------------------ + +MetaTextAction::MetaTextAction( const Point& rPt, const XubString& rStr, + USHORT nIndex, USHORT nLen ) : + MetaAction ( META_TEXT_ACTION ), + maPt ( rPt ), + maStr ( rStr ), + mnIndex ( nIndex ), + mnLen ( nLen ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaTextAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawText( maPt, maStr, mnIndex, mnLen ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaTextAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaTextAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaTextAction::Move( long nHorzMove, long nVertMove ) +{ + maPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaTextAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maPt, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaTextAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maPt; + rOStm.WriteByteString( maStr, pData->meActualCharSet ); + rOStm << mnIndex; + rOStm << mnLen; +} + +// ------------------------------------------------------------------------ + +void MetaTextAction::Read( SvStream& rIStm, ImplMetaReadData* pData ) +{ + COMPAT( rIStm ); + rIStm >> maPt; + rIStm.ReadByteString( maStr, pData->meActualCharSet ); + rIStm >> mnIndex; + rIStm >> mnLen; +} + +// ======================================================================== + +MetaTextArrayAction::MetaTextArrayAction() : + MetaAction ( META_TEXTARRAY_ACTION ), + mpDXAry ( NULL ), + mnIndex ( 0 ), + mnLen ( 0 ) +{ +} + +// ------------------------------------------------------------------------ + +MetaTextArrayAction::MetaTextArrayAction( const MetaTextArrayAction& rAction ) : + MetaAction ( META_TEXTARRAY_ACTION ), + maStartPt ( rAction.maStartPt ), + maStr ( rAction.maStr ), + mnIndex ( rAction.mnIndex ), + mnLen ( rAction.mnLen ) +{ + if( rAction.mpDXAry ) + { + const ULONG nAryLen = mnLen - 1; + + mpDXAry = new long[ nAryLen ]; + memcpy( mpDXAry, rAction.mpDXAry, nAryLen * sizeof( long ) ); + } + else + mpDXAry = NULL; +} + +// ------------------------------------------------------------------------ + +MetaTextArrayAction::MetaTextArrayAction( const Point& rStartPt, + const XubString& rStr, + const long* pDXAry, + USHORT nIndex, + USHORT nLen ) : + MetaAction ( META_TEXTARRAY_ACTION ), + maStartPt ( rStartPt ), + maStr ( rStr ), + mnIndex ( nIndex ), + mnLen ( ( nLen == STRING_LEN ) ? rStr.Len() : nLen ) +{ + const ULONG nAryLen = ( ( mnLen > 1 ) && pDXAry ) ? ( mnLen - 1 ) : 0UL; + + if( nAryLen ) + { + mpDXAry = new long[ nAryLen ]; + memcpy( mpDXAry, pDXAry, nAryLen * sizeof( long ) ); + } + else + mpDXAry = NULL; +} + +// ------------------------------------------------------------------------ + +MetaTextArrayAction::~MetaTextArrayAction() +{ + delete[] mpDXAry; +} + +// ------------------------------------------------------------------------ + +void MetaTextArrayAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawTextArray( maStartPt, maStr, mpDXAry, mnIndex, mnLen ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaTextArrayAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaTextArrayAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaTextArrayAction::Move( long nHorzMove, long nVertMove ) +{ + maStartPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaTextArrayAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maStartPt, fScaleX, fScaleY ); + + if ( mpDXAry && mnLen ) + { + for ( USHORT i = 0, nCount = mnLen - 1; i < nCount; i++ ) + mpDXAry[ i ] = FRound( mpDXAry[ i ] * fScaleX ); + } +} + +// ------------------------------------------------------------------------ + +void MetaTextArrayAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + const ULONG nAryLen = ( ( mnLen > 1 ) && mpDXAry ) ? ( mnLen - 1 ) : 0UL; + + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maStartPt; + rOStm.WriteByteString( maStr, pData->meActualCharSet ); + rOStm << mnIndex; + rOStm << mnLen; + rOStm << nAryLen; + + for( ULONG i = 0UL; i < nAryLen; i++ ) + rOStm << mpDXAry[ i ]; +} + +// ------------------------------------------------------------------------ + +void MetaTextArrayAction::Read( SvStream& rIStm, ImplMetaReadData* pData ) +{ + ULONG nAryLen; + + delete[] mpDXAry; + + COMPAT( rIStm ); + rIStm >> maStartPt; + rIStm.ReadByteString( maStr, pData->meActualCharSet ); + rIStm >> mnIndex; + rIStm >> mnLen; + rIStm >> nAryLen; + + if( nAryLen ) + { + mpDXAry = new long[ nAryLen ]; + + for( ULONG i = 0UL; i < nAryLen; i++ ) + rIStm >> mpDXAry[ i ]; + } + else + mpDXAry = NULL; +} + +// ======================================================================== + +IMPL_META_ACTION( StretchText, META_STRETCHTEXT_ACTION ) + +// ------------------------------------------------------------------------ + +MetaStretchTextAction::MetaStretchTextAction( const Point& rPt, ULONG nWidth, + const XubString& rStr, + USHORT nIndex, USHORT nLen ) : + MetaAction ( META_STRETCHTEXT_ACTION ), + maPt ( rPt ), + maStr ( rStr ), + mnWidth ( nWidth ), + mnIndex ( nIndex ), + mnLen ( nLen ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaStretchTextAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawStretchText( maPt, mnWidth, maStr, mnIndex, mnLen ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaStretchTextAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaStretchTextAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaStretchTextAction::Move( long nHorzMove, long nVertMove ) +{ + maPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaStretchTextAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maPt, fScaleX, fScaleY ); + mnWidth = (ULONG)FRound( mnWidth * fScaleX ); +} + +// ------------------------------------------------------------------------ + +void MetaStretchTextAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maPt; + rOStm.WriteByteString( maStr, pData->meActualCharSet ); + rOStm << mnWidth; + rOStm << mnIndex; + rOStm << mnLen; +} + +// ------------------------------------------------------------------------ + +void MetaStretchTextAction::Read( SvStream& rIStm, ImplMetaReadData* pData ) +{ + COMPAT( rIStm ); + rIStm >> maPt; + rIStm.ReadByteString( maStr, pData->meActualCharSet ); + rIStm >> mnWidth; + rIStm >> mnIndex; + rIStm >> mnLen; +} + +// ======================================================================== + +IMPL_META_ACTION( TextRect, META_TEXTRECT_ACTION ) + +// ------------------------------------------------------------------------ + +MetaTextRectAction::MetaTextRectAction( const Rectangle& rRect, + const XubString& rStr, USHORT nStyle ) : + MetaAction ( META_TEXTRECT_ACTION ), + maRect ( rRect ), + maStr ( rStr ), + mnStyle ( nStyle ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaTextRectAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawText( maRect, maStr, mnStyle ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaTextRectAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaTextRectAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaTextRectAction::Move( long nHorzMove, long nVertMove ) +{ + maRect.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaTextRectAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScaleRect( maRect, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaTextRectAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maRect; + rOStm.WriteByteString( maStr, pData->meActualCharSet ); + rOStm << mnStyle; +} + +// ------------------------------------------------------------------------ + +void MetaTextRectAction::Read( SvStream& rIStm, ImplMetaReadData* pData ) +{ + COMPAT( rIStm ); + rIStm >> maRect; + rIStm.ReadByteString( maStr, pData->meActualCharSet ); + rIStm >> mnStyle; +} + +// ======================================================================== + +IMPL_META_ACTION( TextLine, META_TEXTLINE_ACTION ) + +// ------------------------------------------------------------------------ + +MetaTextLineAction::MetaTextLineAction( const Point& rPos, long nWidth, + FontStrikeout eStrikeout, + FontUnderline eUnderline ) : + MetaAction ( META_TEXTLINE_ACTION ), + maPos ( rPos ), + mnWidth ( nWidth ), + meStrikeout ( eStrikeout ), + meUnderline ( eUnderline ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaTextLineAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawTextLine( maPos, mnWidth, meStrikeout, meUnderline ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaTextLineAction::Clone() +{ + MetaAction* pClone = (MetaAction*)new MetaTextLineAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaTextLineAction::Move( long nHorzMove, long nVertMove ) +{ + maPos.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaTextLineAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maPos, fScaleX, fScaleY ); + mnWidth = FRound( mnWidth * fScaleX ); +} + +// ------------------------------------------------------------------------ + +void MetaTextLineAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 2, pData ); + + rOStm << maPos; + rOStm << mnWidth; + rOStm << (ULONG)meStrikeout; + rOStm << (ULONG)meUnderline; +} + +// ------------------------------------------------------------------------ + +void MetaTextLineAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + + ULONG nTemp; + rIStm >> maPos; + rIStm >> mnWidth; + rIStm >> nTemp; + meStrikeout = (FontStrikeout)nTemp; + rIStm >> nTemp; + meUnderline = (FontUnderline)nTemp; +} + +// ======================================================================== + +IMPL_META_ACTION( Bmp, META_BMP_ACTION ) + +// ------------------------------------------------------------------------ + +MetaBmpAction::MetaBmpAction( const Point& rPt, const Bitmap& rBmp ) : + MetaAction ( META_BMP_ACTION ), + maBmp ( rBmp ), + maPt ( rPt ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaBmpAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawBitmap( maPt, maBmp ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaBmpAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaBmpAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaBmpAction::Move( long nHorzMove, long nVertMove ) +{ + maPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaBmpAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maPt, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaBmpAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + if( !!maBmp ) + { + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maBmp << maPt; + } +} + +// ------------------------------------------------------------------------ + +void MetaBmpAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maBmp >> maPt; +} + +// ======================================================================== + +IMPL_META_ACTION( BmpScale, META_BMPSCALE_ACTION ) + +// ------------------------------------------------------------------------ + +MetaBmpScaleAction::MetaBmpScaleAction( const Point& rPt, const Size& rSz, + const Bitmap& rBmp ) : + MetaAction ( META_BMPSCALE_ACTION ), + maBmp ( rBmp ), + maPt ( rPt ), + maSz ( rSz ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaBmpScaleAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawBitmap( maPt, maSz, maBmp ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaBmpScaleAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaBmpScaleAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaBmpScaleAction::Move( long nHorzMove, long nVertMove ) +{ + maPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaBmpScaleAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maPt, fScaleX, fScaleY ); + ImplScaleSize( maSz, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaBmpScaleAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + if( !!maBmp ) + { + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maBmp << maPt << maSz; + } +} + +// ------------------------------------------------------------------------ + +void MetaBmpScaleAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maBmp >> maPt >> maSz; +} + +// ======================================================================== + +IMPL_META_ACTION( BmpScalePart, META_BMPSCALEPART_ACTION ) + +// ------------------------------------------------------------------------ + +MetaBmpScalePartAction::MetaBmpScalePartAction( const Point& rDstPt, const Size& rDstSz, + const Point& rSrcPt, const Size& rSrcSz, + const Bitmap& rBmp ) : + MetaAction ( META_BMPSCALEPART_ACTION ), + maBmp ( rBmp ), + maDstPt ( rDstPt ), + maDstSz ( rDstSz ), + maSrcPt ( rSrcPt ), + maSrcSz ( rSrcSz ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaBmpScalePartAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawBitmap( maDstPt, maDstSz, maSrcPt, maSrcSz, maBmp ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaBmpScalePartAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaBmpScalePartAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaBmpScalePartAction::Move( long nHorzMove, long nVertMove ) +{ + maDstPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaBmpScalePartAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maDstPt, fScaleX, fScaleY ); + ImplScaleSize( maDstSz, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaBmpScalePartAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + if( !!maBmp ) + { + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maBmp << maDstPt << maDstSz << maSrcPt << maSrcSz; + } +} + +// ------------------------------------------------------------------------ + +void MetaBmpScalePartAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maBmp >> maDstPt >> maDstSz >> maSrcPt >> maSrcSz; +} + +// ======================================================================== + +IMPL_META_ACTION( BmpEx, META_BMPEX_ACTION ) + +// ------------------------------------------------------------------------ + +MetaBmpExAction::MetaBmpExAction( const Point& rPt, const BitmapEx& rBmpEx ) : + MetaAction ( META_BMPEX_ACTION ), + maBmpEx ( rBmpEx ), + maPt ( rPt ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaBmpExAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawBitmapEx( maPt, maBmpEx ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaBmpExAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaBmpExAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaBmpExAction::Move( long nHorzMove, long nVertMove ) +{ + maPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaBmpExAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maPt, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaBmpExAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + if( !!maBmpEx.GetBitmap() ) + { + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maBmpEx << maPt; + } +} + +// ------------------------------------------------------------------------ + +void MetaBmpExAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maBmpEx >> maPt; +} + +// ======================================================================== + +IMPL_META_ACTION( BmpExScale, META_BMPEXSCALE_ACTION ) + +// ------------------------------------------------------------------------ + +MetaBmpExScaleAction::MetaBmpExScaleAction( const Point& rPt, const Size& rSz, + const BitmapEx& rBmpEx ) : + MetaAction ( META_BMPEXSCALE_ACTION ), + maBmpEx ( rBmpEx ), + maPt ( rPt ), + maSz ( rSz ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaBmpExScaleAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawBitmapEx( maPt, maSz, maBmpEx ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaBmpExScaleAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaBmpExScaleAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaBmpExScaleAction::Move( long nHorzMove, long nVertMove ) +{ + maPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaBmpExScaleAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maPt, fScaleX, fScaleY ); + ImplScaleSize( maSz, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaBmpExScaleAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + if( !!maBmpEx.GetBitmap() ) + { + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maBmpEx << maPt << maSz; + } +} + +// ------------------------------------------------------------------------ + +void MetaBmpExScaleAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maBmpEx >> maPt >> maSz; +} + +// ======================================================================== + +IMPL_META_ACTION( BmpExScalePart, META_BMPEXSCALEPART_ACTION ) + +// ------------------------------------------------------------------------ + +MetaBmpExScalePartAction::MetaBmpExScalePartAction( const Point& rDstPt, const Size& rDstSz, + const Point& rSrcPt, const Size& rSrcSz, + const BitmapEx& rBmpEx ) : + MetaAction ( META_BMPEXSCALEPART_ACTION ), + maBmpEx ( rBmpEx ), + maDstPt ( rDstPt ), + maDstSz ( rDstSz ), + maSrcPt ( rSrcPt ), + maSrcSz ( rSrcSz ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaBmpExScalePartAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawBitmapEx( maDstPt, maDstSz, maSrcPt, maSrcSz, maBmpEx ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaBmpExScalePartAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaBmpExScalePartAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaBmpExScalePartAction::Move( long nHorzMove, long nVertMove ) +{ + maDstPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaBmpExScalePartAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maDstPt, fScaleX, fScaleY ); + ImplScaleSize( maDstSz, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaBmpExScalePartAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + if( !!maBmpEx.GetBitmap() ) + { + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maBmpEx << maDstPt << maDstSz << maSrcPt << maSrcSz; + } +} + +// ------------------------------------------------------------------------ + +void MetaBmpExScalePartAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maBmpEx >> maDstPt >> maDstSz >> maSrcPt >> maSrcSz; +} + +// ======================================================================== + +IMPL_META_ACTION( Mask, META_MASK_ACTION ) + +// ------------------------------------------------------------------------ + +MetaMaskAction::MetaMaskAction( const Point& rPt, + const Bitmap& rBmp, + const Color& rColor ) : + MetaAction ( META_MASK_ACTION ), + maBmp ( rBmp ), + maColor ( rColor ), + maPt ( rPt ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaMaskAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawMask( maPt, maBmp, maColor ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaMaskAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaMaskAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaMaskAction::Move( long nHorzMove, long nVertMove ) +{ + maPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaMaskAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maPt, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaMaskAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + if( !!maBmp ) + { + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maBmp << maPt; + } +} + +// ------------------------------------------------------------------------ + +void MetaMaskAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maBmp >> maPt; +} + +// ======================================================================== + +IMPL_META_ACTION( MaskScale, META_MASKSCALE_ACTION ) + +// ------------------------------------------------------------------------ + +MetaMaskScaleAction::MetaMaskScaleAction( const Point& rPt, const Size& rSz, + const Bitmap& rBmp, + const Color& rColor ) : + MetaAction ( META_MASKSCALE_ACTION ), + maBmp ( rBmp ), + maColor ( rColor ), + maPt ( rPt ), + maSz ( rSz ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaMaskScaleAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawMask( maPt, maSz, maBmp, maColor ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaMaskScaleAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaMaskScaleAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaMaskScaleAction::Move( long nHorzMove, long nVertMove ) +{ + maPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaMaskScaleAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maPt, fScaleX, fScaleY ); + ImplScaleSize( maSz, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaMaskScaleAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + if( !!maBmp ) + { + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maBmp << maPt << maSz; + } +} + +// ------------------------------------------------------------------------ + +void MetaMaskScaleAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maBmp >> maPt >> maSz; +} + +// ======================================================================== + +IMPL_META_ACTION( MaskScalePart, META_MASKSCALEPART_ACTION ) + +// ------------------------------------------------------------------------ + +MetaMaskScalePartAction::MetaMaskScalePartAction( const Point& rDstPt, const Size& rDstSz, + const Point& rSrcPt, const Size& rSrcSz, + const Bitmap& rBmp, + const Color& rColor ) : + MetaAction ( META_MASKSCALEPART_ACTION ), + maBmp ( rBmp ), + maColor ( rColor ), + maDstPt ( rDstPt ), + maDstSz ( rDstSz ), + maSrcPt ( rSrcPt ), + maSrcSz ( rSrcSz ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaMaskScalePartAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawMask( maDstPt, maDstSz, maSrcPt, maSrcSz, maBmp, maColor ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaMaskScalePartAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaMaskScalePartAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaMaskScalePartAction::Move( long nHorzMove, long nVertMove ) +{ + maDstPt.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaMaskScalePartAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maDstPt, fScaleX, fScaleY ); + ImplScaleSize( maDstSz, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaMaskScalePartAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + if( !!maBmp ) + { + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maBmp; + maColor.Write( rOStm, TRUE ); + rOStm << maDstPt << maDstSz << maSrcPt << maSrcSz; + } +} + +// ------------------------------------------------------------------------ + +void MetaMaskScalePartAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maBmp; + maColor.Read( rIStm, TRUE ); + rIStm >> maDstPt >> maDstSz >> maSrcPt >> maSrcSz; +} + +// ======================================================================== + +IMPL_META_ACTION( Gradient, META_GRADIENT_ACTION ) + +// ------------------------------------------------------------------------ + +MetaGradientAction::MetaGradientAction( const Rectangle& rRect, const Gradient& rGradient ) : + MetaAction ( META_GRADIENT_ACTION ), + maRect ( rRect ), + maGradient ( rGradient ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaGradientAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawGradient( maRect, maGradient ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaGradientAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaGradientAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaGradientAction::Move( long nHorzMove, long nVertMove ) +{ + maRect.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaGradientAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScaleRect( maRect, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaGradientAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maRect << maGradient; +} + +// ------------------------------------------------------------------------ + +void MetaGradientAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maRect >> maGradient; +} + +// ======================================================================== + +MetaGradientExAction::MetaGradientExAction() : + MetaAction ( META_GRADIENTEX_ACTION ) +{ +} + +// ------------------------------------------------------------------------ + +MetaGradientExAction::MetaGradientExAction( const PolyPolygon& rPolyPoly, const Gradient& rGradient ) : + MetaAction ( META_GRADIENTEX_ACTION ), + maPolyPoly ( rPolyPoly ), + maGradient ( rGradient ) +{ +} + +// ------------------------------------------------------------------------ + +MetaGradientExAction::~MetaGradientExAction() +{ +} + +// ------------------------------------------------------------------------ + +void MetaGradientExAction::Execute( OutputDevice* pOut ) +{ + if( pOut->GetConnectMetaFile() ) + pOut->GetConnectMetaFile()->AddAction( Clone() ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaGradientExAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaGradientExAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaGradientExAction::Move( long nHorzMove, long nVertMove ) +{ + maPolyPoly.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaGradientExAction::Scale( double fScaleX, double fScaleY ) +{ + for( USHORT i = 0, nCount = maPolyPoly.Count(); i < nCount; i++ ) + ImplScalePoly( maPolyPoly[ i ], fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaGradientExAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maPolyPoly << maGradient; +} + +// ------------------------------------------------------------------------ + +void MetaGradientExAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maPolyPoly >> maGradient; +} + +// ======================================================================== + +IMPL_META_ACTION( Hatch, META_HATCH_ACTION ) + +// ------------------------------------------------------------------------ + +MetaHatchAction::MetaHatchAction( const PolyPolygon& rPolyPoly, const Hatch& rHatch ) : + MetaAction ( META_HATCH_ACTION ), + maPolyPoly ( rPolyPoly ), + maHatch ( rHatch ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaHatchAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawHatch( maPolyPoly, maHatch ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaHatchAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaHatchAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaHatchAction::Move( long nHorzMove, long nVertMove ) +{ + maPolyPoly.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaHatchAction::Scale( double fScaleX, double fScaleY ) +{ + for( USHORT i = 0, nCount = maPolyPoly.Count(); i < nCount; i++ ) + ImplScalePoly( maPolyPoly[ i ], fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaHatchAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maPolyPoly << maHatch; +} + +// ------------------------------------------------------------------------ + +void MetaHatchAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maPolyPoly >> maHatch; +} + +// ======================================================================== + +IMPL_META_ACTION( Wallpaper, META_WALLPAPER_ACTION ) + +// ------------------------------------------------------------------------ + +MetaWallpaperAction::MetaWallpaperAction( const Rectangle& rRect, + const Wallpaper& rPaper ) : + MetaAction ( META_WALLPAPER_ACTION ), + maRect ( rRect ), + maWallpaper ( rPaper ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaWallpaperAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawWallpaper( maRect, maWallpaper ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaWallpaperAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaWallpaperAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaWallpaperAction::Move( long nHorzMove, long nVertMove ) +{ + maRect.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaWallpaperAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScaleRect( maRect, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaWallpaperAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maWallpaper; +} + +// ------------------------------------------------------------------------ + +void MetaWallpaperAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maWallpaper; +} + +// ======================================================================== + +IMPL_META_ACTION( ClipRegion, META_CLIPREGION_ACTION ) + +// ------------------------------------------------------------------------ + +MetaClipRegionAction::MetaClipRegionAction( const Region& rRegion, BOOL bClip ) : + MetaAction ( META_CLIPREGION_ACTION ), + maRegion ( rRegion ), + mbClip ( bClip ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaClipRegionAction::Execute( OutputDevice* pOut ) +{ + if( mbClip ) + pOut->SetClipRegion( maRegion ); + else + pOut->SetClipRegion(); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaClipRegionAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaClipRegionAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaClipRegionAction::Move( long nHorzMove, long nVertMove ) +{ + maRegion.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaClipRegionAction::Scale( double fScaleX, double fScaleY ) +{ + maRegion.Scale( fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaClipRegionAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maRegion << mbClip; +} + +// ------------------------------------------------------------------------ + +void MetaClipRegionAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maRegion >> mbClip; +} + +// ======================================================================== + +IMPL_META_ACTION( ISectRectClipRegion, META_ISECTRECTCLIPREGION_ACTION ) + +// ------------------------------------------------------------------------ + +MetaISectRectClipRegionAction::MetaISectRectClipRegionAction( const Rectangle& rRect ) : + MetaAction ( META_ISECTRECTCLIPREGION_ACTION ), + maRect ( rRect ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaISectRectClipRegionAction::Execute( OutputDevice* pOut ) +{ + pOut->IntersectClipRegion( maRect ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaISectRectClipRegionAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaISectRectClipRegionAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaISectRectClipRegionAction::Move( long nHorzMove, long nVertMove ) +{ + maRect.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaISectRectClipRegionAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScaleRect( maRect, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaISectRectClipRegionAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maRect; +} + +// ------------------------------------------------------------------------ + +void MetaISectRectClipRegionAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maRect; +} + +// ======================================================================== + +IMPL_META_ACTION( ISectRegionClipRegion, META_ISECTREGIONCLIPREGION_ACTION ) + +// ------------------------------------------------------------------------ + +MetaISectRegionClipRegionAction::MetaISectRegionClipRegionAction( const Region& rRegion ) : + MetaAction ( META_ISECTREGIONCLIPREGION_ACTION ), + maRegion ( rRegion ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaISectRegionClipRegionAction::Execute( OutputDevice* pOut ) +{ + pOut->IntersectClipRegion( maRegion ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaISectRegionClipRegionAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaISectRegionClipRegionAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaISectRegionClipRegionAction::Move( long nHorzMove, long nVertMove ) +{ + maRegion.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaISectRegionClipRegionAction::Scale( double fScaleX, double fScaleY ) +{ + maRegion.Scale( fScaleX, fScaleY ); +} + + +// ------------------------------------------------------------------------ + +void MetaISectRegionClipRegionAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maRegion; +} + +// ------------------------------------------------------------------------ + +void MetaISectRegionClipRegionAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maRegion; +} + +// ======================================================================== + +IMPL_META_ACTION( MoveClipRegion, META_MOVECLIPREGION_ACTION ) + +// ------------------------------------------------------------------------ + +MetaMoveClipRegionAction::MetaMoveClipRegionAction( long nHorzMove, long nVertMove ) : + MetaAction ( META_MOVECLIPREGION_ACTION ), + mnHorzMove ( nHorzMove ), + mnVertMove ( nVertMove ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaMoveClipRegionAction::Execute( OutputDevice* pOut ) +{ + pOut->MoveClipRegion( mnHorzMove, mnVertMove ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaMoveClipRegionAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaMoveClipRegionAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaMoveClipRegionAction::Scale( double fScaleX, double fScaleY ) +{ + mnHorzMove = FRound( mnHorzMove * fScaleX ); + mnVertMove = FRound( mnVertMove * fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaMoveClipRegionAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << mnHorzMove << mnVertMove; +} + +// ------------------------------------------------------------------------ + +void MetaMoveClipRegionAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> mnHorzMove >> mnVertMove; +} + +// ======================================================================== + +IMPL_META_ACTION( LineColor, META_LINECOLOR_ACTION ) + +// ------------------------------------------------------------------------ + +MetaLineColorAction::MetaLineColorAction( const Color& rColor, BOOL bSet ) : + MetaAction ( META_LINECOLOR_ACTION ), + maColor ( rColor ), + mbSet ( bSet ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaLineColorAction::Execute( OutputDevice* pOut ) +{ + if( mbSet ) + pOut->SetLineColor( maColor ); + else + pOut->SetLineColor(); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaLineColorAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaLineColorAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaLineColorAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + maColor.Write( rOStm, TRUE ); + rOStm << mbSet; +} + +// ------------------------------------------------------------------------ + +void MetaLineColorAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + maColor.Read( rIStm, TRUE ); + rIStm >> mbSet; +} + +// ======================================================================== + +IMPL_META_ACTION( FillColor, META_FILLCOLOR_ACTION ) + +// ------------------------------------------------------------------------ + +MetaFillColorAction::MetaFillColorAction( const Color& rColor, BOOL bSet ) : + MetaAction ( META_FILLCOLOR_ACTION ), + maColor ( rColor ), + mbSet ( bSet ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaFillColorAction::Execute( OutputDevice* pOut ) +{ + if( mbSet ) + pOut->SetFillColor( maColor ); + else + pOut->SetFillColor(); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaFillColorAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaFillColorAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaFillColorAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + maColor.Write( rOStm, TRUE ); + rOStm << mbSet; +} + +// ------------------------------------------------------------------------ + +void MetaFillColorAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + maColor.Read( rIStm, TRUE ); + rIStm >> mbSet; +} + +// ======================================================================== + +IMPL_META_ACTION( TextColor, META_TEXTCOLOR_ACTION ) + +// ------------------------------------------------------------------------ + +MetaTextColorAction::MetaTextColorAction( const Color& rColor ) : + MetaAction ( META_TEXTCOLOR_ACTION ), + maColor ( rColor ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaTextColorAction::Execute( OutputDevice* pOut ) +{ + pOut->SetTextColor( maColor ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaTextColorAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaTextColorAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaTextColorAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + maColor.Write( rOStm, TRUE ); +} + +// ------------------------------------------------------------------------ + +void MetaTextColorAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + maColor.Read( rIStm, TRUE ); +} + +// ======================================================================== + +IMPL_META_ACTION( TextFillColor, META_TEXTFILLCOLOR_ACTION ) + +// ------------------------------------------------------------------------ + +MetaTextFillColorAction::MetaTextFillColorAction( const Color& rColor, BOOL bSet ) : + MetaAction ( META_TEXTFILLCOLOR_ACTION ), + maColor ( rColor ), + mbSet ( bSet ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaTextFillColorAction::Execute( OutputDevice* pOut ) +{ + if( mbSet ) + pOut->SetTextFillColor( maColor ); + else + pOut->SetTextFillColor(); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaTextFillColorAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaTextFillColorAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaTextFillColorAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + maColor.Write( rOStm, TRUE ); + rOStm << mbSet; +} + +// ------------------------------------------------------------------------ + +void MetaTextFillColorAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + maColor.Read( rIStm, TRUE ); + rIStm >> mbSet; +} + +// ======================================================================== + +IMPL_META_ACTION( TextLineColor, META_TEXTLINECOLOR_ACTION ) + +// ------------------------------------------------------------------------ + +MetaTextLineColorAction::MetaTextLineColorAction( const Color& rColor, BOOL bSet ) : + MetaAction ( META_TEXTLINECOLOR_ACTION ), + maColor ( rColor ), + mbSet ( bSet ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaTextLineColorAction::Execute( OutputDevice* pOut ) +{ + if( mbSet ) + pOut->SetTextLineColor( maColor ); + else + pOut->SetTextLineColor(); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaTextLineColorAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaTextLineColorAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaTextLineColorAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + maColor.Write( rOStm, TRUE ); + rOStm << mbSet; +} + +// ------------------------------------------------------------------------ + +void MetaTextLineColorAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + maColor.Read( rIStm, TRUE ); + rIStm >> mbSet; +} + +// ======================================================================== + +IMPL_META_ACTION( TextAlign, META_TEXTALIGN_ACTION ) + +// ------------------------------------------------------------------------ + +MetaTextAlignAction::MetaTextAlignAction( TextAlign aAlign ) : + MetaAction ( META_TEXTALIGN_ACTION ), + maAlign ( aAlign ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaTextAlignAction::Execute( OutputDevice* pOut ) +{ + pOut->SetTextAlign( maAlign ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaTextAlignAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaTextAlignAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaTextAlignAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << (UINT16) maAlign; +} + +// ------------------------------------------------------------------------ + +void MetaTextAlignAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + UINT16 nTmp16; + + COMPAT( rIStm ); + rIStm >> nTmp16; maAlign = (TextAlign) nTmp16; +} + +// ======================================================================== + +IMPL_META_ACTION( MapMode, META_MAPMODE_ACTION ) + +// ------------------------------------------------------------------------ + +MetaMapModeAction::MetaMapModeAction( const MapMode& rMapMode ) : + MetaAction ( META_MAPMODE_ACTION ), + maMapMode ( rMapMode ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaMapModeAction::Execute( OutputDevice* pOut ) +{ + pOut->SetMapMode( maMapMode ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaMapModeAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaMapModeAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaMapModeAction::Scale( double fScaleX, double fScaleY ) +{ + Point aPoint( maMapMode.GetOrigin() ); + + ImplScalePoint( aPoint, fScaleX, fScaleY ); + maMapMode.SetOrigin( aPoint ); +} + +// ------------------------------------------------------------------------ + +void MetaMapModeAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maMapMode; +} + +// ------------------------------------------------------------------------ + +void MetaMapModeAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maMapMode; +} + +// ======================================================================== + +IMPL_META_ACTION( Font, META_FONT_ACTION ) + +// ------------------------------------------------------------------------ + +MetaFontAction::MetaFontAction( const Font& rFont ) : + MetaAction ( META_FONT_ACTION ), + maFont ( rFont ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaFontAction::Execute( OutputDevice* pOut ) +{ + pOut->SetFont( maFont ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaFontAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaFontAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaFontAction::Scale( double fScaleX, double fScaleY ) +{ + Size aSize( maFont.GetSize() ); + + ImplScaleSize( aSize, fScaleX, fScaleY ); + maFont.SetSize( aSize ); +} + +// ------------------------------------------------------------------------ + +void MetaFontAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maFont; + pData->meActualCharSet = maFont.GetCharSet(); + if ( pData->meActualCharSet == RTL_TEXTENCODING_DONTKNOW ) + pData->meActualCharSet = gsl_getSystemTextEncoding(); +} + +// ------------------------------------------------------------------------ + +void MetaFontAction::Read( SvStream& rIStm, ImplMetaReadData* pData ) +{ + COMPAT( rIStm ); + rIStm >> maFont; + pData->meActualCharSet = maFont.GetCharSet(); + if ( pData->meActualCharSet == RTL_TEXTENCODING_DONTKNOW ) + pData->meActualCharSet = gsl_getSystemTextEncoding(); +} + +// ======================================================================== + +IMPL_META_ACTION( Push, META_PUSH_ACTION ) + +// ------------------------------------------------------------------------ + +MetaPushAction::MetaPushAction( USHORT nFlags ) : + MetaAction ( META_PUSH_ACTION ), + mnFlags ( nFlags ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaPushAction::Execute( OutputDevice* pOut ) +{ + pOut->Push( mnFlags ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaPushAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaPushAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaPushAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << mnFlags; +} + +// ------------------------------------------------------------------------ + +void MetaPushAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> mnFlags; +} + +// ======================================================================== + +IMPL_META_ACTION( Pop, META_POP_ACTION ) + +// ------------------------------------------------------------------------ + +void MetaPopAction::Execute( OutputDevice* pOut ) +{ + pOut->Pop(); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaPopAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaPopAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaPopAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); +} + +// ------------------------------------------------------------------------ + +void MetaPopAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); +} + +// ======================================================================== + +IMPL_META_ACTION( RasterOp, META_RASTEROP_ACTION ) + +// ------------------------------------------------------------------------ + +MetaRasterOpAction::MetaRasterOpAction( RasterOp eRasterOp ) : + MetaAction ( META_RASTEROP_ACTION ), + meRasterOp ( eRasterOp ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaRasterOpAction::Execute( OutputDevice* pOut ) +{ + pOut->SetRasterOp( meRasterOp ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaRasterOpAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaRasterOpAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaRasterOpAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << (UINT16) meRasterOp; +} + +// ------------------------------------------------------------------------ + +void MetaRasterOpAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + UINT16 nTmp16; + + COMPAT( rIStm ); + rIStm >> nTmp16; meRasterOp = (RasterOp) nTmp16; +} + +// ======================================================================== + +IMPL_META_ACTION( Transparent, META_TRANSPARENT_ACTION ) + +// ------------------------------------------------------------------------ + +MetaTransparentAction::MetaTransparentAction( const PolyPolygon& rPolyPoly, USHORT nTransPercent ) : + MetaAction ( META_TRANSPARENT_ACTION ), + maPolyPoly ( rPolyPoly ), + mnTransPercent ( nTransPercent ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaTransparentAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawTransparent( maPolyPoly, mnTransPercent ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaTransparentAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaTransparentAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaTransparentAction::Move( long nHorzMove, long nVertMove ) +{ + maPolyPoly.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaTransparentAction::Scale( double fScaleX, double fScaleY ) +{ + for( USHORT i = 0, nCount = maPolyPoly.Count(); i < nCount; i++ ) + ImplScalePoly( maPolyPoly[ i ], fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaTransparentAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maPolyPoly; + rOStm << mnTransPercent; +} + +// ------------------------------------------------------------------------ + +void MetaTransparentAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maPolyPoly; + rIStm >> mnTransPercent; +} + +// ======================================================================== + +IMPL_META_ACTION( FloatTransparent, META_FLOATTRANSPARENT_ACTION ) + +// ------------------------------------------------------------------------ + +MetaFloatTransparentAction::MetaFloatTransparentAction( const GDIMetaFile& rMtf, const Point& rPos, + const Size& rSize, const Gradient& rGradient ) : + MetaAction ( META_FLOATTRANSPARENT_ACTION ), + maMtf ( rMtf ), + maPoint ( rPos ), + maSize ( rSize ), + maGradient ( rGradient ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaFloatTransparentAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawTransparent( maMtf, maPoint, maSize, maGradient ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaFloatTransparentAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaFloatTransparentAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaFloatTransparentAction::Move( long nHorzMove, long nVertMove ) +{ + maPoint.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaFloatTransparentAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maPoint, fScaleX, fScaleY ); + ImplScaleSize( maSize, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaFloatTransparentAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maMtf << maPoint << maSize << maGradient; +} + +// ------------------------------------------------------------------------ + +void MetaFloatTransparentAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maMtf >> maPoint >> maSize >> maGradient; +} + +// ======================================================================== + +IMPL_META_ACTION( EPS, META_EPS_ACTION ) + +// ------------------------------------------------------------------------ + +MetaEPSAction::MetaEPSAction( const Point& rPoint, const Size& rSize, + const GfxLink& rGfxLink, const GDIMetaFile& rSubst ) : + MetaAction ( META_EPS_ACTION ), + maGfxLink ( rGfxLink ), + maSubst ( rSubst ), + maPoint ( rPoint ), + maSize ( rSize ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaEPSAction::Execute( OutputDevice* pOut ) +{ + pOut->DrawEPS( maPoint, maSize, maGfxLink, &maSubst ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaEPSAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaEPSAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaEPSAction::Move( long nHorzMove, long nVertMove ) +{ + maPoint.Move( nHorzMove, nVertMove ); +} + +// ------------------------------------------------------------------------ + +void MetaEPSAction::Scale( double fScaleX, double fScaleY ) +{ + ImplScalePoint( maPoint, fScaleX, fScaleY ); + ImplScaleSize( maSize, fScaleX, fScaleY ); +} + +// ------------------------------------------------------------------------ + +void MetaEPSAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maGfxLink; + rOStm << maPoint; + rOStm << maSize; + rOStm << maSubst; +} + +// ------------------------------------------------------------------------ + +void MetaEPSAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maGfxLink; + rIStm >> maPoint; + rIStm >> maSize; + rIStm >> maSubst; +} + +// ======================================================================== + +IMPL_META_ACTION( RefPoint, META_REFPOINT_ACTION ) + +// ------------------------------------------------------------------------ + +MetaRefPointAction::MetaRefPointAction( const Point& rRefPoint, BOOL bSet ) : + MetaAction ( META_REFPOINT_ACTION ), + maRefPoint ( rRefPoint ), + mbSet ( bSet ) +{ +} + +// ------------------------------------------------------------------------ + +void MetaRefPointAction::Execute( OutputDevice* pOut ) +{ + if( mbSet ) + pOut->SetRefPoint( maRefPoint ); + else + pOut->SetRefPoint(); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaRefPointAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaRefPointAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaRefPointAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maRefPoint << mbSet; +} + +// ------------------------------------------------------------------------ + +void MetaRefPointAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maRefPoint >> mbSet; +} + +// ======================================================================== + +MetaCommentAction::MetaCommentAction( long nValue ) : + MetaAction ( META_COMMENT_ACTION ), + mnValue ( nValue ) +{ + ImplInitDynamicData( NULL, 0UL ); +} + +// ------------------------------------------------------------------------ + +MetaCommentAction::MetaCommentAction( const MetaCommentAction& rAct ) : + MetaAction ( META_COMMENT_ACTION ), + maComment ( rAct.maComment ), + mnValue ( rAct.mnValue ) +{ + ImplInitDynamicData( rAct.mpData, rAct.mnDataSize ); +} + +// ------------------------------------------------------------------------ + +MetaCommentAction::MetaCommentAction( const ByteString& rComment, long nValue, const BYTE* pData, ULONG nDataSize ) : + MetaAction ( META_COMMENT_ACTION ), + maComment ( rComment ), + mnValue ( nValue ) +{ + ImplInitDynamicData( pData, nDataSize ); +} + +// ------------------------------------------------------------------------ + +MetaCommentAction::MetaCommentAction( const BYTE* pData, ULONG nDataSize ) : + MetaAction ( META_COMMENT_ACTION ), + mnValue ( 0L ) +{ + ImplInitDynamicData( pData, nDataSize ); +} + +// ------------------------------------------------------------------------ + +MetaCommentAction::~MetaCommentAction() +{ + if ( mpData ) + delete[] mpData; +} + +// ------------------------------------------------------------------------ + +void MetaCommentAction::ImplInitDynamicData( const BYTE* pData, ULONG nDataSize ) +{ + if ( nDataSize && pData ) + { + mnDataSize = nDataSize, mpData = new BYTE[ mnDataSize ]; + HMEMCPY( mpData, pData, mnDataSize ); + } + else + { + mnDataSize = 0; + mpData = NULL; + } +} + +// ------------------------------------------------------------------------ + +void MetaCommentAction::Execute( OutputDevice* pOut ) +{ + if ( pOut->GetConnectMetaFile() ) + pOut->GetConnectMetaFile()->AddAction( Clone() ); +} + +// ------------------------------------------------------------------------ + +MetaAction* MetaCommentAction::Clone() +{ + MetaAction* pClone = (MetaAction*) new MetaCommentAction( *this ); + pClone->ResetRefCount(); + return pClone; +} + +// ------------------------------------------------------------------------ + +void MetaCommentAction::Write( SvStream& rOStm, ImplMetaWriteData* pData ) +{ + WRITE_BASE_COMPAT( rOStm, 1, pData ); + rOStm << maComment << mnValue << mnDataSize; + + if ( mnDataSize ) + rOStm.Write( mpData, mnDataSize ); +} + +// ------------------------------------------------------------------------ + +void MetaCommentAction::Read( SvStream& rIStm, ImplMetaReadData* ) +{ + COMPAT( rIStm ); + rIStm >> maComment >> mnValue >> mnDataSize; + + if( mpData ) + delete[] mpData; + + if( mnDataSize ) + { + mpData = new BYTE[ mnDataSize ]; + rIStm.Read( mpData, mnDataSize ); + } + else + mpData = NULL; +} diff --git a/vcl/source/gdi/metric.cxx b/vcl/source/gdi/metric.cxx new file mode 100644 index 000000000000..b4a5f70fa5cd --- /dev/null +++ b/vcl/source/gdi/metric.cxx @@ -0,0 +1,142 @@ +/************************************************************************* + * + * $RCSfile: metric.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <metric.hxx> + +// ======================================================================= + +FontInfo::FontInfo() +{ + mpImplMetric = new ImplFontMetric; + mpImplMetric->mnRefCount = 1; + mpImplMetric->meType = TYPE_DONTKNOW; + mpImplMetric->mbDevice = FALSE; + mpImplMetric->mnAscent = 0; + mpImplMetric->mnDescent = 0; + mpImplMetric->mnLeading = 0; + mpImplMetric->mnLineHeight = 0; + mpImplMetric->mnSlant = 0; + mpImplMetric->mnFirstChar = 0; + mpImplMetric->mnLastChar = 0; +} + +// ----------------------------------------------------------------------- + +FontInfo::FontInfo( const FontInfo& rInfo ) : + Font( rInfo ) +{ + mpImplMetric = rInfo.mpImplMetric; + mpImplMetric->mnRefCount++; +} + +// ----------------------------------------------------------------------- + +FontInfo::~FontInfo() +{ + // Eventuell Metric loeschen + if ( mpImplMetric->mnRefCount > 1 ) + mpImplMetric->mnRefCount--; + else + delete mpImplMetric; +} + +// ----------------------------------------------------------------------- + +FontInfo& FontInfo::operator=( const FontInfo& rInfo ) +{ + Font::operator=( rInfo ); + + // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann + rInfo.mpImplMetric->mnRefCount++; + + // Sind wir nicht die letzten ? + if ( mpImplMetric->mnRefCount > 1 ) + mpImplMetric->mnRefCount--; + else + delete mpImplMetric; + + mpImplMetric = rInfo.mpImplMetric; + + return *this; +} + +// ----------------------------------------------------------------------- + +BOOL FontInfo::operator==( const FontInfo& rInfo ) const +{ + if ( !Font::operator==( rInfo ) ) + return FALSE; + + if ( mpImplMetric == rInfo.mpImplMetric ) + return TRUE; + + if ( (mpImplMetric->meType == rInfo.mpImplMetric->meType ) && + (mpImplMetric->mbDevice == rInfo.mpImplMetric->mbDevice ) && + (mpImplMetric->mnAscent == rInfo.mpImplMetric->mnAscent ) && + (mpImplMetric->mnDescent == rInfo.mpImplMetric->mnDescent ) && + (mpImplMetric->mnLeading == rInfo.mpImplMetric->mnLeading ) && + (mpImplMetric->mnSlant == rInfo.mpImplMetric->mnSlant ) && + (mpImplMetric->mnFirstChar == rInfo.mpImplMetric->mnFirstChar ) && + (mpImplMetric->mnLastChar == rInfo.mpImplMetric->mnLastChar ) ) + return TRUE; + else + return FALSE; +} diff --git a/vcl/source/gdi/octree.cxx b/vcl/source/gdi/octree.cxx new file mode 100644 index 000000000000..7d4f9f688d65 --- /dev/null +++ b/vcl/source/gdi/octree.cxx @@ -0,0 +1,419 @@ +/************************************************************************* + * + * $RCSfile: octree.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ +#include <limits.h> +#ifndef _SV_BMPACC_HXX +#include <bmpacc.hxx> +#endif +#ifndef _SV_IMPOCT_HXX +#include <impoct.hxx> +#endif +#ifndef _NEW_HXX +#include<tools/new.hxx> +#endif +#include <octree.hxx> + +// ------------ +// - Typedefs - +// ------------ + +#ifdef WIN +typedef ULONG huge* HPULONG; +#else +typedef ULONG* HPULONG; +#endif + +// --------- +// - pMask - +// --------- + +static BYTE pImplMask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; + +// ------------- +// - NodeCache - +// ------------- + +ImpNodeCache::ImpNodeCache( const ULONG nInitSize ) : + pActNode( NULL ) +{ + const ULONG nSize = nInitSize + 4; + + for( ULONG i = 0; i < nSize; i++ ) + { + OctreeNode* pNewNode = new NODE; + + pNewNode->pNextInCache = pActNode; + pActNode = pNewNode; + } +} + +// ------------------------------------------------------------------------ + +ImpNodeCache::~ImpNodeCache() +{ + while( pActNode ) + { + OctreeNode* pNode = pActNode; + + pActNode = pNode->pNextInCache; + delete pNode; + } +} + +// ---------- +// - Octree - +// ---------- + +Octree::Octree( ULONG nColors ) : + nMax ( nColors ), + nLeafCount ( 0L ), + pTree ( NULL ), + pAcc ( NULL ) +{ + pNodeCache = new ImpNodeCache( nColors ); + memset( pReduce, 0, ( OCTREE_BITS + 1 ) * sizeof( PNODE ) ); +} + +// ------------------------------------------------------------------------ + +Octree::Octree( const BitmapReadAccess& rReadAcc, ULONG nColors ) : + nMax ( nColors ), + nLeafCount ( 0L ), + pTree ( NULL ), + pAcc ( &rReadAcc ) +{ + pNodeCache = new ImpNodeCache( nColors ); + memset( pReduce, 0, ( OCTREE_BITS + 1 ) * sizeof( PNODE ) ); + ImplCreateOctree(); +} + +// ------------------------------------------------------------------------ + +Octree::~Octree() +{ + ImplDeleteOctree( &pTree ); + delete pNodeCache; +} + +// ------------------------------------------------------------------------ + +void Octree::AddColor( const BitmapColor& rColor ) +{ + pColor = &(BitmapColor&) rColor; + nLevel = 0L; + ImplAdd( &pTree ); + + while( nLeafCount > nMax ) + ImplReduce(); +} + +// ------------------------------------------------------------------------ + +void Octree::ImplCreateOctree() +{ + if( !!*pAcc ) + { + const long nWidth = pAcc->Width(); + const long nHeight = pAcc->Height(); + + if( pAcc->HasPalette() ) + { + for( long nY = 0; nY < nHeight; nY++ ) + { + for( long nX = 0; nX < nWidth; nX++ ) + { + pColor = &(BitmapColor&) pAcc->GetPaletteColor( pAcc->GetPixel( nY, nX ) ); + nLevel = 0L; + ImplAdd( &pTree ); + + while( nLeafCount > nMax ) + ImplReduce(); + } + } + } + else + { + BitmapColor aColor; + + pColor = &aColor; + + for( long nY = 0; nY < nHeight; nY++ ) + { + for( long nX = 0; nX < nWidth; nX++ ) + { + aColor = pAcc->GetPixel( nY, nX ); + nLevel = 0L; + ImplAdd( &pTree ); + + while( nLeafCount > nMax ) + ImplReduce(); + } + } + } + } +} + +// ------------------------------------------------------------------------ + +void Octree::ImplDeleteOctree( PPNODE ppNode ) +{ + for ( ULONG i = 0UL; i < 8UL; i++ ) + { + if ( (*ppNode)->pChild[ i ] ) + ImplDeleteOctree( &(*ppNode)->pChild[ i ] ); + } + + pNodeCache->ImplReleaseNode( *ppNode ); + *ppNode = NULL; +} + +// ------------------------------------------------------------------------ + +void Octree::ImplAdd( PPNODE ppNode ) +{ + // ggf. neuen Knoten erzeugen + if( !*ppNode ) + { + *ppNode = pNodeCache->ImplGetFreeNode(); + (*ppNode)->bLeaf = ( OCTREE_BITS == nLevel ); + + if( (*ppNode)->bLeaf ) + nLeafCount++; + else + { + (*ppNode)->pNext = pReduce[ nLevel ]; + pReduce[ nLevel ] = *ppNode; + } + } + + if( (*ppNode)->bLeaf ) + { + (*ppNode)->nCount++; + (*ppNode)->nRed += pColor->GetRed(); + (*ppNode)->nGreen += pColor->GetGreen(); + (*ppNode)->nBlue += pColor->GetBlue(); + } + else + { + const ULONG nShift = 7 - nLevel; + const BYTE cMask = pImplMask[ nLevel ]; + const ULONG nIndex = ( ( ( pColor->GetRed() & cMask ) >> nShift ) << 2 ) | + ( ( ( pColor->GetGreen() & cMask ) >> nShift ) << 1 ) | + ( ( pColor->GetBlue() & cMask ) >> nShift ); + + nLevel++; + ImplAdd( &(*ppNode)->pChild[ nIndex ] ); + } +} + +// ------------------------------------------------------------------------ + +void Octree::ImplReduce() +{ + ULONG i; + PNODE pNode; + ULONG nRedSum = 0L; + ULONG nGreenSum = 0L; + ULONG nBlueSum = 0L; + ULONG nChilds = 0L; + + for ( i = OCTREE_BITS - 1; i && !pReduce[i]; i-- ) {} + + pNode = pReduce[ i ]; + pReduce[ i ] = pNode->pNext; + + for ( i = 0; i < 8; i++ ) + { + if ( pNode->pChild[ i ] ) + { + PNODE pChild = pNode->pChild[ i ]; + + nRedSum += pChild->nRed; + nGreenSum += pChild->nGreen; + nBlueSum += pChild->nBlue; + pNode->nCount += pChild->nCount; + + pNodeCache->ImplReleaseNode( pNode->pChild[ i ] ); + pNode->pChild[ i ] = NULL; + nChilds++; + } + } + + pNode->bLeaf = TRUE; + pNode->nRed = nRedSum; + pNode->nGreen = nGreenSum; + pNode->nBlue = nBlueSum; + nLeafCount -= --nChilds; +} + +// ------------------------------------------------------------------------ + +void Octree::CreatePalette( PNODE pNode ) +{ + if( pNode->bLeaf ) + { + pNode->nPalIndex = nPalIndex; + aPal[ nPalIndex++ ] = BitmapColor( (BYTE) ( (double) pNode->nRed / pNode->nCount ), + (BYTE) ( (double) pNode->nGreen / pNode->nCount ), + (BYTE) ( (double) pNode->nBlue / pNode->nCount ) ); + } + else for( ULONG i = 0UL; i < 8UL; i++ ) + if( pNode->pChild[ i ] ) + CreatePalette( pNode->pChild[ i ] ); + +} + +// ------------------------------------------------------------------------ + +void Octree::GetPalIndex( PNODE pNode ) +{ + if ( pNode->bLeaf ) + nPalIndex = pNode->nPalIndex; + else + { + const ULONG nShift = 7 - nLevel; + const BYTE cMask = pImplMask[ nLevel++ ]; + const ULONG nIndex = ( ( ( pColor->GetRed() & cMask ) >> nShift ) << 2 ) | + ( ( ( pColor->GetGreen() & cMask ) >> nShift ) << 1 ) | + ( ( pColor->GetBlue() & cMask ) >> nShift ); + + GetPalIndex( pNode->pChild[ nIndex ] ); + } +} + +// ------------------- +// - InverseColorMap - +// ------------------- + +InverseColorMap::InverseColorMap( const BitmapPalette& rPal ) : + nBits( 8 - OCTREE_BITS ) +{ + HPULONG cdp; + BYTE* crgbp; + const ULONG nColorMax = 1 << OCTREE_BITS; + const ULONG xsqr = 1 << ( nBits << 1 ); + const ULONG xsqr2 = xsqr << 1; + const ULONG gstride = nColorMax; + const ULONG rstride = nColorMax * nColorMax; + const ULONG nColors = rPal.GetEntryCount(); + const long x = 1L << nBits; + const long x2 = x >> 1L; + ULONG r, g, b; + long rxx, gxx, bxx; + long rdist, gdist, bdist; + long crinc, cginc, cbinc; + + ImplCreateBuffers( nColorMax ); + + for( ULONG nIndex = 0; nIndex < nColors; nIndex++ ) + { + const BitmapColor& rColor = rPal[ (USHORT) nIndex ]; + const BYTE cRed = rColor.GetRed(); + const BYTE cGreen = rColor.GetGreen(); + const BYTE cBlue = rColor.GetBlue(); + + rdist = cRed - x2; + gdist = cGreen - x2; + bdist = cBlue - x2; + rdist = rdist*rdist + gdist*gdist + bdist*bdist; + + crinc = ( xsqr - ( cRed << nBits ) ) << 1L; + cginc = ( xsqr - ( cGreen << nBits ) ) << 1L; + cbinc = ( xsqr - ( cBlue << nBits ) ) << 1L; + + cdp = (HPULONG) pBuffer; + crgbp = pMap; + + for( r = 0, rxx = crinc; r < nColorMax; rdist += rxx, r++, rxx += xsqr2 ) + { + for( g = 0, gdist = rdist, gxx = cginc; g < nColorMax; gdist += gxx, g++, gxx += xsqr2 ) + { + for( b = 0, bdist = gdist, bxx = cbinc; b < nColorMax; bdist += bxx, b++, cdp++, crgbp++, bxx += xsqr2 ) + if ( !nIndex || ( (long) *cdp ) > bdist ) + { + *cdp = bdist; + *crgbp = (BYTE) nIndex; + } + } + } + } +} + +// ------------------------------------------------------------------------ + +InverseColorMap::~InverseColorMap() +{ + SvMemFree( pBuffer ); + SvMemFree( pMap ); +} + +// ------------------------------------------------------------------------ + +void InverseColorMap::ImplCreateBuffers( const ULONG nMax ) +{ + const ULONG nCount = nMax * nMax * nMax; + const ULONG nSize = nCount * sizeof( ULONG ); + + pMap = (BYTE*) SvMemAlloc( nCount ); + HMEMSET( pMap, 0x00, nCount ); + + pBuffer = (BYTE*) SvMemAlloc( nSize ); + HMEMSET( pBuffer, 0xff, nSize ); +} diff --git a/vcl/source/gdi/opengl.cxx b/vcl/source/gdi/opengl.cxx new file mode 100644 index 000000000000..fa45d1700725 --- /dev/null +++ b/vcl/source/gdi/opengl.cxx @@ -0,0 +1,1714 @@ +/************************************************************************* + * + * $RCSfile: opengl.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_OPENGL_CXX + +#define private public +#include <svsys.h> +#include <window.hxx> +#undef private +#define private public + +#ifndef _SV_OUTDEV_HXX +#include <outdev.hxx> +#endif +#ifndef _SV_SALOGL_HXX +#include <salogl.hxx> +#endif +#ifndef _SV_OPENGL_HXX +#include <opengl.hxx> +#endif + +#include <svapp.hxx> +#include <vos/mutex.hxx> + +// ----------------------- +// - Fnc-Pointer-Typedef - +// ----------------------- + +typedef void ( *OGLFncClearDepth )( GLclampd fDepth ); +typedef void ( *OGLFncDepthFunc )( GLenum fFunc ); +typedef void ( *OGLFncEnable )( GLenum eCap ); +typedef void ( *OGLFncDisable )( GLenum eCap ); +typedef void ( *OGLFncDepthMask )( GLboolean bFlag ); +typedef void ( *OGLFncShadeModel )( GLenum eMode ); +typedef void ( *OGLFncEdgeFlag )( GLboolean bFlag ); +typedef void ( *OGLFncClear )( GLbitfield nMask ); +typedef void ( *OGLFncFlush )( void ); +typedef void ( *OGLFncFinish )( void ); +typedef void ( *OGLFncViewport )( GLint nX, GLint nY, GLsizei nWidth, GLsizei nHeight ); +typedef void ( *OGLFncBegin )( GLenum eMode ); +typedef void ( *OGLFncEnd )( void ); +typedef void ( *OGLFncVertex3dv )( const GLdouble *fV ); +typedef void ( *OGLFncNormal3dv )( const GLdouble *fV ); +typedef void ( *OGLFncColor4ub )( GLubyte cRed, GLubyte cGreen, GLubyte cBlue, GLubyte cAlpha ); +typedef void ( *OGLFncMaterialfv )( GLenum eFace, GLenum ePNname, const GLfloat *fParams ); +typedef void ( *OGLFncMaterialf )( GLenum eFace, GLenum ePName, GLfloat fParam ); +typedef void ( *OGLFncLightModelfv )( GLenum ePNname, const GLfloat *fParams ); +typedef void ( *OGLFncLightModelf )( GLenum ePname, GLfloat fParam ); +typedef void ( *OGLFncLightfv )( GLenum eLight, GLenum ePNname, const GLfloat *fParams ); +typedef void ( *OGLFncLightf )( GLenum eLight, GLenum ePname, GLfloat fParam ); +typedef void ( *OGLFncPolygonMode )( GLenum eFace, GLenum eMode ); +typedef void ( *OGLFncCullFace )( GLenum eMode ); +typedef void ( *OGLFncPointSize )( GLfloat fSize ); +typedef void ( *OGLFncLineWidth )( GLfloat fWidth ); +typedef void ( *OGLFncMatrixMode )( GLenum eMode ); +typedef void ( *OGLFncLoadMatrixd )( const GLdouble *fM ); +typedef void ( *OGLFncTexCoord2dv )( const GLdouble *pParams ); +typedef void ( *OGLFncTexCoord3dv )( const GLdouble *fV ); +typedef void ( *OGLFncTexImage1D )( GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels ); +typedef void ( *OGLFncTexImage2D )( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels ); +typedef void ( *OGLFncCopyTexImage1D )( GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border ); +typedef void ( *OGLFncCopyTexImage2D )( GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ); +typedef void ( *OGLFncCopyTexSubImage1D )( GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width ); +typedef void ( *OGLFncCopyTexSubImage2D )( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ); +typedef void ( *OGLFncPixelTransferf )( GLenum pname, GLfloat param ); +typedef void ( *OGLFncPixelTransferi )( GLenum pname, GLint param ); +typedef void ( *OGLFncGetTexLevelParameterfv )( GLenum target, GLint level, GLenum pname, GLfloat *params ); +typedef void ( *OGLFncGetTexLevelParameteriv )( GLenum target, GLint level, GLenum pname, GLint *params ); +typedef void ( *OGLFncGetTexParameterfv )( GLenum target, GLenum pname, GLfloat *params ); +typedef void ( *OGLFncGetTexParameteriv )( GLenum target, GLenum pname, GLint *params ); +typedef void ( *OGLFncTexSubImage1D )( GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels ); +typedef void ( *OGLFncTexSubImage2D )( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ); +typedef void ( *OGLFncPixelStoref )( GLenum pname, GLfloat param ); +typedef void ( *OGLFncPixelStorei )( GLenum pname, GLint param ); +typedef void ( *OGLFncGenTextures )( GLsizei n, GLuint *textures ); +typedef GLboolean ( *OGLFncIsTexture )( GLuint texture ); +typedef void ( *OGLFncBindTexture )( GLenum target, GLuint texture ); +typedef void ( *OGLFncDeleteTextures )( GLsizei n, const GLuint *textures ); +typedef GLboolean ( *OGLFncAreTexturesResident )( GLsizei n, const GLuint *textures, GLboolean *residences ); +typedef void ( *OGLFncPrioritizeTextures )( GLsizei n, const GLuint *textures, const GLclampf *priorities ); +typedef void ( *OGLFncTexEnvf )( GLenum target, GLenum pname, GLfloat param ); +typedef void ( *OGLFncTexEnvfv )( GLenum target, GLenum pname, const GLfloat *params ); +typedef void ( *OGLFncTexEnvi )( GLenum target, GLenum pname, GLint param ); +typedef void ( *OGLFncTexEnviv )( GLenum target, GLenum pname, const GLint *params ); +typedef void ( *OGLFncTexParameterf )( GLenum target, GLenum pname, GLfloat param ); +typedef void ( *OGLFncTexParameterfv )( GLenum target, GLenum pname, const GLfloat *params ); +typedef void ( *OGLFncTexParameteri )( GLenum target, GLenum pname, GLint param ); +typedef void ( *OGLFncTexParameteriv )( GLenum target, GLenum pname, const GLint *params ); +typedef void ( *OGLFncTexGend )( GLenum coord, GLenum pname, GLdouble param ); +typedef void ( *OGLFncTexGendv )( GLenum coord, GLenum pname, const GLdouble *params ); +typedef void ( *OGLFncTexGenf )( GLenum coord, GLenum pname, GLfloat param ); +typedef void ( *OGLFncTexGenfv )( GLenum coord, GLenum pname, const GLfloat *params ); +typedef void ( *OGLFncTexGeni )( GLenum coord, GLenum pname, GLint param ); +typedef void ( *OGLFncTexGeniv )( GLenum coord, GLenum pname, const GLint *params ); +typedef void ( *OGLFncGetIntegerv )( GLenum pname, GLint *params ); +typedef void ( *OGLFncPolygonOffset ) ( GLfloat factor, GLfloat units ); +typedef void ( *OGLFncScissor ) ( GLint x, GLint y, GLsizei width, GLsizei height ); + +typedef void ( *OGLFncEnableClientState ) ( GLenum array ); +typedef void ( *OGLFncDisableClientState ) ( GLenum array ); +typedef void ( *OGLFncVertexPointer ) ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ); +typedef void ( *OGLFncColorPointer ) ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ); +typedef void ( *OGLFncIndexPointer ) ( GLenum type, GLsizei stride, const GLvoid *pointer ); +typedef void ( *OGLFncNormalPointer ) ( GLenum type, GLsizei stride, const GLvoid *pointer ); +typedef void ( *OGLFncTexCoordPointer ) ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ); +typedef void ( *OGLFncEdgeFlagPointer ) ( GLsizei stride, const GLvoid *pointer ); +typedef void ( *OGLFncArrayElement ) ( GLint i ); +typedef void ( *OGLFncDrawElements ) ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices ); +typedef void ( *OGLFncDrawArrays ) ( GLenum mode, GLint first, GLsizei count ); +typedef void ( *OGLFncInterleavedArrays ) ( GLenum format, GLsizei stride, const GLvoid *pointer ); + +typedef void ( *OGLFncLoadIdentity ) (); +typedef void ( *OGLFncBlendFunc ) ( GLenum sfactor, GLenum dfactor ); + +// ---------- +// - Macros - +// ---------- + +#define PGRAPHICS mpOutDev->mpGraphics + +#ifndef REMOTE_APPSERVER +#define OGL_INIT() (mpOGL && (mpOutDev->mpGraphics || mpOutDev->ImplGetGraphics())) +#else +#define OGL_INIT() (mpOGL && (mpOutDev->mpGraphics || mpOutDev->ImplGetGraphics())) +#endif + +#define INIT_OGLFNC( FncName ) static OGLFnc##FncName pImplOpenGLFnc##FncName = NULL; +#define GET_OGLFNC_GL( FncName ) \ +pImplOpenGLFnc##FncName = (OGLFnc##FncName##) mpOGL->GetOGLFnc( "gl" #FncName ); \ +if( !pImplOpenGLFnc##FncName ) bRet = FALSE; + +// ---------- +// - OpenGL - +// ---------- + +static BOOL bImplOpenGLFncPtrInitialized = FALSE; + +INIT_OGLFNC( ClearDepth ); +INIT_OGLFNC( DepthFunc ); +INIT_OGLFNC( Enable ); +INIT_OGLFNC( Disable ); +INIT_OGLFNC( DepthMask ); +INIT_OGLFNC( ShadeModel ); +INIT_OGLFNC( EdgeFlag ); +INIT_OGLFNC( Clear ); +INIT_OGLFNC( Flush ); +INIT_OGLFNC( Finish ); +INIT_OGLFNC( Viewport ); +INIT_OGLFNC( Begin ); +INIT_OGLFNC( End ); +INIT_OGLFNC( Vertex3dv ); +INIT_OGLFNC( Normal3dv ); +INIT_OGLFNC( Color4ub ); +INIT_OGLFNC( Materialfv ); +INIT_OGLFNC( Materialf ); +INIT_OGLFNC( LightModelfv ); +INIT_OGLFNC( LightModelf ); +INIT_OGLFNC( Lightfv ); +INIT_OGLFNC( Lightf ); +INIT_OGLFNC( PolygonMode ); +INIT_OGLFNC( CullFace ); +INIT_OGLFNC( PointSize ); +INIT_OGLFNC( LineWidth ); +INIT_OGLFNC( MatrixMode ); +INIT_OGLFNC( LoadMatrixd ); +INIT_OGLFNC( TexCoord2dv ); +INIT_OGLFNC( TexCoord3dv ); +INIT_OGLFNC( TexImage1D ); +INIT_OGLFNC( TexImage2D ); +INIT_OGLFNC( CopyTexImage1D ); +INIT_OGLFNC( CopyTexImage2D ); +INIT_OGLFNC( CopyTexSubImage1D ); +INIT_OGLFNC( CopyTexSubImage2D ); +INIT_OGLFNC( PixelTransferf ); +INIT_OGLFNC( PixelTransferi ); +INIT_OGLFNC( GetTexLevelParameterfv ); +INIT_OGLFNC( GetTexLevelParameteriv ); +INIT_OGLFNC( GetTexParameterfv ); +INIT_OGLFNC( GetTexParameteriv ); +INIT_OGLFNC( TexSubImage1D ); +INIT_OGLFNC( TexSubImage2D ); +INIT_OGLFNC( PixelStoref ); +INIT_OGLFNC( PixelStorei ); +INIT_OGLFNC( GenTextures ); +INIT_OGLFNC( IsTexture ); +INIT_OGLFNC( BindTexture ); +INIT_OGLFNC( DeleteTextures ); +INIT_OGLFNC( AreTexturesResident ); +INIT_OGLFNC( PrioritizeTextures ); +INIT_OGLFNC( TexEnvf ); +INIT_OGLFNC( TexEnvfv ); +INIT_OGLFNC( TexEnvi ); +INIT_OGLFNC( TexEnviv ); +INIT_OGLFNC( TexParameterf ); +INIT_OGLFNC( TexParameterfv ); +INIT_OGLFNC( TexParameteri ); +INIT_OGLFNC( TexParameteriv ); +INIT_OGLFNC( TexGend ); +INIT_OGLFNC( TexGendv ); +INIT_OGLFNC( TexGenf ); +INIT_OGLFNC( TexGenfv ); +INIT_OGLFNC( TexGeni ); +INIT_OGLFNC( TexGeniv ); +INIT_OGLFNC( GetIntegerv ); +INIT_OGLFNC( PolygonOffset ); +INIT_OGLFNC( Scissor ); + +INIT_OGLFNC( EnableClientState ); +INIT_OGLFNC( DisableClientState ); +INIT_OGLFNC( VertexPointer ); +INIT_OGLFNC( ColorPointer ); +INIT_OGLFNC( IndexPointer ); +INIT_OGLFNC( NormalPointer ); +INIT_OGLFNC( TexCoordPointer ); +INIT_OGLFNC( EdgeFlagPointer ); +INIT_OGLFNC( ArrayElement ); +INIT_OGLFNC( DrawElements ); +INIT_OGLFNC( DrawArrays ); +INIT_OGLFNC( InterleavedArrays ); + +INIT_OGLFNC( LoadIdentity ); +INIT_OGLFNC( BlendFunc ); + +// ------------------------------------------------------------------------ + +BOOL OpenGL::ImplInitFncPointers() +{ +#ifndef REMOTE_APPSERVER + BOOL bRet = TRUE; + + GET_OGLFNC_GL( ClearDepth ); + GET_OGLFNC_GL( DepthFunc ); + GET_OGLFNC_GL( Enable ); + GET_OGLFNC_GL( Disable ); + GET_OGLFNC_GL( DepthMask ); + GET_OGLFNC_GL( ShadeModel ); + GET_OGLFNC_GL( EdgeFlag ); + GET_OGLFNC_GL( Clear ); + GET_OGLFNC_GL( Flush ); + GET_OGLFNC_GL( Finish ); + GET_OGLFNC_GL( Viewport ); + GET_OGLFNC_GL( Begin ); + GET_OGLFNC_GL( End ); + GET_OGLFNC_GL( Vertex3dv ); + GET_OGLFNC_GL( Normal3dv ); + GET_OGLFNC_GL( Color4ub ); + GET_OGLFNC_GL( Materialfv ); + GET_OGLFNC_GL( Materialf ); + GET_OGLFNC_GL( LightModelfv ); + GET_OGLFNC_GL( LightModelf ); + GET_OGLFNC_GL( Lightfv ); + GET_OGLFNC_GL( Lightf ); + GET_OGLFNC_GL( PolygonMode ); + GET_OGLFNC_GL( CullFace ); + GET_OGLFNC_GL( PointSize ); + GET_OGLFNC_GL( LineWidth ); + GET_OGLFNC_GL( MatrixMode ); + GET_OGLFNC_GL( LoadMatrixd ); + GET_OGLFNC_GL( TexCoord2dv ); + GET_OGLFNC_GL( TexCoord3dv ); + GET_OGLFNC_GL( TexImage1D ); + GET_OGLFNC_GL( TexImage2D ); + GET_OGLFNC_GL( CopyTexImage1D ); + GET_OGLFNC_GL( CopyTexImage2D ); + GET_OGLFNC_GL( CopyTexSubImage1D ); + GET_OGLFNC_GL( CopyTexSubImage2D ); + GET_OGLFNC_GL( PixelTransferf ); + GET_OGLFNC_GL( PixelTransferi ); + GET_OGLFNC_GL( GetTexLevelParameterfv ); + GET_OGLFNC_GL( GetTexLevelParameteriv ); + GET_OGLFNC_GL( GetTexParameterfv ); + GET_OGLFNC_GL( GetTexParameteriv ); + GET_OGLFNC_GL( TexSubImage1D ); + GET_OGLFNC_GL( TexSubImage2D ); + GET_OGLFNC_GL( PixelStoref ); + GET_OGLFNC_GL( PixelStorei ); + GET_OGLFNC_GL( GenTextures ); + GET_OGLFNC_GL( IsTexture ); + GET_OGLFNC_GL( BindTexture ); + GET_OGLFNC_GL( DeleteTextures ); + GET_OGLFNC_GL( AreTexturesResident ); + GET_OGLFNC_GL( PrioritizeTextures ); + GET_OGLFNC_GL( TexEnvf ); + GET_OGLFNC_GL( TexEnvfv ); + GET_OGLFNC_GL( TexEnvi ); + GET_OGLFNC_GL( TexEnviv ); + GET_OGLFNC_GL( TexParameterf ); + GET_OGLFNC_GL( TexParameterfv ); + GET_OGLFNC_GL( TexParameteri ); + GET_OGLFNC_GL( TexParameteriv ); + GET_OGLFNC_GL( TexGend ); + GET_OGLFNC_GL( TexGendv ); + GET_OGLFNC_GL( TexGenf ); + GET_OGLFNC_GL( TexGenfv ); + GET_OGLFNC_GL( TexGeni ); + GET_OGLFNC_GL( TexGeniv ); + GET_OGLFNC_GL( GetIntegerv ); + GET_OGLFNC_GL( PolygonOffset ); + GET_OGLFNC_GL( Scissor ); + + GET_OGLFNC_GL( EnableClientState ); + GET_OGLFNC_GL( DisableClientState ); + GET_OGLFNC_GL( VertexPointer ); + GET_OGLFNC_GL( ColorPointer ); + GET_OGLFNC_GL( IndexPointer ); + GET_OGLFNC_GL( NormalPointer ); + GET_OGLFNC_GL( TexCoordPointer ); + GET_OGLFNC_GL( EdgeFlagPointer ); + GET_OGLFNC_GL( ArrayElement ); + GET_OGLFNC_GL( DrawElements ); + GET_OGLFNC_GL( DrawArrays ); + GET_OGLFNC_GL( InterleavedArrays ); + + GET_OGLFNC_GL( LoadIdentity ); + GET_OGLFNC_GL( BlendFunc ); + + return bRet; +#else + return FALSE; +#endif +} + +// ------------------------------------------------------------------------ + +OpenGL::OpenGL( OutputDevice* pOutDev ) : + mpOutDev( pOutDev ) +{ + ImplInit(); +} + +// ------------------------------------------------------------------------ + +OpenGL::~OpenGL() +{ +#ifndef REMOTE_APPSERVER + delete mpOGL; +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::ImplInit() +{ +#ifndef REMOTE_APPSERVER + if( PGRAPHICS || mpOutDev->ImplGetGraphics() ) + { + mpOGL = new SalOpenGL( PGRAPHICS ); + + if ( !mpOGL->Create() || (!bImplOpenGLFncPtrInitialized && !ImplInitFncPointers()) ) + { + delete mpOGL; + mpOGL = NULL; + } + else + bImplOpenGLFncPtrInitialized = TRUE; + } + else + mpOGL = NULL; +#else + mpOGL = NULL; +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::SetConnectOutputDevice( OutputDevice* pOutDev ) +{ +#ifndef REMOTE_APPSERVER + delete mpOGL; + mpOutDev = pOutDev; + ImplInit(); +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::ClearDepth( GLclampd fDepth ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncClearDepth( fDepth ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::DepthFunc( GLenum eFunc ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncDepthFunc( eFunc ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::Enable( GLenum eCap ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncEnable( eCap ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::Disable( GLenum eCap ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncDisable( eCap ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::DepthMask( GLboolean bFlag ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncDepthMask( bFlag ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::ShadeModel( GLenum eMode ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncShadeModel( eMode ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::EdgeFlag( GLboolean bFlag ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncEdgeFlag( bFlag ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::Clear( GLbitfield nMask ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { +#if defined UNX && ! defined MACOSX + mpOGL->StartScene( PGRAPHICS ); +#endif + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncClear( nMask ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::Flush() +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncFlush(); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::Finish() +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncFinish(); +#if defined UNX && ! defined MACOSX + mpOGL->StopScene(); +#endif + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::Viewport( GLint nX, GLint nY, GLsizei nWidth, GLsizei nHeight ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + long nOutHeight; + + if( mpOutDev->GetOutDevType() == OUTDEV_WINDOW ) + nOutHeight = ( (Window*) mpOutDev )->mpFrameWindow->mnOutHeight; + else + nOutHeight = mpOutDev->mnOutHeight; + + mpOGL->OGLEntry( PGRAPHICS ); + + pImplOpenGLFncViewport( nX + mpOutDev->mnOutOffX, + nOutHeight - nY - nHeight - mpOutDev->mnOutOffY, + nWidth, nHeight ); + + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::Begin( GLenum eMode ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncBegin( eMode ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::End() +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncEnd(); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::Vertex3dv( const GLdouble* fVar ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncVertex3dv( fVar ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::Normal3dv( const GLdouble* fVar ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncNormal3dv( fVar ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::Color4ub( GLubyte cRed, GLubyte cGreen, GLubyte cBlue, GLubyte cAlpha ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncColor4ub( cRed, cGreen, cBlue, cAlpha ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::Materialfv( GLenum eFace, GLenum ePName, const GLfloat *fParams ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncMaterialfv( eFace, ePName, fParams ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::Materialf( GLenum eFace, GLenum ePName, GLfloat fParam ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncMaterialf( eFace, ePName, fParam ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::LightModelfv( GLenum ePName, const GLfloat *fParams ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncLightModelfv( ePName, fParams ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::LightModelf( GLenum ePName, GLfloat fParam ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncLightModelf( ePName, fParam ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::Lightfv( GLenum eLight, GLenum ePName, const GLfloat *fParams ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncLightfv( eLight, ePName, fParams ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::Lightf( GLenum eLight, GLenum ePName, GLfloat fParam ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncLightf( eLight, ePName, fParam ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::PolygonMode( GLenum eFace, GLenum eMode ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncPolygonMode( eFace, eMode ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::CullFace( GLenum eMode ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncCullFace( eMode ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::PointSize( GLfloat fSize ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncPointSize( fSize ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::LineWidth( GLfloat fWidth ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncLineWidth( fWidth ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::MatrixMode( GLenum eMode ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncMatrixMode( eMode ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::LoadMatrixd( const GLdouble *fM ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncLoadMatrixd( fM ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexCoord2dv( const GLdouble *pParams ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexCoord2dv( pParams ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexCoord3dv( const GLdouble *fVar ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexCoord3dv( fVar ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexImage1D( GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexImage1D( target, level, internalformat, width, border, format, type, pixels ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexImage2D( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexImage2D( target, level, internalformat, width, height, border, format, type, pixels ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::CopyTexImage1D( GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncCopyTexImage1D( target, level, internalFormat, x, y, width, border ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncCopyTexImage2D( target, level, internalFormat, x, y, width, height, border ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::CopyTexSubImage1D( GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncCopyTexSubImage1D( target, level, xoffset, x, y, width ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::CopyTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncCopyTexSubImage2D( target, level, xoffset, yoffset, x, y, width, height ); + mpOGL->OGLExit( PGRAPHICS ); + } + +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::PixelTransferf( GLenum pname, GLfloat param ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncPixelTransferf( pname, param ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::PixelTransferi( GLenum pname, GLint param ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncPixelTransferi( pname, param ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::GetTexLevelParameterfv( GLenum target, GLint level, GLenum pname, GLfloat *params ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncGetTexLevelParameterfv( target, level, pname, params ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::GetTexLevelParameteriv( GLenum target, GLint level, GLenum pname, GLint *params ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncGetTexLevelParameteriv( target, level, pname, params ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::GetTexParameterfv( GLenum target, GLenum pname, GLfloat *params ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncGetTexParameterfv( target, pname, params ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::GetTexParameteriv( GLenum target, GLenum pname, GLint *params ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncGetTexParameteriv( target, pname, params ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexSubImage1D( GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexSubImage1D( target, level, xoffset, width, format, type, pixels ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexSubImage2D( target, level, xoffset, yoffset, width, height, format, type, pixels ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::PixelStoref( GLenum pname, GLfloat param ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncPixelStoref( pname, param ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::PixelStorei( GLenum pname, GLint param ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncPixelStorei( pname, param ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::GenTextures( GLsizei n, GLuint *textures ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncGenTextures( n, textures ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +GLboolean OpenGL::IsTexture( GLuint texture ) +{ + GLboolean bRet = FALSE; + +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + bRet = pImplOpenGLFncIsTexture( texture ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif + + return bRet; +} + +// ------------------------------------------------------------------------ + +void OpenGL::BindTexture( GLenum target, GLuint texture ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncBindTexture( target, texture ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::DeleteTextures( GLsizei n, const GLuint *textures ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncDeleteTextures( n, textures ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +GLboolean OpenGL::AreTexturesResident( GLsizei n, const GLuint *textures, GLboolean *residences ) +{ + GLboolean bRet = FALSE; + +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + bRet = pImplOpenGLFncAreTexturesResident( n, textures, residences ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif + + return bRet; +} + +// ------------------------------------------------------------------------ + +void OpenGL::PrioritizeTextures( GLsizei n, const GLuint *textures, const GLclampf *priorities ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncPrioritizeTextures( n, textures, priorities ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexEnvf( GLenum target, GLenum pname, GLfloat param ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexEnvf( target, pname, param ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexEnvfv( GLenum target, GLenum pname, const GLfloat *params ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexEnvfv( target, pname, params ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexEnvi( GLenum target, GLenum pname, GLint param ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexEnvi( target, pname, param ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexEnviv( GLenum target, GLenum pname, const GLint *params ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexEnviv( target, pname, params ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexParameterf( GLenum target, GLenum pname, GLfloat param ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexParameterf( target, pname, param ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexParameterfv( GLenum target, GLenum pname, const GLfloat *params ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexParameterfv( target, pname, params ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexParameteri( GLenum target, GLenum pname, GLint param ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexParameteri( target, pname, param ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexParameteriv( GLenum target, GLenum pname, const GLint *params ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexParameteriv( target, pname, params ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexGend( GLenum coord, GLenum pname, GLdouble param ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexGend( coord, pname, param ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexGendv( GLenum coord, GLenum pname, const GLdouble *params ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexGendv( coord, pname, params ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexGenf( GLenum coord, GLenum pname, GLfloat param ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexGenf( coord, pname, param ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexGenfv( GLenum coord, GLenum pname, const GLfloat *params ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexGenfv( coord, pname, params ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexGeni( GLenum coord, GLenum pname, GLint param ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexGeni( coord, pname, param ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexGeniv( GLenum coord, GLenum pname, const GLint *params ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexGeniv( coord, pname, params ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::GetIntegerv( GLenum pname, GLint *params ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncGetIntegerv( pname, params ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::PolygonOffset( GLfloat factor, GLfloat units ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncPolygonOffset( factor, units ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::Scissor( GLint nX, GLint nY, GLsizei nWidth, GLsizei nHeight ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + long nOutHeight; + + if( mpOutDev->GetOutDevType() == OUTDEV_WINDOW ) + nOutHeight = ( (Window*) mpOutDev )->mpFrameWindow->mnOutHeight; + else + nOutHeight = mpOutDev->mnOutHeight; + + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncScissor( nX + mpOutDev->mnOutOffX, + nOutHeight - nY - nHeight - mpOutDev->mnOutOffY, + nWidth, nHeight ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::EnableClientState( GLenum array ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncEnableClientState( array ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::DisableClientState( GLenum array ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncDisableClientState( array ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::VertexPointer( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncVertexPointer( size, type, stride, pointer ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::ColorPointer( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncColorPointer( size, type, stride, pointer ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::IndexPointer( GLenum type, GLsizei stride, const GLvoid *pointer ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncIndexPointer( type, stride, pointer ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::NormalPointer( GLenum type, GLsizei stride, const GLvoid *pointer ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncNormalPointer( type, stride, pointer ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::TexCoordPointer( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncTexCoordPointer( size, type, stride, pointer ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::EdgeFlagPointer( GLsizei stride, const GLvoid *pointer ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncEdgeFlagPointer( stride, pointer ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::ArrayElement( GLint i ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncArrayElement( i ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::DrawElements( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncDrawElements( mode, count, type, indices ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::DrawArrays( GLenum mode, GLint first, GLsizei count ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncDrawArrays( mode, first, count ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::InterleavedArrays( GLenum format, GLsizei stride, const GLvoid *pointer ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncInterleavedArrays( format, stride, pointer ); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::LoadIdentity( ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncLoadIdentity(); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + +// ------------------------------------------------------------------------ + +void OpenGL::BlendFunc( GLenum sfactor, GLenum dfactor ) +{ +#ifndef REMOTE_APPSERVER + if( OGL_INIT() ) + { + mpOGL->OGLEntry( PGRAPHICS ); + pImplOpenGLFncBlendFunc( sfactor, dfactor); + mpOGL->OGLExit( PGRAPHICS ); + } +#else +#endif +} + diff --git a/vcl/source/gdi/outdev.cxx b/vcl/source/gdi/outdev.cxx new file mode 100644 index 000000000000..591ecf8c8f8d --- /dev/null +++ b/vcl/source/gdi/outdev.cxx @@ -0,0 +1,1927 @@ +/************************************************************************* + * + * $RCSfile: outdev.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_OUTDEV_CXX +#include <tools/ref.hxx> +#ifndef REMOTE_APPSERVER +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#endif + +#ifndef REMOTE_APPSERVER +#ifndef _SV_SALGDI_HXX +#include <salgdi.hxx> +#endif +#ifndef _SV_SALFRAME_HXX +#include <salframe.hxx> +#endif +#ifndef _SV_SALVD_HXX +#include <salvd.hxx> +#endif +#ifndef _SV_SALPRN_HXX +#include <salprn.hxx> +#endif +#else +#ifndef _SV_RMOUTDEV_HXX +#include <rmoutdev.hxx> +#endif +#endif + +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _SV_SVDATA_HXX +#include <svdata.hxx> +#endif +#ifndef _SV_SVAPP_HXX +#include <svapp.hxx> +#endif +#ifndef _SV_POLY_H +#include <poly.h> +#endif +#ifndef _SV_POLY_HXX +#include <poly.hxx> +#endif +#ifndef _SV_REGION_HXX +#include <region.hxx> +#endif +#ifndef _SV_REGION_H +#include <region.h> +#endif +#ifndef _SV_VIRDEV_HXX +#include <virdev.hxx> +#endif +#ifndef _SV_WINDOW_H +#include <window.h> +#endif +#ifndef _SV_WINDOW_HXX +#include <window.hxx> +#endif +#ifndef _SV_METAACT_HXX +#include <metaact.hxx> +#endif +#ifndef _SV_GDIMTF_HXX +#include <gdimtf.hxx> +#endif +#ifndef _SV_OUTDATA_HXX +#include <outdata.hxx> +#endif +#ifndef _SV_PRINT_HXX +#include <print.hxx> +#endif +#ifndef _SV_SALOTYPE_HXX +#include <salotype.hxx> +#endif +#ifndef _SV_OPENGL_HXX +#include <opengl.hxx> +#endif +#ifndef _VCL_IMPLNCVT_HXX +#include <implncvt.hxx> +#endif +#ifndef _SV_OUTDEV3D_HXX +#include <outdev3d.hxx> +#endif +#ifndef _SV_OUTDEV_H +#include <outdev.h> +#endif +#ifndef _SV_OUTDEV_HXX +#include <outdev.hxx> +#endif +#ifndef _VCL_UNOWRAP_HXX +#include <unowrap.hxx> +#endif + +#include <com/sun/star/awt/XGraphics.hpp> + +DBG_NAME( OutputDevice ); +DBG_NAMEEX( Polygon ); +DBG_NAMEEX( PolyPolygon ); +DBG_NAMEEX( Region ); + +// ----------------------------------------------------------------------- + +#ifdef DBG_UTIL +const char* ImplDbgCheckOutputDevice( const void* pObj ) +{ + DBG_TESTSOLARMUTEX(); + + const OutputDevice* pOutDev = (OutputDevice*)pObj; + + if ( (pOutDev->GetOutDevType() != OUTDEV_DONTKNOW) && + (pOutDev->GetOutDevType() != OUTDEV_WINDOW) && + (pOutDev->GetOutDevType() != OUTDEV_PRINTER) && + (pOutDev->GetOutDevType() != OUTDEV_VIRDEV) ) + return "OutputDevice data overwrite"; + + return NULL; +} +#endif + +// ======================================================================= + +#define OUTDEV_POLYPOLY_STACKBUF 32 + +// ======================================================================= + +struct ImplObjStack +{ + ImplObjStack* mpPrev; + MapMode* mpMapMode; + Region* mpClipRegion; + Color* mpLineColor; + Color* mpFillColor; + Font* mpFont; + Color* mpTextColor; + Color* mpTextFillColor; + Color* mpTextLineColor; + Point* mpRefPoint; + TextAlign meTextAlign; + RasterOp meRasterOp; + USHORT mnFlags; +}; + +// ----------------------------------------------------------------------- + +static void ImplDeleteObjStack( ImplObjStack* pObjStack ) +{ + if ( pObjStack->mnFlags & PUSH_LINECOLOR ) + { + if ( pObjStack->mpLineColor ) + delete pObjStack->mpLineColor; + } + if ( pObjStack->mnFlags & PUSH_FILLCOLOR ) + { + if ( pObjStack->mpFillColor ) + delete pObjStack->mpFillColor; + } + if ( pObjStack->mnFlags & PUSH_FONT ) + delete pObjStack->mpFont; + if ( pObjStack->mnFlags & PUSH_TEXTCOLOR ) + delete pObjStack->mpTextColor; + if ( pObjStack->mnFlags & PUSH_TEXTFILLCOLOR ) + { + if ( pObjStack->mpTextFillColor ) + delete pObjStack->mpTextFillColor; + } + if ( pObjStack->mnFlags & PUSH_TEXTLINECOLOR ) + { + if ( pObjStack->mpTextLineColor ) + delete pObjStack->mpTextLineColor; + } + if ( pObjStack->mnFlags & PUSH_MAPMODE ) + { + if ( pObjStack->mpMapMode ) + delete pObjStack->mpMapMode; + } + if ( pObjStack->mnFlags & PUSH_CLIPREGION ) + { + if ( pObjStack->mpClipRegion ) + delete pObjStack->mpClipRegion; + } + if ( pObjStack->mnFlags & PUSH_REFPOINT ) + { + if ( pObjStack->mpRefPoint ) + delete pObjStack->mpRefPoint; + } + + delete pObjStack; +} + +// ----------------------------------------------------------------------- + +#ifndef REMOTE_APPSERVER + +BOOL OutputDevice::ImplSelectClipRegion( SalGraphics* pGraphics, const Region& rRegion ) +{ + DBG_TESTSOLARMUTEX(); + + long nX; + long nY; + long nWidth; + long nHeight; + ULONG nRectCount; + ImplRegionInfo aInfo; + BOOL bRegionRect; + BOOL bClipRegion = TRUE; + + nRectCount = rRegion.GetRectCount(); + pGraphics->BeginSetClipRegion( nRectCount ); + bRegionRect = rRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); + while ( bRegionRect ) + { + if ( !pGraphics->UnionClipRegion( nX, nY, nWidth, nHeight ) ) + bClipRegion = FALSE; + DBG_ASSERT( bClipRegion, "OutputDevice::ImplSelectClipRegion() - can't cerate region" ); + bRegionRect = rRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + } + pGraphics->EndSetClipRegion(); + return bClipRegion; +} + +#endif + +// ======================================================================= + +OutputDevice::OutputDevice() : + maRegion( REGION_NULL ), + maSettings( Application::GetSettings() ), + maFillColor( COL_WHITE ), + maTextLineColor( COL_TRANSPARENT ) +{ + DBG_CTOR( OutputDevice, ImplDbgCheckOutputDevice ); + + mpGraphics = NULL; + mpUnoGraphicsList = NULL; + mpPrevGraphics = NULL; + mpNextGraphics = NULL; + mpMetaFile = NULL; + mpFontEntry = NULL; + mpFontCache = NULL; + mpFontList = NULL; + mpGetDevFontList = NULL; + mpGetDevSizeList = NULL; + mpObjStack = NULL; + mpOutDevData = NULL; + mp3DContext = NULL; + mnOutOffX = 0; + mnOutOffY = 0; + mnOutWidth = 0; + mnOutHeight = 0; + mnDPIX = 0; + mnDPIY = 0; + mnTextOffX = 0; + mnTextOffY = 0; + mnDrawMode = 0; + meOutDevType = OUTDEV_DONTKNOW; + mbMap = FALSE; + mbClipRegion = FALSE; + mbBackground = FALSE; + mbOutput = TRUE; + mbDevOutput = FALSE; + mbOutputClipped = FALSE; + maTextColor = maFont.GetColor(); + maTextFillColorDummy= maFont.GetFillColor(); + meTextAlign = maFont.GetAlign(); + meRasterOp = ROP_OVERPAINT; + mbLineColor = TRUE; + mbFillColor = TRUE; + mbInitLineColor = TRUE; + mbInitFillColor = TRUE; + mbInitFont = TRUE; + mbInitTextColor = TRUE; + mbInitClipRegion = TRUE; + mbClipRegionSet = FALSE; + mbKerning = FALSE; + mbNewFont = TRUE; + mbTextLines = FALSE; + mbTextSpecial = FALSE; + mbRefPoint = FALSE; +} + +// ----------------------------------------------------------------------- + +OutputDevice::~OutputDevice() +{ + DBG_DTOR( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( GetUnoGraphicsList() ) + { + UnoWrapperBase* pWrapper = Application::GetUnoWrapper(); + if ( pWrapper ) + pWrapper->ReleaseAllGraphics( this ); + delete mpUnoGraphicsList; + mpUnoGraphicsList = NULL; + } + + if ( mp3DContext ) + mp3DContext->Destroy( this ); + + if ( mpOutDevData ) + ImplDeInitOutDevData(); + + ImplObjStack* pData = mpObjStack; + if ( pData ) + { + DBG_ERRORFILE( "OutputDevice::~OutputDevice(): OutputDevice::Push() calls != OutputDevice::Pop() calls" ); + while ( pData ) + { + ImplObjStack* pTemp = pData; + pData = pData->mpPrev; + ImplDeleteObjStack( pTemp ); + } + } + + if ( mpFontEntry ) + mpFontCache->Release( mpFontEntry ); + if ( mpGetDevFontList ) + delete mpGetDevFontList; + if ( mpGetDevSizeList ) + delete mpGetDevSizeList; +} + +// ----------------------------------------------------------------------- + +#ifndef REMOTE_APPSERVER + +int OutputDevice::ImplGetGraphics() +{ + DBG_TESTSOLARMUTEX(); + + if ( mpGraphics ) + return TRUE; + + mbInitLineColor = TRUE; + mbInitFillColor = TRUE; + mbInitFont = TRUE; + mbInitTextColor = TRUE; + mbInitClipRegion = TRUE; + + ImplSVData* pSVData = ImplGetSVData(); + if ( meOutDevType == OUTDEV_WINDOW ) + { + Window* pWindow = (Window*)this; + + mpGraphics = pWindow->mpFrame->GetGraphics(); + // Wenn wir keinen bekommen haben, versuchen wir uns einen zu klauen + if ( !mpGraphics ) + { + OutputDevice* pReleaseOutDev = pSVData->maGDIData.mpLastWinGraphics; + while ( pReleaseOutDev ) + { + if ( ((Window*)pReleaseOutDev)->mpFrame == pWindow->mpFrame ) + break; + pReleaseOutDev = pReleaseOutDev->mpPrevGraphics; + } + + if ( pReleaseOutDev ) + { + mpGraphics = pReleaseOutDev->mpGraphics; + pReleaseOutDev->ImplReleaseGraphics( FALSE ); + } + else + { + while ( !mpGraphics ) + { + if ( !pSVData->maGDIData.mpLastWinGraphics ) + break; + pSVData->maGDIData.mpLastWinGraphics->ImplReleaseGraphics(); + mpGraphics = pWindow->mpFrame->GetGraphics(); + } + } + } + + if ( mpGraphics ) + { + mpNextGraphics = pSVData->maGDIData.mpFirstWinGraphics; + pSVData->maGDIData.mpFirstWinGraphics = this; + if ( mpNextGraphics ) + mpNextGraphics->mpPrevGraphics = this; + if ( !pSVData->maGDIData.mpLastWinGraphics ) + pSVData->maGDIData.mpLastWinGraphics = this; + } + } + else if ( meOutDevType == OUTDEV_VIRDEV ) + { + VirtualDevice* pVirDev = (VirtualDevice*)this; + + if ( pVirDev->mpVirDev ) + { + mpGraphics = pVirDev->mpVirDev->GetGraphics(); + while ( !mpGraphics ) + { + if ( !pSVData->maGDIData.mpLastVirGraphics ) + break; + pSVData->maGDIData.mpLastVirGraphics->ImplReleaseGraphics(); + mpGraphics = pVirDev->mpVirDev->GetGraphics(); + } + if ( mpGraphics ) + { + mpNextGraphics = pSVData->maGDIData.mpFirstVirGraphics; + pSVData->maGDIData.mpFirstVirGraphics = this; + if ( mpNextGraphics ) + mpNextGraphics->mpPrevGraphics = this; + if ( !pSVData->maGDIData.mpLastVirGraphics ) + pSVData->maGDIData.mpLastVirGraphics = this; + } + } + } + else if ( meOutDevType == OUTDEV_PRINTER ) + { + Printer* pPrinter = (Printer*)this; + + if ( pPrinter->mpJobGraphics ) + mpGraphics = pPrinter->mpJobGraphics; + else if ( pPrinter->mpDisplayDev ) + { + VirtualDevice* pVirDev = pPrinter->mpDisplayDev; + mpGraphics = pVirDev->mpVirDev->GetGraphics(); + while ( !mpGraphics ) + { + if ( !pSVData->maGDIData.mpLastVirGraphics ) + break; + pSVData->maGDIData.mpLastVirGraphics->ImplReleaseGraphics(); + mpGraphics = pVirDev->mpVirDev->GetGraphics(); + } + if ( mpGraphics ) + { + mpNextGraphics = pSVData->maGDIData.mpFirstVirGraphics; + pSVData->maGDIData.mpFirstVirGraphics = this; + if ( mpNextGraphics ) + mpNextGraphics->mpPrevGraphics = this; + if ( !pSVData->maGDIData.mpLastVirGraphics ) + pSVData->maGDIData.mpLastVirGraphics = this; + } + } + else + { + mpGraphics = pPrinter->mpInfoPrinter->GetGraphics(); + while ( !mpGraphics ) + { + if ( !pSVData->maGDIData.mpLastPrnGraphics ) + break; + pSVData->maGDIData.mpLastPrnGraphics->ImplReleaseGraphics(); + mpGraphics = pPrinter->mpInfoPrinter->GetGraphics(); + } + if ( mpGraphics ) + { + mpNextGraphics = pSVData->maGDIData.mpFirstPrnGraphics; + pSVData->maGDIData.mpFirstPrnGraphics = this; + if ( mpNextGraphics ) + mpNextGraphics->mpPrevGraphics = this; + if ( !pSVData->maGDIData.mpLastPrnGraphics ) + pSVData->maGDIData.mpLastPrnGraphics = this; + } + } + } + + if ( mpGraphics ) + { + mpGraphics->SetXORMode( (ROP_INVERT == meRasterOp) || (ROP_XOR == meRasterOp) ); + return TRUE; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplReleaseGraphics( BOOL bRelease ) +{ + DBG_TESTSOLARMUTEX(); + + if ( !mpGraphics ) + return; + + ImplSVData* pSVData = ImplGetSVData(); + if ( meOutDevType == OUTDEV_WINDOW ) + { + Window* pWindow = (Window*)this; + + if ( bRelease ) + pWindow->mpFrame->ReleaseGraphics( mpGraphics ); + if ( mpPrevGraphics ) + mpPrevGraphics->mpNextGraphics = mpNextGraphics; + else + pSVData->maGDIData.mpFirstWinGraphics = mpNextGraphics; + if ( mpNextGraphics ) + mpNextGraphics->mpPrevGraphics = mpPrevGraphics; + else + pSVData->maGDIData.mpLastWinGraphics = mpPrevGraphics; + } + else if ( meOutDevType == OUTDEV_VIRDEV ) + { + VirtualDevice* pVirDev = (VirtualDevice*)this; + + if ( bRelease ) + pVirDev->mpVirDev->ReleaseGraphics( mpGraphics ); + if ( mpPrevGraphics ) + mpPrevGraphics->mpNextGraphics = mpNextGraphics; + else + pSVData->maGDIData.mpFirstVirGraphics = mpNextGraphics; + if ( mpNextGraphics ) + mpNextGraphics->mpPrevGraphics = mpPrevGraphics; + else + pSVData->maGDIData.mpLastVirGraphics = mpPrevGraphics; + } + else if ( meOutDevType == OUTDEV_PRINTER ) + { + Printer* pPrinter = (Printer*)this; + + if ( !pPrinter->mpJobGraphics ) + { + if ( pPrinter->mpDisplayDev ) + { + VirtualDevice* pVirDev = pPrinter->mpDisplayDev; + if ( bRelease ) + pVirDev->mpVirDev->ReleaseGraphics( mpGraphics ); + if ( mpPrevGraphics ) + mpPrevGraphics->mpNextGraphics = mpNextGraphics; + else + pSVData->maGDIData.mpFirstVirGraphics = mpNextGraphics; + if ( mpNextGraphics ) + mpNextGraphics->mpPrevGraphics = mpPrevGraphics; + else + pSVData->maGDIData.mpLastVirGraphics = mpPrevGraphics; + } + else + { + if ( bRelease ) + pPrinter->mpInfoPrinter->ReleaseGraphics( mpGraphics ); + if ( mpPrevGraphics ) + mpPrevGraphics->mpNextGraphics = mpNextGraphics; + else + pSVData->maGDIData.mpFirstPrnGraphics = mpNextGraphics; + if ( mpNextGraphics ) + mpNextGraphics->mpPrevGraphics = mpPrevGraphics; + else + pSVData->maGDIData.mpLastPrnGraphics = mpPrevGraphics; + } + } + } + + mpGraphics = NULL; + mpPrevGraphics = NULL; + mpNextGraphics = NULL; + + if ( mpGetDevFontList ) + { + delete mpGetDevFontList; + mpGetDevFontList = NULL; + } + if ( mpGetDevSizeList ) + { + delete mpGetDevSizeList; + mpGetDevSizeList = NULL; + } +} + +#endif + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplInitOutDevData() +{ + if ( !mpOutDevData ) + { + mpOutDevData = new ImplOutDevData; + mpOutDevData->mpRotateDev = NULL; + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplDeInitOutDevData() +{ + if ( mpOutDevData ) + { + if ( mpOutDevData->mpRotateDev ) + delete mpOutDevData->mpRotateDev; + delete mpOutDevData; + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplInitLineColor() +{ + DBG_TESTSOLARMUTEX(); + +#ifndef REMOTE_APPSERVER + if( mbLineColor ) + { + if( ROP_0 == meRasterOp ) + mpGraphics->SetROPLineColor( SAL_ROP_0 ); + else if( ROP_1 == meRasterOp ) + mpGraphics->SetROPLineColor( SAL_ROP_1 ); + else if( ROP_INVERT == meRasterOp ) + mpGraphics->SetROPLineColor( SAL_ROP_INVERT ); + else + mpGraphics->SetLineColor( ImplColorToSal( maLineColor ) ); + } + else + mpGraphics->SetLineColor(); +#else + mpGraphics->SetLineColor( maLineColor ); +#endif + + mbInitLineColor = FALSE; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplInitFillColor() +{ + DBG_TESTSOLARMUTEX(); + +#ifndef REMOTE_APPSERVER + if( mbFillColor ) + { + if( ROP_0 == meRasterOp ) + mpGraphics->SetROPFillColor( SAL_ROP_0 ); + else if( ROP_1 == meRasterOp ) + mpGraphics->SetROPFillColor( SAL_ROP_1 ); + else if( ROP_INVERT == meRasterOp ) + mpGraphics->SetROPFillColor( SAL_ROP_INVERT ); + else + mpGraphics->SetFillColor( ImplColorToSal( maFillColor ) ); + } + else + mpGraphics->SetFillColor(); +#else + mpGraphics->SetFillColor( maFillColor ); +#endif + + mbInitFillColor = FALSE; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplInitClipRegion() +{ + DBG_TESTSOLARMUTEX(); + + if ( GetOutDevType() == OUTDEV_WINDOW ) + { + Window* pWindow = (Window*)this; + Region aRegion; + // Hintergrund-Sicherung zuruecksetzen + if ( pWindow->mpFrameData->mpFirstBackWin ) + pWindow->ImplInvalidateAllOverlapBackgrounds(); + if ( pWindow->mbInPaint ) + aRegion = *(pWindow->mpPaintRegion); + else + aRegion = *(pWindow->ImplGetWinChildClipRegion()); + if ( mbClipRegion ) + aRegion.Intersect( ImplPixelToDevicePixel( maRegion ) ); + if ( aRegion.IsEmpty() ) + mbOutputClipped = TRUE; + else + { + mbOutputClipped = FALSE; +#ifndef REMOTE_APPSERVER + ImplSelectClipRegion( mpGraphics, aRegion ); +#else + mpGraphics->SetClipRegion( aRegion ); +#endif + } + mbClipRegionSet = TRUE; + } + else + { + if ( mbClipRegion ) + { + if ( maRegion.IsEmpty() ) + mbOutputClipped = TRUE; + else + { + mbOutputClipped = FALSE; +#ifndef REMOTE_APPSERVER + ImplSelectClipRegion( mpGraphics, maRegion ); +#else + mpGraphics->SetClipRegion( maRegion ); +#endif + } + + mbClipRegionSet = TRUE; + } + else + { + if ( mbClipRegionSet ) + { +#ifndef REMOTE_APPSERVER + mpGraphics->ResetClipRegion(); +#else + mpGraphics->SetClipRegion(); +#endif + mbClipRegionSet = FALSE; + } + + mbOutputClipped = FALSE; + } + } + + mbInitClipRegion = FALSE; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplSetClipRegion( const Region* pRegion ) +{ + DBG_TESTSOLARMUTEX(); + + if ( !pRegion ) + { + if ( mbClipRegion ) + { + maRegion = Region( REGION_NULL ); + mbClipRegion = FALSE; + mbInitClipRegion = TRUE; + } + } + else + { + maRegion = *pRegion; + mbClipRegion = TRUE; + mbInitClipRegion = TRUE; + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetClipRegion() +{ + DBG_TRACE( "OutputDevice::SetClipRegion()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaClipRegionAction( Region(), FALSE ) ); + + ImplSetClipRegion( NULL ); +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetClipRegion( const Region& rRegion ) +{ + DBG_TRACE( "OutputDevice::SetClipRegion( rRegion )" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaClipRegionAction( rRegion, TRUE ) ); + + if ( rRegion.GetType() == REGION_NULL ) + ImplSetClipRegion( NULL ); + else + { + Region aRegion = LogicToPixel( rRegion ); + ImplSetClipRegion( &aRegion ); + } +} + +// ----------------------------------------------------------------------- + +Region OutputDevice::GetClipRegion() const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + return PixelToLogic( maRegion ); +} + +// ----------------------------------------------------------------------- + +Region OutputDevice::GetActiveClipRegion() const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( GetOutDevType() == OUTDEV_WINDOW ) + { + Region aRegion( REGION_NULL ); + Window* pWindow = (Window*)this; + if ( pWindow->mbInPaint ) + { + aRegion = *(pWindow->mpPaintRegion); + aRegion.Move( -mnOutOffX, -mnOutOffY ); + } + if ( mbClipRegion ) + aRegion.Intersect( maRegion ); + return PixelToLogic( aRegion ); + } + else + return GetClipRegion(); +} + +// ----------------------------------------------------------------------- + +void OutputDevice::MoveClipRegion( long nHorzMove, long nVertMove ) +{ + DBG_TRACE( "OutputDevice::MoveClipRegion()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mbClipRegion ) + { + if( mpMetaFile ) + mpMetaFile->AddAction( new MetaMoveClipRegionAction( nHorzMove, nVertMove ) ); + + maRegion.Move( ImplLogicWidthToDevicePixel( nHorzMove ), + ImplLogicHeightToDevicePixel( nVertMove ) ); + mbInitClipRegion = TRUE; + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::IntersectClipRegion( const Rectangle& rRect ) +{ + DBG_TRACE( "OutputDevice::IntersectClipRegion( rRect )" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaISectRectClipRegionAction( rRect ) ); + + Rectangle aRect = LogicToPixel( rRect ); + maRegion.Intersect( aRect ); + mbClipRegion = TRUE; + mbInitClipRegion = TRUE; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::IntersectClipRegion( const Region& rRegion ) +{ + DBG_TRACE( "OutputDevice::IntersectClipRegion( rRegion )" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); + + RegionType eType = rRegion.GetType(); + + if ( eType != REGION_NULL ) + { + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaISectRegionClipRegionAction( rRegion ) ); + + Region aRegion = LogicToPixel( rRegion ); + maRegion.Intersect( aRegion ); + mbClipRegion = TRUE; + mbInitClipRegion = TRUE; + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetDrawMode( ULONG nDrawMode ) +{ + DBG_TRACE1( "OutputDevice::SetDrawMode( %lx )", nDrawMode ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + mnDrawMode = nDrawMode; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetRasterOp( RasterOp eRasterOp ) +{ + DBG_TRACE1( "OutputDevice::SetRasterOp( %d )", (int)eRasterOp ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaRasterOpAction( eRasterOp ) ); + + if ( meRasterOp != eRasterOp ) + { + meRasterOp = eRasterOp; + mbInitLineColor = mbInitFillColor = TRUE; + +#ifndef REMOTE_APPSERVER + if( mpGraphics || ImplGetGraphics() ) + mpGraphics->SetXORMode( (ROP_INVERT == meRasterOp) || (ROP_XOR == meRasterOp) ); +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if( pGraphics ) + pGraphics->SetRasterOp( eRasterOp ); +#endif + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetLineColor() +{ + DBG_TRACE( "OutputDevice::SetLineColor()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaLineColorAction( Color(), FALSE ) ); + + if ( mbLineColor ) + { + mbInitLineColor = TRUE; + mbLineColor = FALSE; + maLineColor = Color( COL_TRANSPARENT ); + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetLineColor( const Color& rColor ) +{ + DBG_TRACE1( "OutputDevice::SetLineColor( %lx )", rColor.GetColor() ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + Color aColor( rColor ); + + if( mnDrawMode & ( DRAWMODE_BLACKLINE | DRAWMODE_WHITELINE | + DRAWMODE_GRAYLINE | DRAWMODE_GHOSTEDLINE ) ) + { + if( !ImplIsColorTransparent( aColor ) ) + { + if( mnDrawMode & DRAWMODE_BLACKLINE ) + { + aColor = Color( COL_BLACK ); + } + else if( mnDrawMode & DRAWMODE_WHITELINE ) + { + aColor = Color( COL_WHITE ); + } + else if( mnDrawMode & DRAWMODE_GRAYLINE ) + { + const UINT8 cLum = aColor.GetLuminance(); + aColor = Color( cLum, cLum, cLum ); + } + + if( mnDrawMode & DRAWMODE_GHOSTEDLINE ) + { + aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80, + ( aColor.GetGreen() >> 1 ) | 0x80, + ( aColor.GetBlue() >> 1 ) | 0x80); + } + } + } + + if( mpMetaFile ) + mpMetaFile->AddAction( new MetaLineColorAction( aColor, TRUE ) ); + + if( ImplIsColorTransparent( aColor ) ) + { + if ( mbLineColor ) + { + mbInitLineColor = TRUE; + mbLineColor = FALSE; + maLineColor = Color( COL_TRANSPARENT ); + } + } + else + { + if( maLineColor != aColor ) + { + mbInitLineColor = TRUE; + mbLineColor = TRUE; + maLineColor = aColor; + } + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetFillColor() +{ + DBG_TRACE( "OutputDevice::SetFillColor()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaFillColorAction( Color(), FALSE ) ); + + if ( mbFillColor ) + { + mbInitFillColor = TRUE; + mbFillColor = FALSE; + maFillColor = Color( COL_TRANSPARENT ); + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetFillColor( const Color& rColor ) +{ + DBG_TRACE1( "OutputDevice::SetFillColor( %lx )", rColor.GetColor() ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + Color aColor( rColor ); + + if( mnDrawMode & ( DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL | + DRAWMODE_GRAYFILL | DRAWMODE_NOFILL | + DRAWMODE_GHOSTEDFILL ) ) + { + if( !ImplIsColorTransparent( aColor ) ) + { + if( mnDrawMode & DRAWMODE_BLACKFILL ) + { + aColor = Color( COL_BLACK ); + } + else if( mnDrawMode & DRAWMODE_WHITEFILL ) + { + aColor = Color( COL_WHITE ); + } + else if( mnDrawMode & DRAWMODE_GRAYFILL ) + { + const UINT8 cLum = aColor.GetLuminance(); + aColor = Color( cLum, cLum, cLum ); + } + else if( mnDrawMode & DRAWMODE_NOFILL ) + { + aColor = Color( COL_TRANSPARENT ); + } + + if( mnDrawMode & DRAWMODE_GHOSTEDFILL ) + { + aColor = Color( (aColor.GetRed() >> 1) | 0x80, + (aColor.GetGreen() >> 1) | 0x80, + (aColor.GetBlue() >> 1) | 0x80); + } + } + } + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaFillColorAction( aColor, TRUE ) ); + + if ( ImplIsColorTransparent( aColor ) ) + { + if ( mbFillColor ) + { + mbInitFillColor = TRUE; + mbFillColor = FALSE; + maFillColor = Color( COL_TRANSPARENT ); + } + } + else + { + if ( maFillColor != aColor ) + { + mbInitFillColor = TRUE; + mbFillColor = TRUE; + maFillColor = aColor; + } + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetBackground() +{ + DBG_TRACE( "OutputDevice::SetBackground()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + maBackground = Wallpaper(); + mbBackground = FALSE; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetBackground( const Wallpaper& rBackground ) +{ + DBG_TRACE( "OutputDevice::SetBackground( rBackground )" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + maBackground = rBackground; + + if( rBackground.GetStyle() == WALLPAPER_NULL ) + mbBackground = FALSE; + else + mbBackground = TRUE; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetRefPoint() +{ + DBG_TRACE( "OutputDevice::SetRefPoint()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaRefPointAction( Point(), FALSE ) ); + + mbRefPoint = FALSE; + maRefPoint.X() = maRefPoint.Y() = 0L; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetRefPoint( const Point& rRefPoint ) +{ + DBG_TRACE( "OutputDevice::SetRefPoint( rRefPoint )" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaRefPointAction( rRefPoint, TRUE ) ); + + mbRefPoint = TRUE; + maRefPoint = rRefPoint; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt ) +{ + DBG_TRACE( "OutputDevice::DrawLine()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaLineAction( rStartPt, rEndPt ) ); + + if ( !IsDeviceOutputNecessary() || !mbLineColor ) + return; + +#ifndef REMOTE_APPSERVER + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; + + if ( mbInitLineColor ) + ImplInitLineColor(); + + Point aStartPt = ImplLogicToDevicePixel( rStartPt ); + Point aEndPt = ImplLogicToDevicePixel( rEndPt ); + + mpGraphics->DrawLine( aStartPt.X(), aStartPt.Y(), aEndPt.X(), aEndPt.Y() ); +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + if ( mbInitLineColor ) + ImplInitLineColor(); + pGraphics->DrawLine( ImplLogicToDevicePixel( rStartPt ), + ImplLogicToDevicePixel( rEndPt ) ); + } +#endif +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt, + const LineInfo& rLineInfo ) +{ + DBG_TRACE( "OutputDevice::DrawLine()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( rLineInfo.IsDefault() ) + { + DrawLine( rStartPt, rEndPt ); + return; + } + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaLineAction( rStartPt, rEndPt, rLineInfo ) ); + + if ( !IsDeviceOutputNecessary() || !mbLineColor || ( LINE_NONE == rLineInfo.GetStyle() ) ) + return; + +#ifndef REMOTE_APPSERVER + + if( !mpGraphics && !ImplGetGraphics() ) + return; + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + + if ( mbOutputClipped ) + return; + + const LineInfo aInfo( ImplLogicToDevicePixel( rLineInfo ) ); + + if( ( aInfo.GetWidth() > 1L ) || ( LINE_DASH == aInfo.GetStyle() ) ) + { + Polygon aPoly( 2 ); aPoly[ 0 ] = rStartPt; aPoly[ 1 ] = rEndPt; + GDIMetaFile* pOldMetaFile = mpMetaFile; + ImplLineConverter aLineCvt( ImplLogicToDevicePixel( aPoly ), aInfo, ( mbRefPoint ) ? &maRefPoint : NULL ); + + mpMetaFile = NULL; + + if ( aInfo.GetWidth() > 1 ) + { + const Color aOldLineColor( maLineColor ); + const Color aOldFillColor( maFillColor ); + + SetLineColor(); + ImplInitLineColor(); + SetFillColor( aOldLineColor ); + ImplInitFillColor(); + + for( const Polygon* pPoly = aLineCvt.ImplGetFirst(); pPoly; pPoly = aLineCvt.ImplGetNext() ) + mpGraphics->DrawPolygon( pPoly->GetSize(), (const SalPoint*) pPoly->ImplGetConstPointAry() ); + + SetFillColor( aOldFillColor ); + SetLineColor( aOldLineColor ); + } + else + { + if ( mbInitLineColor ) + ImplInitLineColor(); + + for ( const Polygon* pPoly = aLineCvt.ImplGetFirst(); pPoly; pPoly = aLineCvt.ImplGetNext() ) + mpGraphics->DrawLine( (*pPoly)[ 0 ].X(), (*pPoly)[ 0 ].Y(), (*pPoly)[ 1 ].X(), (*pPoly)[ 1 ].Y() ); + } + mpMetaFile = pOldMetaFile; + } + else + { + const Point aStartPt( ImplLogicToDevicePixel( rStartPt ) ); + const Point aEndPt( ImplLogicToDevicePixel( rEndPt ) ); + + if ( mbInitLineColor ) + ImplInitLineColor(); + + mpGraphics->DrawLine( aStartPt.X(), aStartPt.Y(), aEndPt.X(), aEndPt.Y() ); + } + +#else + + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + const LineInfo aInfo( ImplLogicToDevicePixel( rLineInfo ) ); + + if( ( aInfo.GetWidth() > 1L ) || ( LINE_DASH == aInfo.GetStyle() ) ) + { + Polygon aPoly( 2 ); aPoly[ 0 ] = rStartPt; aPoly[ 1 ] = rEndPt; + GDIMetaFile* pOldMetaFile = mpMetaFile; + ImplLineConverter aLineCvt( ImplLogicToDevicePixel( aPoly ), aInfo, ( mbRefPoint ) ? &maRefPoint : NULL ); + + mpMetaFile = NULL; + + if ( aInfo.GetWidth() > 1 ) + { + const Color aOldLineColor( maLineColor ); + const Color aOldFillColor( maFillColor ); + + SetLineColor(); + ImplInitLineColor(); + SetFillColor( aOldLineColor ); + ImplInitFillColor(); + + for( const Polygon* pPoly = aLineCvt.ImplGetFirst(); pPoly; pPoly = aLineCvt.ImplGetNext() ) + pGraphics->DrawPolygon( *pPoly ); + + SetLineColor( aOldLineColor ); + SetFillColor( aOldFillColor ); + } + else + { + if ( mbInitLineColor ) + ImplInitLineColor(); + + for ( const Polygon* pPoly = aLineCvt.ImplGetFirst(); pPoly; pPoly = aLineCvt.ImplGetNext() ) { + Point xPoint((*pPoly)[ 0 ].X(), (*pPoly)[ 0 ].Y()); + Point yPoint((*pPoly)[ 1 ].X(), (*pPoly)[ 1 ].Y()); + mpGraphics->DrawLine( xPoint, yPoint ); + } + } + mpMetaFile = pOldMetaFile; + } + else + { + if ( mbInitLineColor ) + ImplInitLineColor(); + + pGraphics->DrawLine( ImplLogicToDevicePixel( rStartPt ), ImplLogicToDevicePixel( rEndPt ) ); + } + } + +#endif +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawRect( const Rectangle& rRect ) +{ + DBG_TRACE( "OutputDevice::DrawRect()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaRectAction( rRect ) ); + + if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) ) + return; + + Rectangle aRect( ImplLogicToDevicePixel( rRect ) ); + + if ( aRect.IsEmpty() ) + return; + aRect.Justify(); + +#ifndef REMOTE_APPSERVER + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; + + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); + + mpGraphics->DrawRect( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight() ); +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); + pGraphics->DrawRect( aRect ); + } +#endif +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawPolyLine( const Polygon& rPoly ) +{ + DBG_TRACE( "OutputDevice::DrawPolyLine()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rPoly, Polygon, NULL ); + + if( mpMetaFile ) + mpMetaFile->AddAction( new MetaPolyLineAction( rPoly ) ); + + USHORT nPoints = rPoly.GetSize(); + + if ( !IsDeviceOutputNecessary() || !mbLineColor || (nPoints < 2) ) + return; + +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; + + if ( mbInitLineColor ) + ImplInitLineColor(); + + Polygon aPoly = ImplLogicToDevicePixel( rPoly ); + + const SalPoint* pPtAry = (const SalPoint*)aPoly.ImplGetConstPointAry(); + mpGraphics->DrawPolyLine( nPoints, pPtAry ); +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + if ( mbInitLineColor ) + ImplInitLineColor(); + pGraphics->DrawPolyLine( ImplLogicToDevicePixel( rPoly ) ); + } +#endif +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawPolyLine( const Polygon& rPoly, const LineInfo& rLineInfo ) +{ + DBG_TRACE( "OutputDevice::DrawPolyLine()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rPoly, Polygon, NULL ); + + if ( rLineInfo.IsDefault() ) + { + DrawPolyLine( rPoly ); + return; + } + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaPolyLineAction( rPoly, rLineInfo ) ); + + USHORT nPoints = rPoly.GetSize(); + + if ( !IsDeviceOutputNecessary() || !mbLineColor || ( nPoints < 2 ) || ( LINE_NONE == rLineInfo.GetStyle() ) ) + return; + +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics && !ImplGetGraphics() ) + return; + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + + if ( mbOutputClipped ) + return; + + const LineInfo aInfo( ImplLogicToDevicePixel( rLineInfo ) ); + + if( aInfo.GetWidth() > 1L ) + { + const Color aOldLineColor( maLineColor ); + const Color aOldFillColor( maFillColor ); + GDIMetaFile* pOldMetaFile = mpMetaFile; + ImplLineConverter aLineCvt( ImplLogicToDevicePixel( rPoly ), aInfo, ( mbRefPoint ) ? &maRefPoint : NULL ); + + mpMetaFile = NULL; + SetLineColor(); + ImplInitLineColor(); + SetFillColor( aOldLineColor ); + ImplInitFillColor(); + + for( const Polygon* pPoly = aLineCvt.ImplGetFirst(); pPoly; pPoly = aLineCvt.ImplGetNext() ) + mpGraphics->DrawPolygon( pPoly->GetSize(), (const SalPoint*) pPoly->ImplGetConstPointAry() ); + + SetLineColor( aOldLineColor ); + SetFillColor( aOldFillColor ); + mpMetaFile = pOldMetaFile; + } + else + { + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( LINE_DASH == aInfo.GetStyle() ) + { + ImplLineConverter aLineCvt( ImplLogicToDevicePixel( rPoly ), aInfo, ( mbRefPoint ) ? &maRefPoint : NULL ); + for( const Polygon* pPoly = aLineCvt.ImplGetFirst(); pPoly; pPoly = aLineCvt.ImplGetNext() ) + mpGraphics->DrawPolyLine( pPoly->GetSize(), (const SalPoint*)pPoly->ImplGetConstPointAry() ); + } + else + mpGraphics->DrawPolyLine( nPoints, (const SalPoint*) ImplLogicToDevicePixel( rPoly ).ImplGetConstPointAry() ); + } +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + + if ( pGraphics ) + { + const LineInfo aInfo( ImplLogicToDevicePixel( rLineInfo ) ); + + if( aInfo.GetWidth() > 1L ) + { + const Color aOldLineColor( maLineColor ); + const Color aOldFillColor( maFillColor ); + GDIMetaFile* pOldMetaFile = mpMetaFile; + ImplLineConverter aLineCvt( ImplLogicToDevicePixel( rPoly ), aInfo, ( mbRefPoint ) ? &maRefPoint : NULL ); + + mpMetaFile = NULL; + SetLineColor(); + ImplInitLineColor(); + SetFillColor( aOldLineColor ); + ImplInitFillColor(); + + for( const Polygon* pPoly = aLineCvt.ImplGetFirst(); pPoly; pPoly = aLineCvt.ImplGetNext() ) + pGraphics->DrawPolygon( *pPoly ); + + SetLineColor( aOldLineColor ); + SetFillColor( aOldFillColor ); + mpMetaFile = pOldMetaFile; + } + else + { + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( LINE_DASH == aInfo.GetStyle() ) + { + ImplLineConverter aLineCvt( ImplLogicToDevicePixel( rPoly ), aInfo, ( mbRefPoint ) ? &maRefPoint : NULL ); + for( const Polygon* pPoly = aLineCvt.ImplGetFirst(); pPoly; pPoly = aLineCvt.ImplGetNext() ) + pGraphics->DrawPolyLine( *pPoly ); + } + else + pGraphics->DrawPolyLine( ImplLogicToDevicePixel( rPoly ) ); + } + } +#endif +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawPolygon( const Polygon& rPoly ) +{ + DBG_TRACE( "OutputDevice::DrawPolygon()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rPoly, Polygon, NULL ); + + if( mpMetaFile ) + mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) ); + + USHORT nPoints = rPoly.GetSize(); + + if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || (nPoints < 2) ) + return; + +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; + + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); + + Polygon aPoly = ImplLogicToDevicePixel( rPoly ); + + const SalPoint* pPtAry = (const SalPoint*)aPoly.ImplGetConstPointAry(); + mpGraphics->DrawPolygon( nPoints, pPtAry ); +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); + pGraphics->DrawPolygon( ImplLogicToDevicePixel( rPoly ) ); + } +#endif +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawPolyPolygon( const PolyPolygon& rPolyPoly ) +{ + DBG_TRACE( "OutputDevice::DrawPolyPolygon()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL ); + + if( mpMetaFile ) + mpMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPoly ) ); + + USHORT nPoly = rPolyPoly.Count(); + + if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || !nPoly ) + return; + +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; + + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); + + if ( nPoly == 1 ) + { + Polygon aPoly = ImplLogicToDevicePixel( rPolyPoly.GetObject( 0 ) ); + USHORT nSize = aPoly.GetSize(); + if ( nSize >= 2 ) + { + const SalPoint* pPtAry = (const SalPoint*)aPoly.ImplGetConstPointAry(); + mpGraphics->DrawPolygon( nSize, pPtAry ); + } + } + else + { + PolyPolygon aPolyPoly = ImplLogicToDevicePixel( rPolyPoly ); + ULONG aStackAry1[OUTDEV_POLYPOLY_STACKBUF]; + PCONSTSALPOINT aStackAry2[OUTDEV_POLYPOLY_STACKBUF]; + ULONG* pPointAry; + PCONSTSALPOINT* pPointAryAry; + USHORT i = 0; + if ( nPoly > OUTDEV_POLYPOLY_STACKBUF ) + { + pPointAry = new ULONG[nPoly]; + pPointAryAry = new PCONSTSALPOINT[nPoly]; + } + else + { + pPointAry = aStackAry1; + pPointAryAry = aStackAry2; + } + do + { + const Polygon& rPoly = aPolyPoly.GetObject( i ); + USHORT nSize = rPoly.GetSize(); + if ( nSize ) + { + pPointAry[i] = nSize; + pPointAryAry[i] = (PCONSTSALPOINT)rPoly.ImplGetConstPointAry(); + i++; + } + else + nPoly--; + } + while ( i < nPoly ); + + if ( nPoly == 1 ) + mpGraphics->DrawPolygon( *pPointAry, *pPointAryAry ); + else + mpGraphics->DrawPolyPolygon( nPoly, pPointAry, pPointAryAry ); + + if ( pPointAry != aStackAry1 ) + { + delete pPointAry; + delete pPointAryAry; + } + } +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); + if ( nPoly == 1 ) + { + Polygon aPoly = ImplLogicToDevicePixel( rPolyPoly.GetObject( 0 ) ); + USHORT nSize = aPoly.GetSize(); + if ( nSize >= 2 ) + pGraphics->DrawPolygon( aPoly ); + } + else + pGraphics->DrawPolyPolygon( ImplLogicToDevicePixel( rPolyPoly ) ); + } +#endif +} + +// ----------------------------------------------------------------------- + +void OutputDevice::Push( USHORT nFlags ) +{ + DBG_TRACE( "OutputDevice::Push()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaPushAction( nFlags ) ); + + ImplObjStack* pData = new ImplObjStack; + pData->mpPrev = mpObjStack; + mpObjStack = pData; + + pData->mnFlags = nFlags; + + if ( nFlags & PUSH_LINECOLOR ) + { + if ( mbLineColor ) + pData->mpLineColor = new Color( maLineColor ); + else + pData->mpLineColor = NULL; + } + if ( nFlags & PUSH_FILLCOLOR ) + { + if ( mbFillColor ) + pData->mpFillColor = new Color( maFillColor ); + else + pData->mpFillColor = NULL; + } + if ( nFlags & PUSH_FONT ) + pData->mpFont = new Font( maFont ); + if ( nFlags & PUSH_TEXTCOLOR ) + pData->mpTextColor = new Color( GetTextColor() ); + if ( nFlags & PUSH_TEXTFILLCOLOR ) + { + if ( IsTextFillColor() ) + pData->mpTextFillColor = new Color( GetTextFillColor() ); + else + pData->mpTextFillColor = NULL; + } + if ( nFlags & PUSH_TEXTLINECOLOR ) + { + if ( IsTextLineColor() ) + pData->mpTextLineColor = new Color( GetTextLineColor() ); + else + pData->mpTextLineColor = NULL; + } + if ( nFlags & PUSH_TEXTALIGN ) + pData->meTextAlign = GetTextAlign(); + if ( nFlags & PUSH_RASTEROP ) + pData->meRasterOp = GetRasterOp(); + if ( nFlags & PUSH_MAPMODE ) + { + if ( mbMap ) + pData->mpMapMode = new MapMode( maMapMode ); + else + pData->mpMapMode = NULL; + } + if ( nFlags & PUSH_CLIPREGION ) + { + if ( mbClipRegion ) + pData->mpClipRegion = new Region( maRegion ); + else + pData->mpClipRegion = NULL; + } + if ( nFlags & PUSH_REFPOINT ) + { + if ( mbRefPoint ) + pData->mpRefPoint = new Point( maRefPoint ); + else + pData->mpRefPoint = NULL; + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::Pop() +{ + DBG_TRACE( "OutputDevice::Pop()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if( mpMetaFile ) + mpMetaFile->AddAction( new MetaPopAction() ); + + GDIMetaFile* pOldMetaFile = mpMetaFile; + ImplObjStack* pData = mpObjStack; + mpMetaFile = NULL; + + if ( !pData ) + { + DBG_ERRORFILE( "OutputDevice::Pop() without OutputDevice::Push()" ); + return; + } + + mpObjStack = pData->mpPrev; + + if ( pData->mnFlags & PUSH_LINECOLOR ) + { + if ( pData->mpLineColor ) + SetLineColor( *pData->mpLineColor ); + else + SetLineColor(); + } + if ( pData->mnFlags & PUSH_FILLCOLOR ) + { + if ( pData->mpFillColor ) + SetFillColor( *pData->mpFillColor ); + else + SetFillColor(); + } + if ( pData->mnFlags & PUSH_FONT ) + SetFont( *pData->mpFont ); + if ( pData->mnFlags & PUSH_TEXTCOLOR ) + SetTextColor( *pData->mpTextColor ); + if ( pData->mnFlags & PUSH_TEXTFILLCOLOR ) + { + if ( pData->mpTextFillColor ) + SetTextFillColor( *pData->mpTextFillColor ); + else + SetTextFillColor(); + } + if ( pData->mnFlags & PUSH_TEXTLINECOLOR ) + { + if ( pData->mpTextLineColor ) + SetTextLineColor( *pData->mpTextLineColor ); + else + SetTextLineColor(); + } + if ( pData->mnFlags & PUSH_TEXTALIGN ) + SetTextAlign( pData->meTextAlign ); + if ( pData->mnFlags & PUSH_RASTEROP ) + SetRasterOp( pData->meRasterOp ); + if ( pData->mnFlags & PUSH_MAPMODE ) + { + if ( pData->mpMapMode ) + SetMapMode( *pData->mpMapMode ); + else + SetMapMode(); + } + if ( pData->mnFlags & PUSH_CLIPREGION ) + ImplSetClipRegion( pData->mpClipRegion ); + if ( pData->mnFlags & PUSH_REFPOINT ) + { + if ( pData->mpRefPoint ) + SetRefPoint( *pData->mpRefPoint ); + else + SetRefPoint(); + } + + ImplDeleteObjStack( pData ); + + mpMetaFile = pOldMetaFile; +} + +// ----------------------------------------------------------------------- + +USHORT OutputDevice::GetBitCount() const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( meOutDevType == OUTDEV_VIRDEV ) + return ((VirtualDevice*)this)->mnBitCount; + +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !((OutputDevice*)this)->ImplGetGraphics() ) + return 0; + } +#endif + + return (USHORT)mpGraphics->GetBitCount(); +} + +// ----------------------------------------------------------------------- + +ULONG OutputDevice::GetColorCount() const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + const USHORT nBitCount = GetBitCount(); + return( ( nBitCount > 31 ) ? ULONG_MAX : ( ( (ULONG) 1 ) << nBitCount) ); +} + +// ----------------------------------------------------------------------- + +OpenGL* OutputDevice::GetOpenGL() +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + +#ifndef REMOTE_APPSERVER + OpenGL* pOGL; + + if( OUTDEV_PRINTER != meOutDevType ) + { + pOGL = new OpenGL( this ); + + if( !pOGL->IsValid() ) + { + delete pOGL; + pOGL = NULL; + } + } + else + pOGL = NULL; + + return pOGL; +#else + return NULL; +#endif +} + +// ----------------------------------------------------------------------- + +::com::sun::star::uno::Reference< ::com::sun::star::awt::XGraphics > OutputDevice::CreateUnoGraphics() +{ + UnoWrapperBase* pWrapper = Application::GetUnoWrapper(); + return pWrapper ? pWrapper->CreateGraphics( this ) : ::com::sun::star::uno::Reference< ::com::sun::star::awt::XGraphics >(); +} diff --git a/vcl/source/gdi/outdev2.cxx b/vcl/source/gdi/outdev2.cxx new file mode 100644 index 000000000000..b454fe3632ff --- /dev/null +++ b/vcl/source/gdi/outdev2.cxx @@ -0,0 +1,1928 @@ +/************************************************************************* + * + * $RCSfile: outdev2.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_OUTDEV2_CXX + +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#ifndef _SV_SALBMP_HXX +#include <salbmp.hxx> +#endif +#ifndef _SV_SALGDI_HXX +#include <salgdi.hxx> +#endif +#ifndef _SV_IMPBMP_HXX +#include <impbmp.hxx> +#endif +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _SV_BITMAP_HXX +#include <bitmap.hxx> +#endif +#ifndef _SV_BITMAPEX_HXX +#include <bitmapex.hxx> +#endif +#ifndef _SV_WINDOW_HXX +#include <window.hxx> +#endif +#ifndef _SV_METAACT_HXX +#include <metaact.hxx> +#endif +#ifndef _SV_GDIMTF_HXX +#include <gdimtf.hxx> +#endif +#ifndef _SV_VIRDEV_HXX +#include <virdev.hxx> +#endif +#ifndef _SV_OUTDATA_HXX +#include <outdata.hxx> +#endif +#ifndef _SV_OUTDEV_H +#include <outdev.h> +#endif +#ifndef _SV_BMPACC_HXX +#include <bmpacc.hxx> +#endif +#ifndef _SV_REGION_H +#include <region.h> +#endif +#ifndef _SV_OUTDEV_HXX +#include <outdev.hxx> +#endif +#ifndef _SV_WINDOW_HXX +#include <window.hxx> +#endif +#ifdef REMOTE_APPSERVER +#include <rmoutdev.hxx> +#endif + +#define BAND_MAX_SIZE 512000 + +// ======================================================================= + +DBG_NAMEEX( OutputDevice ); + +// ======================================================================= + +// ----------- +// - Defines - +// ----------- + +#ifndef REMOTE_APPSERVER + +#define OUTDEV_INIT() \ +{ \ + if ( !IsDeviceOutputNecessary() ) \ + return; \ + \ + if ( !mpGraphics ) \ + if ( !ImplGetGraphics() ) \ + return; \ + \ + if ( mbInitClipRegion ) \ + ImplInitClipRegion(); \ + \ + if ( mbOutputClipped ) \ + return; \ +} + +#else // !REMOTE_APPSERVER + +#define OUTDEV_INIT() \ +{ \ + if ( !IsDeviceOutputNecessary() ) \ + return; \ + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); \ + if ( !pGraphics ) \ + return; \ +} + +#endif // REMOTE_APPSERVER + +#ifndef REMOTE_APPSERVER +#define TwoRect SalTwoRect +#else +#define TwoRect RemoteTwoRect +#endif + +// ------------- +// - externals - +// ------------- + +extern ULONG nVCLRLut[ 6 ]; +extern ULONG nVCLGLut[ 6 ]; +extern ULONG nVCLBLut[ 6 ]; +extern ULONG nVCLDitherLut[ 256 ]; +extern ULONG nVCLLut[ 256 ]; + +// ======================================================================= + +ULONG ImplAdjustTwoRect( TwoRect& rTwoRect, const Size& rSizePix ) +{ + ULONG nMirrFlags = 0; + + if ( rTwoRect.mnDestWidth < 0 ) + { + rTwoRect.mnSrcX = rSizePix.Width() - rTwoRect.mnSrcX - rTwoRect.mnSrcWidth; + rTwoRect.mnDestWidth = -rTwoRect.mnDestWidth; + rTwoRect.mnDestX -= rTwoRect.mnDestWidth-1; + nMirrFlags |= BMP_MIRROR_HORZ; + } + + if ( rTwoRect.mnDestHeight < 0 ) + { + rTwoRect.mnSrcY = rSizePix.Height() - rTwoRect.mnSrcY - rTwoRect.mnSrcHeight; + rTwoRect.mnDestHeight = -rTwoRect.mnDestHeight; + rTwoRect.mnDestY -= rTwoRect.mnDestHeight-1; + nMirrFlags |= BMP_MIRROR_VERT; + } + + return nMirrFlags; +} + +// ======================================================================= + +void OutputDevice::ImplDrawOutDevDirect( const OutputDevice* pSrcDev, void* pVoidPosAry ) +{ + TwoRect* pPosAry = (TwoRect*)pVoidPosAry; +#ifndef REMOTE_APPSERVER + SalGraphics* pGraphics2; +#else + ImplServerGraphics* pGraphics2; +#endif + + if ( pPosAry->mnSrcWidth && pPosAry->mnSrcHeight && pPosAry->mnDestWidth && pPosAry->mnDestHeight ) + { + if ( this == pSrcDev ) + pGraphics2 = NULL; + else + { + if ( (GetOutDevType() != pSrcDev->GetOutDevType()) || + (GetOutDevType() != OUTDEV_WINDOW) ) + { +#ifndef REMOTE_APPSERVER + if ( !pSrcDev->mpGraphics ) + { + if ( !((OutputDevice*)pSrcDev)->ImplGetGraphics() ) + return; + } +#endif + pGraphics2 = pSrcDev->mpGraphics; + } + else + { + if ( ((Window*)this)->mpFrameWindow == ((Window*)pSrcDev)->mpFrameWindow ) + pGraphics2 = NULL; + else + { +#ifndef REMOTE_APPSERVER + if ( !pSrcDev->mpGraphics ) + { + if ( !((OutputDevice*)pSrcDev)->ImplGetGraphics() ) + return; + } +#endif + pGraphics2 = pSrcDev->mpGraphics; + +#ifndef REMOTE_APPSERVER + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + DBG_ASSERT( mpGraphics && pSrcDev->mpGraphics, + "OutputDevice::DrawOutDev(): We need more than one Graphics" ); +#endif + } + } + } + + Rectangle aSrcOutRect( Point( pSrcDev->mnOutOffX, pSrcDev->mnOutOffY ), + Size( pSrcDev->mnOutWidth, pSrcDev->mnOutHeight ) ); + Rectangle aSrcRect( Point( pPosAry->mnSrcX, pPosAry->mnSrcY ), + Size( pPosAry->mnSrcWidth, pPosAry->mnSrcHeight ) ); + const long nOldRight = aSrcRect.Right(); + const long nOldBottom = aSrcRect.Bottom(); + + if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() ) + { + if ( (pPosAry->mnSrcX+pPosAry->mnSrcWidth-1) > aSrcOutRect.Right() ) + { + const long nOldWidth = pPosAry->mnSrcWidth; + pPosAry->mnSrcWidth -= (nOldRight - aSrcRect.Right()); + pPosAry->mnDestWidth = pPosAry->mnDestWidth * pPosAry->mnSrcWidth / nOldWidth; + } + + if ( (pPosAry->mnSrcY+pPosAry->mnSrcHeight-1) > aSrcOutRect.Bottom() ) + { + const long nOldHeight = pPosAry->mnSrcHeight; + pPosAry->mnSrcHeight -= (nOldBottom - aSrcRect.Bottom()); + pPosAry->mnDestHeight = pPosAry->mnDestHeight * pPosAry->mnSrcHeight / nOldHeight; + } + + mpGraphics->CopyBits( pPosAry, pGraphics2 ); + } + } +} + +// ------------------------------------------------------------------ + +void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize, + const Point& rSrcPt, const Size& rSrcSize ) +{ + DBG_TRACE( "OutputDevice::DrawOutDev()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" ); + + if ( meOutDevType == OUTDEV_PRINTER ) + return; + + if ( ROP_INVERT == meRasterOp ) + { + DrawRect( Rectangle( rDestPt, rDestSize ) ); + return; + } + + if ( mpMetaFile ) + { + const Bitmap aBmp( GetBitmap( rSrcPt, rSrcSize ) ); + mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) ); + } + + OUTDEV_INIT(); + + TwoRect aPosAry; + aPosAry.mnSrcWidth = ImplLogicWidthToDevicePixel( rSrcSize.Width() ); + aPosAry.mnSrcHeight = ImplLogicHeightToDevicePixel( rSrcSize.Height() ); + aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() ); + aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() ); + + if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight ) + { + aPosAry.mnSrcX = ImplLogicXToDevicePixel( rSrcPt.X() ); + aPosAry.mnSrcY = ImplLogicYToDevicePixel( rSrcPt.Y() ); + aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() ); + aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() ); + + Rectangle aSrcOutRect( Point( mnOutOffX, mnOutOffY ), + Size( mnOutWidth, mnOutHeight ) ); + Rectangle aSrcRect( Point( aPosAry.mnSrcX, aPosAry.mnSrcY ), + Size( aPosAry.mnSrcWidth, aPosAry.mnSrcHeight ) ); + long nOldRight = aSrcRect.Right(); + long nOldBottom = aSrcRect.Bottom(); + + if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() ) + { + if ( (aPosAry.mnSrcX+aPosAry.mnSrcWidth-1) > aSrcOutRect.Right() ) + { + long nOldWidth = aPosAry.mnSrcWidth; + aPosAry.mnSrcWidth -= nOldRight-aSrcRect.Right(); + aPosAry.mnDestWidth = aPosAry.mnDestWidth*aPosAry.mnSrcWidth/nOldWidth; + } + + if ( (aPosAry.mnSrcY+aPosAry.mnSrcHeight-1) > aSrcOutRect.Bottom() ) + { + long nOldHeight = aPosAry.mnSrcHeight; + aPosAry.mnSrcHeight -= nOldBottom-aSrcRect.Bottom(); + aPosAry.mnDestHeight = aPosAry.mnDestHeight*aPosAry.mnSrcHeight/nOldHeight; + } + + mpGraphics->CopyBits( &aPosAry, NULL ); + } + } +} + +// ------------------------------------------------------------------ + +void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize, + const Point& rSrcPt, const Size& rSrcSize, + const OutputDevice& rOutDev ) +{ + DBG_TRACE( "OutputDevice::DrawOutDev()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rOutDev, OutputDevice, ImplDbgCheckOutputDevice ); + DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" ); + DBG_ASSERT( rOutDev.meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" ); + + if ( (meOutDevType == OUTDEV_PRINTER) || (rOutDev.meOutDevType == OUTDEV_PRINTER) ) + return; + + if ( ROP_INVERT == meRasterOp ) + { + DrawRect( Rectangle( rDestPt, rDestSize ) ); + return; + } + + if ( mpMetaFile ) + { + const Bitmap aBmp( rOutDev.GetBitmap( rSrcPt, rSrcSize ) ); + mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) ); + } + + OUTDEV_INIT(); + + TwoRect aPosAry; + aPosAry.mnSrcX = rOutDev.ImplLogicXToDevicePixel( rSrcPt.X() ); + aPosAry.mnSrcY = rOutDev.ImplLogicYToDevicePixel( rSrcPt.Y() ); + aPosAry.mnSrcWidth = rOutDev.ImplLogicWidthToDevicePixel( rSrcSize.Width() ); + aPosAry.mnSrcHeight = rOutDev.ImplLogicHeightToDevicePixel( rSrcSize.Height() ); + aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() ); + aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() ); + aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() ); + aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() ); + + ImplDrawOutDevDirect( &rOutDev, &aPosAry ); +} + +// ------------------------------------------------------------------ + +void OutputDevice::CopyArea( const Point& rDestPt, + const Point& rSrcPt, const Size& rSrcSize, + USHORT nFlags ) +{ + DBG_TRACE( "OutputDevice::CopyArea()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::CopyArea(...) with printer devices!" ); + + if ( meOutDevType == OUTDEV_PRINTER ) + return; + + RasterOp eOldRop = GetRasterOp(); + SetRasterOp( ROP_OVERPAINT ); + + OUTDEV_INIT(); + + TwoRect aPosAry; + aPosAry.mnSrcWidth = ImplLogicWidthToDevicePixel( rSrcSize.Width() ); + aPosAry.mnSrcHeight = ImplLogicHeightToDevicePixel( rSrcSize.Height() ); + + if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight ) + { + aPosAry.mnSrcX = ImplLogicXToDevicePixel( rSrcPt.X() ); + aPosAry.mnSrcY = ImplLogicYToDevicePixel( rSrcPt.Y() ); + aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() ); + aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() ); + + Rectangle aSrcOutRect( Point( mnOutOffX, mnOutOffY ), + Size( mnOutWidth, mnOutHeight ) ); + Rectangle aSrcRect( Point( aPosAry.mnSrcX, aPosAry.mnSrcY ), + Size( aPosAry.mnSrcWidth, aPosAry.mnSrcHeight ) ); + long nOldRight = aSrcRect.Right(); + long nOldBottom = aSrcRect.Bottom(); + + if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() ) + { + if ( (aPosAry.mnSrcX+aPosAry.mnSrcWidth-1) > aSrcOutRect.Right() ) + aPosAry.mnSrcWidth -= nOldRight-aSrcRect.Right(); + + if ( (aPosAry.mnSrcY+aPosAry.mnSrcHeight-1) > aSrcOutRect.Bottom() ) + aPosAry.mnSrcHeight -= nOldBottom-aSrcRect.Bottom(); + + if ( (meOutDevType == OUTDEV_WINDOW) && (nFlags & COPYAREA_WINDOWINVALIDATE) ) + { + ((Window*)this)->ImplMoveAllInvalidateRegions( aSrcRect, + aPosAry.mnDestX-aPosAry.mnSrcX, + aPosAry.mnDestY-aPosAry.mnSrcY, + FALSE ); + +#ifndef REMOTE_APPSERVER + mpGraphics->CopyArea( aPosAry.mnDestX, aPosAry.mnDestY, + aPosAry.mnSrcX, aPosAry.mnSrcY, + aPosAry.mnSrcWidth, aPosAry.mnSrcHeight, + SAL_COPYAREA_WINDOWINVALIDATE ); +#else + mpGraphics->CopyArea( aPosAry.mnDestX, aPosAry.mnDestY, + aPosAry.mnSrcX, aPosAry.mnSrcY, + aPosAry.mnSrcWidth, aPosAry.mnSrcHeight, + COPYAREA_WINDOWINVALIDATE ); +#endif + } + else + { + aPosAry.mnDestWidth = aPosAry.mnSrcWidth; + aPosAry.mnDestHeight = aPosAry.mnSrcHeight; + mpGraphics->CopyBits( &aPosAry, NULL ); + } + } + } + + SetRasterOp( eOldRop ); +} + +// ------------------------------------------------------------------ + +void OutputDevice::ImplDrawFrameDev( const Point& rPt, const Point& rDevPt, const Size& rDevSize, + const OutputDevice& rOutDev, const Region& rRegion ) +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + GDIMetaFile* pOldMetaFile = mpMetaFile; + BOOL bOldMap = mbMap; + RasterOp eOldROP = GetRasterOp(); + mpMetaFile = NULL; + mbMap = FALSE; + SetRasterOp( ROP_OVERPAINT ); + +#ifndef REMOTE_APPSERVER + if ( !IsDeviceOutputNecessary() ) + return; + + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } +#else + if ( !IsDeviceOutputNecessary() ) + return; + +#endif + + // ClipRegion zuruecksetzen +#ifndef REMOTE_APPSERVER + if ( rRegion.IsNull() ) + mpGraphics->ResetClipRegion(); + else + ImplSelectClipRegion( mpGraphics, rRegion ); +#else + if ( rRegion.IsNull() ) + mpGraphics->SetClipRegion(); + else + mpGraphics->SetClipRegion( rRegion ); +#endif + + TwoRect aPosAry; + aPosAry.mnSrcX = rDevPt.X(); + aPosAry.mnSrcY = rDevPt.Y(); + aPosAry.mnSrcWidth = rDevSize.Width(); + aPosAry.mnSrcHeight = rDevSize.Height(); + aPosAry.mnDestX = rPt.X(); + aPosAry.mnDestY = rPt.Y(); + aPosAry.mnDestWidth = rDevSize.Width(); + aPosAry.mnDestHeight = rDevSize.Height(); + ImplDrawOutDevDirect( &rOutDev, &aPosAry ); + + // Dafuer sorgen, das ClipRegion neu berechnet und gesetzt wird + mbInitClipRegion = TRUE; + + SetRasterOp( eOldROP ); + mbMap = bOldMap; + mpMetaFile = pOldMetaFile; +} + +// ------------------------------------------------------------------ + +void OutputDevice::ImplGetFrameDev( const Point& rPt, const Point& rDevPt, const Size& rDevSize, + OutputDevice& rDev ) +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + BOOL bOldMap = mbMap; + mbMap = FALSE; + rDev.DrawOutDev( rDevPt, rDevSize, rPt, rDevSize, *this ); + mbMap = bOldMap; +} + +// ------------------------------------------------------------------ + +void OutputDevice::DrawBitmap( const Point& rDestPt, const Bitmap& rBitmap ) +{ + DBG_TRACE( "OutputDevice::DrawBitmap()" ); + const Size aSizePix( rBitmap.GetSizePixel() ); + ImplDrawBitmap( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, META_BMP_ACTION ); +} + +// ------------------------------------------------------------------ + +void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize, const Bitmap& rBitmap ) +{ + DBG_TRACE( "OutputDevice::DrawBitmap( Size )" ); + ImplDrawBitmap( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, META_BMPSCALE_ACTION ); +} + +// ------------------------------------------------------------------ + +void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize, + const Point& rSrcPtPixel, const Size& rSrcSizePixel, + const Bitmap& rBitmap ) +{ + DBG_TRACE( "OutputDevice::DrawBitmap( Point, Size )" ); + ImplDrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmap, META_BMPSCALEPART_ACTION ); +} + +// ----------------------------------------------------------------------------- + +void OutputDevice::ImplDrawBitmap( const Point& rDestPt, const Size& rDestSize, + const Point& rSrcPtPixel, const Size& rSrcSizePixel, + const Bitmap& rBitmap, const ULONG nAction ) +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + Bitmap aBmp( rBitmap ); + + if ( ( mnDrawMode & DRAWMODE_NOBITMAP ) ) + return; + else if ( ROP_INVERT == meRasterOp ) + { + DrawRect( Rectangle( rDestPt, rDestSize ) ); + return; + } + else if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP | + DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) ) + { + if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) ) + { + BYTE cCmpVal; + + if ( mnDrawMode & DRAWMODE_BLACKBITMAP ) + cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0; + else + cCmpVal = 255; + + Color aCol( cCmpVal, cCmpVal, cCmpVal ); + Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); + SetLineColor( aCol ); + SetFillColor( aCol ); + DrawRect( Rectangle( rDestPt, rDestSize ) ); + Pop(); + return; + } + else if( !!aBmp ) + { + if ( mnDrawMode & DRAWMODE_GRAYBITMAP ) + aBmp.Convert( BMP_CONVERSION_8BIT_GREYS ); + + if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) + aBmp.Convert( BMP_CONVERSION_GHOSTED ); + } + } + + if ( mpMetaFile ) + { + switch( nAction ) + { + case( META_BMP_ACTION ): + mpMetaFile->AddAction( new MetaBmpAction( rDestPt, aBmp ) ); + break; + + case( META_BMPSCALE_ACTION ): + mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) ); + break; + + case( META_BMPSCALEPART_ACTION ): + mpMetaFile->AddAction( new MetaBmpScalePartAction( + rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp ) ); + break; + } + } + + OUTDEV_INIT(); + + if( ( OUTDEV_PRINTER == meOutDevType ) && mbClipRegion && ( REGION_COMPLEX == maRegion.GetType() ) ) + { + Bitmap aMask; + ImplPrintTransparent( aBmp, aMask, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel ); + return; + } + + if ( !( !aBmp ) ) + { + TwoRect aPosAry; + + aPosAry.mnSrcX = rSrcPtPixel.X(); + aPosAry.mnSrcY = rSrcPtPixel.Y(); + aPosAry.mnSrcWidth = rSrcSizePixel.Width(); + aPosAry.mnSrcHeight = rSrcSizePixel.Height(); + aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() ); + aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() ); + aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() ); + aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() ); + + const ULONG nMirrFlags = ImplAdjustTwoRect( aPosAry, aBmp.GetSizePixel() ); + + if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight ) + { + if ( nMirrFlags ) + aBmp.Mirror( nMirrFlags ); + +#ifndef REMOTE_APPSERVER + mpGraphics->DrawBitmap( &aPosAry, *aBmp.ImplGetImpBitmap()->ImplGetSalBitmap() ); +#else + aBmp.ImplDrawRemote( this, + Point( aPosAry.mnSrcX, aPosAry.mnSrcY ), + Size( aPosAry.mnSrcWidth, aPosAry.mnSrcHeight ), + Point( aPosAry.mnDestX, aPosAry.mnDestY ), + Size( aPosAry.mnDestWidth, aPosAry.mnDestHeight ) ); +#endif + } + } +} + +// ------------------------------------------------------------------ + +void OutputDevice::DrawBitmapEx( const Point& rDestPt, + const BitmapEx& rBitmapEx ) +{ + DBG_TRACE( "OutputDevice::DrawBitmapEx()" ); + + if( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() ) + DrawBitmap( rDestPt, rBitmapEx.GetBitmap() ); + else + { + const Size aSizePix( rBitmapEx.GetSizePixel() ); + ImplDrawBitmapEx( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmapEx, META_BMPEX_ACTION ); + } +} + +// ------------------------------------------------------------------ + +void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize, + const BitmapEx& rBitmapEx ) +{ + DBG_TRACE( "OutputDevice::DrawBitmapEx( Size )" ); + + if ( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() ) + DrawBitmap( rDestPt, rDestSize, rBitmapEx.GetBitmap() ); + else + ImplDrawBitmapEx( rDestPt, rDestSize, Point(), rBitmapEx.GetSizePixel(), rBitmapEx, META_BMPEXSCALE_ACTION ); +} + +// ------------------------------------------------------------------ + +void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize, + const Point& rSrcPtPixel, const Size& rSrcSizePixel, + const BitmapEx& rBitmapEx ) +{ + DBG_TRACE( "OutputDevice::DrawBitmapEx( Point, Size )" ); + + if( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() ) + DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmapEx.GetBitmap() ); + else + ImplDrawBitmapEx( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmapEx, META_BMPEXSCALEPART_ACTION ); +} + +// ------------------------------------------------------------------ + +void OutputDevice::ImplDrawBitmapEx( const Point& rDestPt, const Size& rDestSize, + const Point& rSrcPtPixel, const Size& rSrcSizePixel, + const BitmapEx& rBitmapEx, const ULONG nAction ) +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + BitmapEx aBmpEx( rBitmapEx ); + + if ( mnDrawMode & DRAWMODE_NOBITMAP ) + return; + else if ( ROP_INVERT == meRasterOp ) + { + DrawRect( Rectangle( rDestPt, rDestSize ) ); + return; + } + else if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP | + DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) ) + { + if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) ) + { + Bitmap aColorBmp( aBmpEx.GetSizePixel(), ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 4 : 1 ); + BYTE cCmpVal; + + if ( mnDrawMode & DRAWMODE_BLACKBITMAP ) + cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0; + else + cCmpVal = 255; + + aColorBmp.Erase( Color( cCmpVal, cCmpVal, cCmpVal ) ); + + if( aBmpEx.IsAlpha() ) + aBmpEx = BitmapEx( aColorBmp, aBmpEx.GetAlpha() ); + else + aBmpEx = BitmapEx( aColorBmp, aBmpEx.GetMask() ); + } + else if( !!aBmpEx ) + { + if ( mnDrawMode & DRAWMODE_GRAYBITMAP ) + aBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS ); + + if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) + aBmpEx.Convert( BMP_CONVERSION_GHOSTED ); + } + } + + if ( mpMetaFile ) + { + switch( nAction ) + { + case( META_BMPEX_ACTION ): + mpMetaFile->AddAction( new MetaBmpExAction( rDestPt, aBmpEx ) ); + break; + + case( META_BMPEXSCALE_ACTION ): + mpMetaFile->AddAction( new MetaBmpExScaleAction( rDestPt, rDestSize, aBmpEx ) ); + break; + + case( META_BMPEXSCALEPART_ACTION ): + mpMetaFile->AddAction( new MetaBmpExScalePartAction( rDestPt, rDestSize, + rSrcPtPixel, rSrcSizePixel, aBmpEx ) ); + break; + } + } + + OUTDEV_INIT(); + + if( OUTDEV_PRINTER == meOutDevType ) + { + Bitmap aBmp( aBmpEx.GetBitmap() ), aMask( aBmpEx.GetMask() ); + aBmp.Replace( aMask, Color( COL_WHITE ) ); + ImplPrintTransparent( aBmp, aMask, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel ); + return; + } +#ifndef REMOTE_APPSERVER + else if( rBitmapEx.IsAlpha() ) + { + ImplDrawAlpha( aBmpEx.GetBitmap(), aBmpEx.GetAlpha(), rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel ); + return; + } +#endif + + if( !( !aBmpEx ) ) + { + TwoRect aPosAry; + + aPosAry.mnSrcX = rSrcPtPixel.X(); + aPosAry.mnSrcY = rSrcPtPixel.Y(); + aPosAry.mnSrcWidth = rSrcSizePixel.Width(); + aPosAry.mnSrcHeight = rSrcSizePixel.Height(); + aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() ); + aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() ); + aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() ); + aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() ); + + const ULONG nMirrFlags = ImplAdjustTwoRect( aPosAry, aBmpEx.GetSizePixel() ); + + if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight ) + { +#ifndef REMOTE_APPSERVER + + if( nMirrFlags ) + aBmpEx.Mirror( nMirrFlags ); + + const ImpBitmap* pImpBmp = aBmpEx.ImplGetBitmapImpBitmap(); + const ImpBitmap* pMaskBmp = aBmpEx.ImplGetMaskImpBitmap(); + + if ( pMaskBmp ) + mpGraphics->DrawBitmap( &aPosAry, *pImpBmp->ImplGetSalBitmap(), *pMaskBmp->ImplGetSalBitmap() ); + else + mpGraphics->DrawBitmap( &aPosAry, *pImpBmp->ImplGetSalBitmap() ); + +#else + + if( nMirrFlags ) + aBmpEx.Mirror( nMirrFlags ); + + aBmpEx.ImplDrawRemote( this, + Point( aPosAry.mnSrcX, aPosAry.mnSrcY ), + Size( aPosAry.mnSrcWidth, aPosAry.mnSrcHeight ), + Point( aPosAry.mnDestX, aPosAry.mnDestY ), + Size( aPosAry.mnDestWidth, aPosAry.mnDestHeight ) ); + +#endif + } + } +} + +// ------------------------------------------------------------------ + +void OutputDevice::DrawMask( const Point& rDestPt, + const Bitmap& rBitmap, const Color& rMaskColor ) +{ + DBG_TRACE( "OutputDevice::DrawMask()" ); + const Size aSizePix( rBitmap.GetSizePixel() ); + ImplDrawMask( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, rMaskColor, META_MASK_ACTION ); +} + +// ------------------------------------------------------------------ + +void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize, + const Bitmap& rBitmap, const Color& rMaskColor ) +{ + DBG_TRACE( "OutputDevice::DrawMask( Size )" ); + ImplDrawMask( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, rMaskColor, META_MASKSCALE_ACTION ); +} + +// ------------------------------------------------------------------ + +void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize, + const Point& rSrcPtPixel, const Size& rSrcSizePixel, + const Bitmap& rBitmap, const Color& rMaskColor ) +{ + DBG_TRACE( "OutputDevice::DrawMask( Point, Size )" ); + ImplDrawMask( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmap, rMaskColor, META_MASKSCALEPART_ACTION ); +} + +// ------------------------------------------------------------------ + +void OutputDevice::ImplDrawMask( const Point& rDestPt, const Size& rDestSize, + const Point& rSrcPtPixel, const Size& rSrcSizePixel, + const Bitmap& rBitmap, const Color& rMaskColor, + const ULONG nAction ) +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if( ROP_INVERT == meRasterOp ) + { + DrawRect( Rectangle( rDestPt, rDestSize ) ); + return; + } + + if ( mpMetaFile ) + { + switch( nAction ) + { + case( META_MASK_ACTION ): + mpMetaFile->AddAction( new MetaMaskAction( rDestPt, + rBitmap, rMaskColor ) ); + break; + + case( META_MASKSCALE_ACTION ): + mpMetaFile->AddAction( new MetaMaskScaleAction( rDestPt, + rDestSize, rBitmap, rMaskColor ) ); + break; + + case( META_MASKSCALEPART_ACTION ): + mpMetaFile->AddAction( new MetaMaskScalePartAction( rDestPt, rDestSize, + rSrcPtPixel, rSrcSizePixel, rBitmap, rMaskColor ) ); + break; + } + } + + OUTDEV_INIT(); + +#ifndef REMOTE_APPSERVER + if ( OUTDEV_PRINTER == meOutDevType ) + { + ImplPrintMask( rBitmap, rMaskColor, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel ); + return; + } +#endif + + const ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap(); + + if ( pImpBmp ) + { + TwoRect aPosAry; + + aPosAry.mnSrcX = rSrcPtPixel.X(); + aPosAry.mnSrcY = rSrcPtPixel.Y(); + aPosAry.mnSrcWidth = rSrcSizePixel.Width(); + aPosAry.mnSrcHeight = rSrcSizePixel.Height(); + aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() ); + aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() ); + aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() ); + aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() ); + + // spiegeln via Koordinaten wollen wir nicht + const ULONG nMirrFlags = ImplAdjustTwoRect( aPosAry, pImpBmp->ImplGetSize() ); + + // check if output is necessary + if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight ) + { +#ifndef REMOTE_APPSERVER + + if( nMirrFlags ) + { + Bitmap aTmp( rBitmap ); + aTmp.Mirror( nMirrFlags ); + mpGraphics->DrawMask( &aPosAry, *aTmp.ImplGetImpBitmap()->ImplGetSalBitmap(), + ImplColorToSal( rMaskColor ) ); + } + else + mpGraphics->DrawMask( &aPosAry, *pImpBmp->ImplGetSalBitmap(), + ImplColorToSal( rMaskColor ) ); + +#else + + if( nMirrFlags ) + { + Bitmap aTmp( rBitmap ); + aTmp.Mirror( nMirrFlags ); + aTmp.ImplDrawRemoteMask( this, + Point( aPosAry.mnSrcX, aPosAry.mnSrcY ), + Size( aPosAry.mnSrcWidth, aPosAry.mnSrcHeight ), + Point( aPosAry.mnDestX, aPosAry.mnDestY ), + Size( aPosAry.mnDestWidth, aPosAry.mnDestHeight ), + rMaskColor ); + } + else + rBitmap.ImplDrawRemoteMask( this, + Point( aPosAry.mnSrcX, aPosAry.mnSrcY ), + Size( aPosAry.mnSrcWidth, aPosAry.mnSrcHeight ), + Point( aPosAry.mnDestX, aPosAry.mnDestY ), + Size( aPosAry.mnDestWidth, aPosAry.mnDestHeight ), + rMaskColor ); + +#endif + } + } +} + +// ------------------------------------------------------------------ + +Bitmap OutputDevice::GetBitmap( const Point& rSrcPt, const Size& rSize ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + Bitmap aBmp; + long nX = ImplLogicXToDevicePixel( rSrcPt.X() ); + long nY = ImplLogicYToDevicePixel( rSrcPt.Y() ); + long nWidth = ImplLogicWidthToDevicePixel( rSize.Width() ); + long nHeight = ImplLogicHeightToDevicePixel( rSize.Height() ); + +#ifndef REMOTE_APPSERVER + if ( mpGraphics || ( (OutputDevice*) this )->ImplGetGraphics() ) +#endif + { + if ( nWidth && nHeight ) + { +#ifndef REMOTE_APPSERVER + Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) ); + BOOL bClipped = FALSE; + + // X-Koordinate ausserhalb des Bereichs? + if ( nX < mnOutOffX ) + { + nWidth -= ( mnOutOffX - nX ); + nX = mnOutOffX; + bClipped = TRUE; + } + + // Y-Koordinate ausserhalb des Bereichs? + if ( nY < mnOutOffY ) + { + nHeight -= ( mnOutOffY - nY ); + nY = mnOutOffY; + bClipped = TRUE; + } + + // Breite ausserhalb des Bereichs? + if ( (nWidth + nX) > (mnOutWidth + mnOutOffX) ) + { + nWidth = mnOutOffX + mnOutWidth - nX; + bClipped = TRUE; + } + + // Hoehe ausserhalb des Bereichs? + if ( (nHeight + nY) > (mnOutHeight + mnOutOffY) ) + { + nHeight = mnOutOffY + mnOutHeight - nY; + bClipped = TRUE; + } + + if ( bClipped ) + { + // Falls auf den sichtbaren Bereich geclipped wurde, + // muessen wir eine Bitmap in der rchtigen Groesse + // erzeugen, in die die geclippte Bitmap an die angepasste + // Position kopiert wird + VirtualDevice aVDev( *this ); + + if ( aVDev.SetOutputSizePixel( aRect.GetSize() ) ) + { + if ( ((OutputDevice*)&aVDev)->mpGraphics || ((OutputDevice*)&aVDev)->ImplGetGraphics() ) + { + TwoRect aPosAry; + + aPosAry.mnSrcX = nX; + aPosAry.mnSrcY = nY; + aPosAry.mnSrcWidth = nWidth; + aPosAry.mnSrcHeight = nHeight; + aPosAry.mnDestX = ( aRect.Left() < mnOutOffX ) ? ( mnOutOffX - aRect.Left() ) : 0L; + aPosAry.mnDestY = ( aRect.Top() < mnOutOffY ) ? ( mnOutOffY - aRect.Top() ) : 0L; + aPosAry.mnDestWidth = nWidth; + aPosAry.mnDestHeight = nHeight; + + if ( (nWidth > 0) && (nHeight > 0) ) + (((OutputDevice*)&aVDev)->mpGraphics)->CopyBits( &aPosAry, mpGraphics ); + + aBmp = aVDev.GetBitmap( Point(), aVDev.GetOutputSizePixel() ); + } + else + bClipped = FALSE; + } + else + bClipped = FALSE; + } + + if ( !bClipped ) + { + SalBitmap* pSalBmp = mpGraphics->GetBitmap( nX, nY, nWidth, nHeight ); + + if( pSalBmp ) + { + ImpBitmap* pImpBmp = new ImpBitmap; + pImpBmp->ImplSetSalBitmap( pSalBmp ); + aBmp.ImplSetImpBitmap( pImpBmp ); + } + } +#else + aBmp.ImplGetRemoteBmp( (OutputDevice*) this, Point( nX, nY ), Size( nWidth, nHeight ) ); +#endif + } + } + + return aBmp; +} + +// ------------------------------------------------------------------ + +void OutputDevice::ImplGetFrameBitmap( const Point& rDestPt, const Size& rSize, + Bitmap& rBitmap ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + BOOL bOldMap = mbMap; + ((OutputDevice*)this)->mbMap = FALSE; + rBitmap = GetBitmap( rDestPt, rSize ); + ((OutputDevice*)this)->mbMap = bOldMap; +} + +// ------------------------------------------------------------------ + +Color OutputDevice::GetPixel( const Point& rPt ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + Color aColor; + +#ifndef REMOTE_APPSERVER + if ( mpGraphics || ((OutputDevice*)this)->ImplGetGraphics() ) + { + if ( mbInitClipRegion ) + ((OutputDevice*)this)->ImplInitClipRegion(); + + if ( !mbOutputClipped ) + { + const long nX = ImplLogicXToDevicePixel( rPt.X() ); + const long nY = ImplLogicYToDevicePixel( rPt.Y() ); + const SalColor aSalCol = mpGraphics->GetPixel( nX, nY ); + aColor.SetRed( SALCOLOR_RED( aSalCol ) ); + aColor.SetGreen( SALCOLOR_GREEN( aSalCol ) ); + aColor.SetBlue( SALCOLOR_BLUE( aSalCol ) ); + } + } +#else // REMOTE_APPSERVER + ImplServerGraphics* pGraphics = ( (OutputDevice*) this )->ImplGetServerGraphics(); + if( pGraphics ) + { + const long nX = ImplLogicXToDevicePixel( rPt.X() ); + const long nY = ImplLogicYToDevicePixel( rPt.Y() ); + aColor = pGraphics->GetPixel( Point( nX, nY ) ); + } +#endif // REMOTE_APPSERVER + + return aColor; +} + +// ------------------------------------------------------------------ + +Color* OutputDevice::GetPixel( const Polygon& rPts ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + Color* pColors = NULL; + const USHORT nSize = rPts.GetSize(); + + if( nSize ) + { +#ifndef REMOTE_APPSERVER + if ( mpGraphics || ((OutputDevice*)this)->ImplGetGraphics() ) + { + if ( mbInitClipRegion ) + ((OutputDevice*)this)->ImplInitClipRegion(); + + if ( !mbOutputClipped ) + { + pColors = new Color[ nSize ]; + + for( USHORT i = 0; i < nSize; i++ ) + { + Color& rCol = pColors[ i ]; + const Point& rPt = rPts[ i ]; + const SalColor aSalCol( mpGraphics->GetPixel( ImplLogicXToDevicePixel( rPt.X() ), + ImplLogicYToDevicePixel( rPt.Y() ) ) ); + + rCol.SetRed( SALCOLOR_RED( aSalCol ) ); + rCol.SetGreen( SALCOLOR_GREEN( aSalCol ) ); + rCol.SetBlue( SALCOLOR_BLUE( aSalCol ) ); + } + } + } +#else // REMOTE_APPSERVER + ImplServerGraphics* pGraphics = ( (OutputDevice*) this )->ImplGetServerGraphics(); + if( pGraphics ) + { + pColors = pGraphics->GetPixel( ImplLogicToDevicePixel( rPts ) ); + } +#endif // REMOTE_APPSERVER + } + + return pColors; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawPixel( const Point& rPt ) +{ + DBG_TRACE( "OutputDevice::DrawPixel()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaPointAction( rPt ) ); + + if ( !IsDeviceOutputNecessary() || !mbLineColor ) + return; + +#ifndef REMOTE_APPSERVER + Point aPt = ImplLogicToDevicePixel( rPt ); + + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; + + if ( mbInitLineColor ) + ImplInitLineColor(); + + mpGraphics->DrawPixel( aPt.X(), aPt.Y() ); +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + if ( mbInitLineColor ) + ImplInitLineColor(); + pGraphics->DrawPixel( ImplLogicToDevicePixel( rPt ) ); + } +#endif +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawPixel( const Point& rPt, const Color& rColor ) +{ + DBG_TRACE( "OutputDevice::DrawPixel()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + Color aColor( rColor ); + + if( mnDrawMode & ( DRAWMODE_BLACKLINE | DRAWMODE_WHITELINE | + DRAWMODE_GRAYLINE | DRAWMODE_GHOSTEDLINE ) ) + { + if( !ImplIsColorTransparent( aColor ) ) + { + if( mnDrawMode & DRAWMODE_BLACKLINE ) + { + aColor = Color( COL_BLACK ); + } + else if( mnDrawMode & DRAWMODE_WHITELINE ) + { + aColor = Color( COL_WHITE ); + } + else if( mnDrawMode & DRAWMODE_GRAYLINE ) + { + const UINT8 cLum = aColor.GetLuminance(); + aColor = Color( cLum, cLum, cLum ); + } + + if( mnDrawMode & DRAWMODE_GHOSTEDLINE ) + { + aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80, + ( aColor.GetGreen() >> 1 ) | 0x80, + ( aColor.GetBlue() >> 1 ) | 0x80 ); + } + } + } + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaPixelAction( rPt, aColor ) ); + + if ( !IsDeviceOutputNecessary() || ImplIsColorTransparent( aColor ) ) + return; + +#ifndef REMOTE_APPSERVER + Point aPt = ImplLogicToDevicePixel( rPt ); + + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; + + mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( aColor ) ); +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + pGraphics->DrawPixel( ImplLogicToDevicePixel( rPt ), aColor ); +#endif +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawPixel( const Polygon& rPts, const Color* pColors ) +{ + if ( !pColors ) + DrawPixel( rPts, GetLineColor() ); + else + { + DBG_TRACE( "OutputDevice::DrawPixel()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_ASSERT( pColors, "OutputDevice::DrawPixel: No color array specified" ); + + const USHORT nSize = rPts.GetSize(); + + if ( nSize ) + { + if ( mpMetaFile ) + for ( USHORT i = 0; i < nSize; i++ ) + mpMetaFile->AddAction( new MetaPixelAction( rPts[ i ], pColors[ i ] ) ); + + if ( !IsDeviceOutputNecessary() ) + return; + +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( mpGraphics || ImplGetGraphics() ) + { + if ( mbInitClipRegion ) + ImplInitClipRegion(); + + if ( mbOutputClipped ) + return; + + for ( USHORT i = 0; i < nSize; i++ ) + { + const Point aPt( ImplLogicToDevicePixel( rPts[ i ] ) ); + mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( pColors[ i ] ) ); + } + } +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + pGraphics->DrawPixel( ImplLogicToDevicePixel( rPts ), pColors ); + } +#endif + } + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawPixel( const Polygon& rPts, const Color& rColor ) +{ + if( rColor != COL_TRANSPARENT ) + { + const USHORT nSize = rPts.GetSize(); + Color* pColArray = new Color[ nSize ]; + + for( USHORT i = 0; i < nSize; i++ ) + pColArray[ i ] = rColor; + + DrawPixel( rPts, pColArray ); + delete[] pColArray; + } +} + +// ------------------------------------------------------------------------ + +void OutputDevice::ImplDrawAlpha( const Bitmap& rBmp, const AlphaMask& rAlpha, + const Point& rDestPt, const Size& rDestSize, + const Point& rSrcPtPixel, const Size& rSrcSizePixel ) +{ + Point aPt; + Point aOutPt( LogicToPixel( rDestPt ) ); + Size aOutSz( LogicToPixel( rDestSize ) ); + Rectangle aDstRect( aPt, GetOutputSizePixel() ); + const BOOL bHMirr = aOutSz.Width() < 0, bVMirr = aOutSz.Height() < 0; + + if( OUTDEV_WINDOW == meOutDevType ) + { + const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() ); + + if( !aPaintRgn.IsNull() ) + aDstRect.Intersection( LogicToPixel( aPaintRgn.GetBoundRect() ) ); + } + + if( bHMirr ) + { + aOutSz.Width() = -aOutSz.Width(); + aOutPt.X() -= ( aOutSz.Width() - 1L ); + } + + if( bVMirr ) + { + aOutSz.Height() = -aOutSz.Height(); + aOutPt.Y() -= ( aOutSz.Height() - 1L ); + } + + if( !aDstRect.Intersection( Rectangle( aOutPt, aOutSz ) ).IsEmpty() ) + { + Rectangle aBmpRect( aPt, rBmp.GetSizePixel() ); + + if( !aBmpRect.Intersection( Rectangle( rSrcPtPixel, rSrcSizePixel ) ).IsEmpty() ) + { + GDIMetaFile* pOldMetaFile = mpMetaFile; mpMetaFile = NULL; + const BOOL bOldMap = mbMap; mbMap = FALSE; + Bitmap aBmp( GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) ); + BitmapColor aDstCol; + const long nSrcWidth = aBmpRect.GetWidth(), nSrcHeight = aBmpRect.GetHeight(); + const long nDstWidth = aDstRect.GetWidth(), nDstHeight = aDstRect.GetHeight(); + const long nOutWidth = aOutSz.Width(), nOutHeight = aOutSz.Height(); + const long nOffX = aDstRect.Left() - aOutPt.X(), nOffY = aDstRect.Top() - aOutPt.Y(); + long nX, nOutX, nY, nOutY, nMirrOffX, nMirrOffY; + long* pMapX = new long[ nDstWidth ]; + long* pMapY = new long[ nDstHeight ]; + + // create horizontal mapping table + if( bHMirr ) + nMirrOffX = ( aBmpRect.Left() << 1 ) + nSrcWidth - 1; + + for( nX = 0L, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ ) + { + pMapX[ nX ] = aBmpRect.Left() + nOutX * nSrcWidth / nOutWidth; + + if( bHMirr ) + pMapX[ nX ] = nMirrOffX - pMapX[ nX ]; + } + + // create vertical mapping table + if( bVMirr ) + nMirrOffY = ( aBmpRect.Top() << 1 ) + nSrcHeight - 1; + + for( nY = 0L, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ ) + { + pMapY[ nY ] = aBmpRect.Top() + nOutY * nSrcHeight / nOutHeight; + + if( bVMirr ) + pMapY[ nY ] = nMirrOffY - pMapY[ nY ]; + } + + if( GetBitCount() <= 8 ) + { + Bitmap aDither( aBmp.GetSizePixel(), 8 ); + BitmapColor aIndex( 0 ); + BitmapReadAccess* pP = ( (Bitmap&) rBmp ).AcquireReadAccess(); + BitmapReadAccess* pA = ( (AlphaMask&) rAlpha ).AcquireReadAccess(); + BitmapReadAccess* pB = aBmp.AcquireReadAccess(); + BitmapWriteAccess* pW = aDither.AcquireWriteAccess(); + + if( pB && pP && pA && pW ) + { + for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ ) + { + const long nMapY = pMapY[ nY ]; + const long nModY = ( nOutY & 0x0FL ) << 4L; + + for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ ) + { + const long nMapX = pMapX[ nX ]; + const ULONG nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ]; + + aDstCol = pB->GetColor( nY, nX ); + aDstCol.Merge( pP->GetColor( nMapY, nMapX ), (BYTE) pA->GetPixel( nMapY, nMapX ) ); + aIndex.SetIndex( (BYTE) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] + + nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] + + nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) ); + pW->SetPixel( nY, nX, aIndex ); + } + } + } + + ( (Bitmap&) rBmp ).ReleaseAccess( pP ); + ( (AlphaMask&) rAlpha ).ReleaseAccess( pA ); + aBmp.ReleaseAccess( pB ); + aDither.ReleaseAccess( pW ); + DrawBitmap( aDstRect.TopLeft(), aDither ); + } + else + { + BitmapReadAccess* pP = ( (Bitmap&) rBmp ).AcquireReadAccess(); + BitmapReadAccess* pA = ( (AlphaMask&) rAlpha ).AcquireReadAccess(); + BitmapWriteAccess* pB = aBmp.AcquireWriteAccess(); + + if( pP && pA && pB ) + { + if( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) + { + switch( pP->GetScanlineFormat() ) + { + case( BMP_FORMAT_8BIT_PAL ): + { + for( nY = 0; nY < nDstHeight; nY++ ) + { + const long nMapY = pMapY[ nY ]; + Scanline pPScan = pP->GetScanline( nMapY ); + Scanline pAScan = pA->GetScanline( nMapY ); + + for( nX = 0; nX < nDstWidth; nX++ ) + { + const long nMapX = pMapX[ nX ]; + aDstCol = pB->GetPixel( nY, nX ); + pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetPaletteColor( pPScan[ nMapX ] ), + pAScan[ nMapX ] ) ); + } + } + } + break; + + case( BMP_FORMAT_24BIT_TC_BGR ): + { + for( nY = 0; nY < nDstHeight; nY++ ) + { + const long nMapY = pMapY[ nY ]; + Scanline pPScan = pP->GetScanline( nMapY ); + Scanline pAScan = pA->GetScanline( nMapY ); + + for( nX = 0; nX < nDstWidth; nX++ ) + { + const long nMapX = pMapX[ nX ]; + Scanline pTmp = pPScan + nMapX * 3; + + aDstCol = pB->GetPixel( nY, nX ); + pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 2 ], pTmp[ 1 ], pTmp[ 0 ], + pAScan[ nMapX ] ) ); + } + } + } + break; + + case( BMP_FORMAT_24BIT_TC_RGB ): + { + for( nY = 0; nY < nDstHeight; nY++ ) + { + const long nMapY = pMapY[ nY ]; + Scanline pPScan = pP->GetScanline( nMapY ); + Scanline pAScan = pA->GetScanline( nMapY ); + + for( nX = 0; nX < nDstWidth; nX++ ) + { + const long nMapX = pMapX[ nX ]; + Scanline pTmp = pPScan + nMapX * 3; + + aDstCol = pB->GetPixel( nY, nX ); + pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 0 ], pTmp[ 1 ], pTmp[ 2 ], + pAScan[ nMapX ] ) ); + } + } + } + break; + + default: + { + for( nY = 0; nY < nDstHeight; nY++ ) + { + const long nMapY = pMapY[ nY ]; + Scanline pAScan = pA->GetScanline( nMapY ); + + for( nX = 0; nX < nDstWidth; nX++ ) + { + const long nMapX = pMapX[ nX ]; + aDstCol = pB->GetPixel( nY, nX ); + pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetColor( nMapY, nMapX ), + pAScan[ nMapX ] ) ); + } + } + } + break; + } + } + else + { + for( nY = 0; nY < nDstHeight; nY++ ) + { + const long nMapY = pMapY[ nY ]; + + for( nX = 0; nX < nDstWidth; nX++ ) + { + const long nMapX = pMapX[ nX ]; + aDstCol = pB->GetPixel( nY, nX ); + pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetColor( nMapY, nMapX ), + (BYTE) pA->GetPixel( nMapY, nMapX ) ) ); + } + } + } + } + + ( (Bitmap&) rBmp ).ReleaseAccess( pP ); + ( (AlphaMask&) rAlpha ).ReleaseAccess( pA ); + aBmp.ReleaseAccess( pB ); + DrawBitmap( aDstRect.TopLeft(), aBmp ); + } + + delete[] pMapX; + delete[] pMapY; + mbMap = bOldMap; + mpMetaFile = pOldMetaFile; + } + } +} + +// ------------------------------------------------------------------------ + +static Pair* ImplGetMap( long nFromSize, long nToSize ) +{ + DBG_ASSERT( nFromSize && nToSize, "ImplGetMap(): Invalid size!" ); + + Pair* pMap = new Pair[ nFromSize ]; + const double fSize = (double) nToSize / nFromSize; + double fRealSum = 0.0; + const long nLastToPos = nToSize - 1L; + long nErrSum = 0L, nPos = 0L, nSize = 0L; + + for( long i = 0L; i < nFromSize; i++ ) + { + nPos = nPos + nSize; + nSize = Max( FRound( fSize - ( nErrSum - fRealSum ) ), 0L ); + + nErrSum += nSize; + fRealSum += fSize; + + pMap[ i ].A() = nPos = Min( nPos, nLastToPos ); + pMap[ i ].B() = Min( nPos + Max( nSize, 1L ) - 1L, nLastToPos ); + } + + return pMap; +} + +// ------------------------------------------------------------------------ + +static BOOL ImplCreateBandBitmaps( BitmapReadAccess* pPAcc, BitmapReadAccess* pMAcc, + long* pMapX, long* pMapY, + long nDstWidth, long nDstY1, long nDstY2, + Bitmap& rPaint, Bitmap& rMask ) +{ + const Size aSz( nDstWidth, nDstY2 - nDstY1 + 1 ); + BOOL bRet = FALSE; + + rPaint = Bitmap( aSz, pPAcc->GetBitCount(), pPAcc->HasPalette() ? &pPAcc->GetPalette() : NULL ); + rMask = Bitmap( aSz, pMAcc->GetBitCount(), pMAcc->HasPalette() ? &pMAcc->GetPalette() : NULL ); + + BitmapWriteAccess* pWPAcc = rPaint.AcquireWriteAccess(); + BitmapWriteAccess* pWMAcc = rMask.AcquireWriteAccess(); + + if( pWPAcc && pWMAcc ) + { + const long nWidth = pWPAcc->Width(); + const long nHeight = pWPAcc->Width(); + const long nPScanSize = pWPAcc->GetScanlineSize(); + const long nMScanSize = pWMAcc->GetScanlineSize(); + long nY = 0, nScanY = nDstY1; + + while( nScanY <= nDstY2 ) + { + const long nMapY = pMapY[ nScanY ]; + + for( long nX = 0L; nX < nWidth; nX++ ) + { + const long nMapX = pMapX[ nX ]; + pWPAcc->SetPixel( nY, nX, pPAcc->GetPixel( nMapY, nMapX ) ); + pWMAcc->SetPixel( nY, nX, pMAcc->GetPixel( nMapY, nMapX ) ); + } + + while( ( nScanY < nDstY2 ) && ( pMapY[ nScanY + 1 ] == nMapY ) ) + { + HMEMCPY( pWPAcc->GetScanline( nY + 1L ), pWPAcc->GetScanline( nY ), nPScanSize ); + HMEMCPY( pWMAcc->GetScanline( nY + 1L ), pWMAcc->GetScanline( nY ), nMScanSize ); + nY++, nScanY++; + } + + nY++, nScanY++; + } + + bRet = TRUE; + } + + if( pWPAcc ) + rPaint.ReleaseAccess( pWPAcc ); + + if( pWMAcc ) + rMask.ReleaseAccess( pWMAcc ); + + return bRet; +} + +// ------------------------------------------------------------------------ + +void OutputDevice::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask, + const Point& rDestPt, const Size& rDestSize, + const Point& rSrcPtPixel, const Size& rSrcSizePixel ) +{ + Point aPt; + Point aDestPt( LogicToPixel( rDestPt ) ); + Size aDestSz( LogicToPixel( rDestSize ) ); + Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel ); + + aSrcRect.Justify(); + + if( !!rBmp && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() ) + { + ULONG nMirrFlags = 0UL; + Bitmap aPaint( rBmp ); + Bitmap aMask( rMask ); + Region aDstRgn; + BOOL bMask = !!aMask; + + if( bMask && ( aMask.GetBitCount() > 1 ) ) + aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD ); + + // mirrored horizontically + if( aDestSz.Width() < 0L ) + { + aDestSz.Width() = -aDestSz.Width(); + aDestPt.X() -= ( aDestSz.Width() - 1L ); + nMirrFlags |= BMP_MIRROR_HORZ; + } + + // mirrored vertically + if( aDestSz.Height() < 0L ) + { + aDestSz.Height() = -aDestSz.Height(); + aDestPt.Y() -= ( aDestSz.Height() - 1L ); + nMirrFlags |= BMP_MIRROR_VERT; + } + + // source cropped? + if( aSrcRect != Rectangle( aPt, aPaint.GetSizePixel() ) ) + { + aPaint.Crop( aSrcRect ); + if( bMask ) + aMask.Crop( aSrcRect ); + } + + // destination mirrored + if( nMirrFlags ) + { + aPaint.Mirror( nMirrFlags ); + if( bMask ) + aMask.Mirror( nMirrFlags ); + } + + const Rectangle aDstRect( aDestPt, aDestSz ); + + // create destination region + if( mbClipRegion && !maRegion.IsEmpty() ) + { + aDstRgn = maRegion; + aDstRgn.Intersect( aDstRect ); + } + else + aDstRgn = aDstRect; + + aDstRgn.Move( -aDstRect.Left(), -aDstRect.Top() ); + + // we always want to have a mask + if( !bMask ) + { + aMask = Bitmap( aSrcRect.GetSize(), 1 ); + aMask.Erase( Color( COL_BLACK ) ); + } + + BitmapReadAccess* pPAcc = aPaint.AcquireReadAccess(); + BitmapReadAccess* pMAcc = aMask.AcquireReadAccess(); + + if( pPAcc && pMAcc ) + { + const long nWidth = aDestSz.Width(); + const long nHeight = aDestSz.Height(); + const long nWidth1 = nWidth - 1; + const long nHeight1 = nHeight - 1; + const long nOldWidth1 = aSrcRect.GetWidth() - 1; + const long nOldHeight1 = aSrcRect.GetHeight() - 1; + const long nScanByteCount = Max( nWidth * aPaint.GetBitCount() / 8L, 1L ); + const long nBandHeight = BAND_MAX_SIZE / nScanByteCount + 1; + long* pMapX = new long[ nWidth ]; + long* pMapY = new long[ nHeight ]; + long nX, nY; + long nBandY1, nBandY2; + GDIMetaFile* pOldMetaFile = mpMetaFile; + const BOOL bOldMap = mbMap; + + mpMetaFile = NULL; + Push( PUSH_CLIPREGION ); + SetClipRegion(); + mbMap = FALSE; + + // create mapping tables + for( nX = 0L; nX < nWidth; nX++ ) + pMapX[ nX ] = nWidth1 ? ( nX * nOldWidth1 / nWidth1 ) : 0; + + for( nY = 0L; nY < nHeight; nY++ ) + pMapY[ nY ] = nHeight1 ? ( nY * nOldHeight1 / nHeight1 ) : 0; + + // process bands + for( nBandY1 = 0, nBandY2 = nBandHeight; nBandY1 < nHeight; nBandY1 += nBandHeight, nBandY2 += nBandHeight ) + { + Bitmap aWorkPaint, aWorkMask; + + // don't walk over bounds + if( nBandY2 > nHeight1 ) + nBandY2 = nHeight1; + + if( ImplCreateBandBitmaps( pPAcc, pMAcc, pMapX, pMapY, nWidth, nBandY1, nBandY2, aWorkPaint, aWorkMask ) ) + { + Region aWorkRgn( aDstRgn ); + aWorkRgn.Move( 0, -nBandY1 ); + aWorkRgn.Intersect( aWorkMask.CreateRegion( COL_BLACK, Rectangle( aPt, aWorkMask.GetSizePixel() ) ) ); + + ImplRegionInfo aInfo; + long nWorkX, nWorkY, nWorkWidth, nWorkHeight; + BOOL bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, + nWorkWidth, nWorkHeight ); + + while( bRgnRect ) + { + Bitmap aCropBmp( aWorkPaint ); + const Point aOutPt( nWorkX + aDestPt.X(), nWorkY + nBandY1 + aDestPt.Y() ); + const Size aOutSz( nWorkWidth, nWorkHeight ); + const Size aOutSz1( nWorkWidth + 1, nWorkHeight + 1 ); + + aCropBmp.Crop( Rectangle( Point( nWorkX, nWorkY ), aOutSz ) ); + ImplDrawBitmap( aOutPt, aOutSz1, Point(), aOutSz, aCropBmp, META_BMPSCALE_ACTION ); + bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight ); + } + } + } + + delete[] pMapX; + delete[] pMapY; + mbMap = bOldMap; + Pop(); + mpMetaFile = pOldMetaFile; + } + + if( pPAcc ) + aPaint.ReleaseAccess( pPAcc ); + + if( pMAcc ) + aMask.ReleaseAccess( pMAcc ); + } +} + +// ------------------------------------------------------------------------ + +void OutputDevice::ImplPrintMask( const Bitmap& rMask, const Color& rMaskColor, + const Point& rDestPt, const Size& rDestSize, + const Point& rSrcPtPixel, const Size& rSrcSizePixel ) +{ +#ifndef REMOTE_APPSERVER + + Point aPt; + Point aDestPt( LogicToPixel( rDestPt ) ); + Size aDestSz( LogicToPixel( rDestSize ) ); + Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel ); + + aSrcRect.Justify(); + + if( !!rMask && + aSrcRect.GetWidth() && aSrcRect.GetHeight() && + aDestSz.Width() && aDestSz.Height() ) + { + ULONG nMirrFlags = 0UL; + Bitmap aMask( rMask ); + Region aRegion; + + if( aMask.GetBitCount() > 1 ) + aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD ); + + if( aDestSz.Width() < 0L ) + { + aDestSz.Width() = -aDestSz.Width(); + aDestPt.X() -= ( aDestSz.Width() - 1L ); + nMirrFlags |= BMP_MIRROR_HORZ; + } + + if( aDestSz.Height() < 0L ) + { + aDestSz.Height() = -aDestSz.Height(); + aDestPt.Y() -= ( aDestSz.Height() - 1L ); + nMirrFlags |= BMP_MIRROR_VERT; + } + + // source cropped? + if( aSrcRect != Rectangle( aPt, aMask.GetSizePixel() ) ) + aMask.Crop( aSrcRect ); + + // destination mirrored + if( nMirrFlags ) + aMask.Mirror( nMirrFlags ); + + aRegion = aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ); + + ImplRegionInfo aInfo; + const Size aSrcSz( aMask.GetSizePixel() ); + long nSrcX, nSrcY, nSrcWidth, nSrcHeight; + long nDstX, nDstY, nDstWidth, nDstHeight; + GDIMetaFile* pOldMetaFile = mpMetaFile; + Pair* pMapX = ImplGetMap( aSrcSz.Width(), aDestSz.Width() ); + Pair* pMapY = ImplGetMap( aSrcSz.Height(), aDestSz.Height() ); + BOOL bOldMap = mbMap; + BOOL bRegionRect = aRegion.ImplGetFirstRect( aInfo, nSrcX, nSrcY, nSrcWidth, nSrcHeight ); + + mpMetaFile = NULL; + mbMap = FALSE; + Push( PUSH_FILLCOLOR | PUSH_LINECOLOR ); + SetLineColor( rMaskColor ); + SetFillColor( rMaskColor ); + ImplInitLineColor(); + ImplInitFillColor(); + + while( bRegionRect ) + { + nDstX = pMapX[ nSrcX ].A(); + nDstY = pMapY[ nSrcY ].A(); + nDstWidth = pMapX[ nSrcX + nSrcWidth - 1L ].B() - nDstX + 1L; + nDstHeight = pMapY[ nSrcY + nSrcHeight - 1L ].B() - nDstY + 1L; + mpGraphics->DrawRect( nDstX + aDestPt.X(), nDstY + aDestPt.Y(), nDstWidth, nDstHeight ); + bRegionRect = aRegion.ImplGetNextRect( aInfo, nSrcX, nSrcY, nSrcWidth, nSrcHeight ); + } + + Pop(); + delete[] pMapX; + delete[] pMapY; + mbMap = bOldMap; + mpMetaFile = pOldMetaFile; + } + +#endif +} diff --git a/vcl/source/gdi/outdev3.cxx b/vcl/source/gdi/outdev3.cxx new file mode 100644 index 000000000000..4dbd5935f2ae --- /dev/null +++ b/vcl/source/gdi/outdev3.cxx @@ -0,0 +1,6326 @@ +/************************************************************************* + * + * $RCSfile: outdev3.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <math.h> +#include <string.h> + +#define _SV_OUTDEV_CXX + +#ifndef REMOTE_APPSERVER +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#endif + +#ifndef REMOTE_APPSERVER +#ifndef _SV_SALGDI_HXX +#include <salgdi.hxx> +#endif +#else +#ifndef _SV_RMOUTDEV_HXX +#include <rmoutdev.hxx> +#endif +#endif + +#ifndef _RTL_TENCINFO_H +#include <rtl/tencinfo.h> +#endif +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif + +#ifndef _SV_SVDATA_HXX +#include <svdata.hxx> +#endif +#ifndef _SV_METRIC_HXX +#include <metric.hxx> +#endif +#ifndef _SV_METAACT_HXX +#include <metaact.hxx> +#endif +#ifndef _SV_GDIMTF_HXX +#include <gdimtf.hxx> +#endif +#ifndef _SV_OUTDATA_HXX +#include <outdata.hxx> +#endif +#ifndef _SV_OUTFONT_HXX +#include <outfont.hxx> +#endif +#ifndef _SV_POLY_HXX +#include <poly.hxx> +#endif +#ifndef _SV_OUTDEV_H +#include <outdev.h> +#endif +#ifndef _SV_VIRDEV_HXX +#include <virdev.hxx> +#endif +#ifndef _SV_PRINT_HXX +#include <print.hxx> +#endif +#ifndef _SV_WINDOW_H +#include <window.h> +#endif +#ifndef _SV_WINDOW_HXX +#include <window.hxx> +#endif +#ifndef _SV_SVAPP_HXX +#include <svapp.hxx> +#endif +#ifndef _SV_BMPACC_HXX +#include <bmpacc.hxx> +#endif +#ifndef _SV_OUTDEV_HXX +#include <outdev.hxx> +#endif +#ifndef _SV_EDIT_HXX +#include <edit.hxx> +#endif + +#include <unohelp.hxx> + +#ifndef _COM_SUN_STAR_TEXT_XBREAKITERATOR_HPP_ +#include <com/sun/star/text/XBreakIterator.hpp> +#endif + +#ifndef _COM_SUN_STAR_TEXT_WORDTYPE_HPP_ +#include <com/sun/star/text/WordType.hpp> +#endif + +#if defined UNX +#define GLYPH_FONT_HEIGHT 128 +#elif defined OS2 +#define GLYPH_FONT_HEIGHT 176 +#else +#define GLYPH_FONT_HEIGHT 256 +#endif + +#define WSstrcmp strcmp + +// ======================================================================= + +DBG_NAMEEX( OutputDevice ); +DBG_NAMEEX( Font ); + +// ======================================================================= + +#define OUTDEV_CHARCONVERT_REPLACE FALSE + +using namespace ::com::sun::star; +using namespace ::rtl; + + +// ======================================================================= + +#define MAX_DX_WORDS 120 +#define TEXT_DRAW_ELLIPSIS (TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS) + +// ======================================================================= + +#define UNDERLINE_LAST UNDERLINE_BOLDWAVE +#define STRIKEOUT_LAST STRIKEOUT_X + +// ======================================================================= + +void OutputDevice::ImplUpdateFontData( BOOL bNewFontLists ) +{ + if ( mpFontEntry ) + { + mpFontCache->Release( mpFontEntry ); + mpFontEntry = NULL; + } + if ( bNewFontLists ) + { + if ( mpGetDevFontList ) + { + delete mpGetDevFontList; + mpGetDevFontList = NULL; + } + if ( mpGetDevSizeList ) + { + delete mpGetDevSizeList; + mpGetDevSizeList = NULL; + } + } + + if ( GetOutDevType() == OUTDEV_PRINTER ) + { + mpFontCache->Clear(); + + if ( bNewFontLists ) + { +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( ImplGetGraphics() ) +#endif + { + mpFontList->Clear(); + mpGraphics->GetDevFontList( mpFontList ); + mpFontList->InitStdFonts(); + } + } + } + + mbInitFont = TRUE; + mbNewFont = TRUE; + + // Bei Fenstern auch alle Child-Fenster mit updaten + if ( GetOutDevType() == OUTDEV_WINDOW ) + { + Window* pChild = ((Window*)this)->mpFirstChild; + while ( pChild ) + { + pChild->ImplUpdateFontData( TRUE ); + pChild = pChild->mpNext; + } + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplUpdateAllFontData( BOOL bNewFontLists ) +{ + ImplSVData* pSVData = ImplGetSVData(); + + // Alle Fenster updaten + Window* pFrame = pSVData->maWinData.mpFirstFrame; + while ( pFrame ) + { + pFrame->ImplUpdateFontData( bNewFontLists ); + + Window* pSysWin = pFrame->mpFrameData->mpFirstOverlap; + while ( pSysWin ) + { + pSysWin->ImplUpdateFontData( bNewFontLists ); + pSysWin = pSysWin->mpNextOverlap; + } + + pFrame = pFrame->mpFrameData->mpNextFrame; + } + + // Alle VirDev's updaten + VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev; + while ( pVirDev ) + { + pVirDev->ImplUpdateFontData( bNewFontLists ); + pVirDev = pVirDev->mpNext; + } + + // Alle Printer updaten + Printer* pPrinter = pSVData->maGDIData.mpFirstPrinter; + while ( pPrinter ) + { + pPrinter->ImplUpdateFontData( bNewFontLists ); + pPrinter = pPrinter->mpNext; + } + + // Globale Fontlisten leeren, damit diese geupdatet werden + pSVData->maGDIData.mpScreenFontCache->Clear(); + if ( bNewFontLists ) + { + pSVData->maGDIData.mpScreenFontList->Clear(); + pFrame = pSVData->maWinData.mpFirstFrame; + if ( pFrame ) + { +#ifndef REMOTE_APPSERVER + if ( pFrame->ImplGetGraphics() ) +#endif + { + pFrame->mpGraphics->GetDevFontList( pFrame->mpFrameData->mpFontList ); + pFrame->mpFrameData->mpFontList->InitStdFonts(); + } + } + } +} + +// ======================================================================= + +struct ImplFontSubstEntry +{ + XubString maName; + XubString maReplaceName; + XubString maMatchName; + XubString maMatchReplaceName; + USHORT mnFlags; + ImplFontSubstEntry* mpNext; +}; + +// ======================================================================= + +static void ImplStrEraseAllSymbols( XubString& rStr ) +{ + xub_StrLen i = 0; + xub_Unicode c = rStr.GetChar( i ); + while ( c ) + { + // Alle Zeichen kleiner 0 zwischen 9-A, Z-a und z-127 loeschen + if ( (c < 48) || ((c > 57) && (c < 65)) || ((c > 90) && (c < 97)) || + ((c > 122) && (c <= 127)) ) + rStr.Erase( i, 1 ); + else + i++; + c = rStr.GetChar( i ); + } +} + +// ----------------------------------------------------------------------- + +static xub_StrLen ImplStrMatch( const XubString& rStr1, const XubString& rStr2 ) +{ + xub_StrLen nMatch = 0; + const xub_Unicode* pStr1 = rStr1.GetBuffer(); + const xub_Unicode* pStr2 = rStr2.GetBuffer(); + while ( (*pStr1 == *pStr2) && *pStr1 ) + { + pStr1++; + pStr2++; + nMatch++; + } + return nMatch; +} + +// ----------------------------------------------------------------------- + +static int ImplStrFullMatch( const XubString& rStr1, const char* pStr2 ) +{ + const xub_Unicode* pStr1 = rStr1.GetBuffer(); + while ( (*pStr1 == (xub_Unicode)(unsigned char)*pStr2) && *pStr1 ) + { + pStr1++; + pStr2++; + } + return !(*pStr1); +} + +// ======================================================================= + +#if 0 + +#define FONT_ATTR_SYMBOL ((ULONG)0x00000001) +#define FONT_ATTR_FIXED ((ULONG)0x00000002) +#define FONT_ATTR_ITALIC ((ULONG)0x00000004) +#define FONT_ATTR_NORMAL ((ULONG)0x00000008) +#define FONT_ATTR_STANDARD ((ULONG)0x00000010) +#define FONT_ATTR_SPECIAL ((ULONG)0x00000020) +#define FONT_ATTR_TITLING ((ULONG)0x00000040) +#define FONT_ATTR_SERIF ((ULONG)0x00000080) +#define FONT_ATTR_NONSERIF ((ULONG)0x00000100) +#define FONT_ATTR_ROUNDED ((ULONG)0x00000200) +#define FONT_ATTR_OUTLINE ((ULONG)0x00000400) +#define FONT_ATTR_SHADOW ((ULONG)0x00000800) +#define FONT_ATTR_SCRIPT ((ULONG)0x00001000) +#define FONT_ATTR_HANDWRITING ((ULONG)0x00002000) +#define FONT_ATTR_DECORATION ((ULONG)0x00004000) +#define FONT_ATTR_CHARSCRIPT ((ULONG)0x00008000) +#define FONT_ATTR_CHANCERY ((ULONG)0x00010000) +#define FONT_ATTR_OLDSTYLE ((ULONG)0x00020000) +#define FONT_ATTR_FAVOR1 ((ULONG)0x01000000) +#define FONT_ATTR_FAVOR2 ((ULONG)0x02000000) +#define FONT_ATTR_FAVOR3 ((ULONG)0x04000000) +#define FONT_ATTR_FAVOR4 ((ULONG)0x08000000) +#define FONT_ATTR_FOUND ((ULONG)0x80000000) + +struct ImplFontAttrWidthSearchData +{ + const char* mpStr; + FontWidth meWidth; +}; + +static ImplFontAttrWidthSearchData const aImplWidthAttrSearchList[] = +{ +{ "narrow", WIDTH_CONDENSED }, +{ "semicondensed", WIDTH_SEMI_CONDENSED }, +{ "ultracondensed", WIDTH_ULTRA_CONDENSED }, +{ "semiexpanded", WIDTH_SEMI_EXPANDED }, +{ "ultraexpanded", WIDTH_ULTRA_EXPANDED }, +{ "expanded", WIDTH_EXPANDED }, +{ "wide", WIDTH_ULTRA_EXPANDED }, +{ "condensed", WIDTH_CONDENSED }, +{ "cond", WIDTH_CONDENSED }, +{ "cn", WIDTH_CONDENSED }, +{ NULL, WIDTH_DONTKNOW }, +}; + +struct ImplFontAttrWeightSearchData +{ + const char* mpStr; + FontWeight meWeight; +}; + +static ImplFontAttrWeightSearchData const aImplWeightAttrSearchList[] = +{ +{ "extrablack", WEIGHT_BLACK }, +{ "ultrablack", WEIGHT_BLACK }, +{ "black", WEIGHT_BLACK }, +{ "heavy", WEIGHT_BLACK }, +{ "ultrabold", WEIGHT_ULTRABOLD }, +{ "semibold", WEIGHT_SEMIBOLD }, +{ "bold", WEIGHT_BOLD }, +{ "ultralight", WEIGHT_ULTRALIGHT }, +{ "semilight", WEIGHT_SEMILIGHT }, +{ "light", WEIGHT_LIGHT }, +{ "demi", WEIGHT_SEMIBOLD }, +{ "medium", WEIGHT_MEDIUM }, +{ NULL, WEIGHT_DONTKNOW }, +}; + +struct ImplFontAttrTypeSearchData +{ + const char* mpStr; + ULONG mnType; +}; + +static ImplFontAttrTypeSearchData const aImplTypeAttrSearchList[] = +{ +{ "titling", FONT_ATTR_TITLING }, +{ "outline", FONT_ATTR_OUTLINE }, +{ "shadow", FONT_ATTR_SHADOW }, +{ NULL, 0 }, +}; + +// ======================================================================= + +struct ImplFontNameAttr +{ + const char* mpName; + FontFamily meFamily; + FontWeight meWeight; + FontWidth meWidth; + ULONG mnType; +}; + +static const ImplFontNameAttr aImplFullList[] = +{ +{ "Bookman", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_NORMAL | FONT_ATTR_STANDARD | FONT_ATTR_SERIF }, +{ NULL, FAMILY_DONTKNOW,WEIGHT_DONTKNOW,WIDTH_DONTKNOW, 0 } +}; + +static const ImplFontNameAttr aImplMatchList[] = +{ +{ "bookman", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_NORMAL | FONT_ATTR_STANDARD | FONT_ATTR_SERIF }, +{ "comicsansms", FAMILY_SCRIPT, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_NONSERIF | FONT_ATTR_SCRIPT | FONT_ATTR_CHARSCRIPT | FONT_ATTR_FAVOR3 }, +{ "kristenitc", FAMILY_SCRIPT, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_NONSERIF | FONT_ATTR_SCRIPT | FONT_ATTR_CHARSCRIPT | FONT_ATTR_FAVOR3 }, +{ "maiandragd", FAMILY_SCRIPT, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_NONSERIF | FONT_ATTR_SCRIPT | FONT_ATTR_CHARSCRIPT | FONT_ATTR_FAVOR3 }, +{ "arioso", FAMILY_SCRIPT, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_NONSERIF | FONT_ATTR_SCRIPT | FONT_ATTR_ITALIC | FONT_ATTR_DECORATION | FONT_ATTR_OLDSTYLE | FONT_ATTR_FAVOR3 }, +{ "tempussansitc", FAMILY_SCRIPT, WEIGHT_LIGHT, WIDTH_NORMAL, FONT_ATTR_NONSERIF | FONT_ATTR_SCRIPT | FONT_ATTR_CHARSCRIPT }, +{ "papyrus", FAMILY_SCRIPT, WEIGHT_LIGHT, WIDTH_NORMAL, FONT_ATTR_NONSERIF | FONT_ATTR_SCRIPT | FONT_ATTR_CHARSCRIPT }, +{ "lucidashadowtitling", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_TITLING | FONT_ATTR_OUTLINE | FONT_ATTR_SHADOW }, +{ "lucidaopenboldtitling",FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_TITLING | FONT_ATTR_OUTLINE }, +{ "lucidaopentitling", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_TITLING | FONT_ATTR_OUTLINE }, +{ "lucidaopen", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_OUTLINE }, +{ "lucidashadow", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_OUTLINE | FONT_ATTR_SHADOW }, +{ "chevara", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_EXPANDED, FONT_ATTR_SERIF | FONT_ATTR_TITLING | FONT_ATTR_OUTLINE }, +{ "colonnamt", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_SPECIAL | FONT_ATTR_OUTLINE }, +{ "imprintmtshadow", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_OUTLINE | FONT_ATTR_SHADOW }, +{ "castellar", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_TITLING | FONT_ATTR_OUTLINE }, +{ "algerian", FAMILY_ROMAN, WEIGHT_NORMAL, WIDTH_NORMAL, FONT_ATTR_SERIF | FONT_ATTR_SPECIAL | FONT_ATTR_TITLING | FONT_ATTR_OUTLINE | FONT_ATTR_SHADOW | FONT_ATTR_OLDSTYLE }, +{ NULL, FAMILY_DONTKNOW,WEIGHT_DONTKNOW,WIDTH_DONTKNOW, 0 } +}; + +#endif + +static const char* aImplSwissMatchList[] = +{ + "arial", + "avantgarde", + "cgomega", + "centurygothic", + "charcoal", + "chicago", + "frutiger", + "geneva", + "haettenschweiler", + "helmet", + "helv", + "lucida", + "impact", + "tahoma", + "univers", + "vagrounded", + "verdana", + NULL +}; + +static const char* aImplSwissSearchList[] = +{ + "sansserif", + "swiss", + NULL +}; + +static const char* aImplRomanMatchList[] = +{ + "algerian", + "antiqua", + "caliso", + "clarendon", + "colonna", + "garamond", + "newyork", + "palatino", + "timmons", + NULL +}; + +static const char* aImplRomanSearchList[] = +{ + "book", + "times", + "roman", + "bright", + NULL +}; + +static const char* aImplFixedMatchList[] = +{ + "lineprinter", + "monaco", + "typewriter", + NULL +}; + +static const char* aImplFixedSearchList[] = +{ + "console", + "courier", + "fixed", + "letter", + "monospace", + "terminal", + NULL +}; + +static const char* aImplScriptMatchList[] = +{ + "arioso", + "coronet", + "cursive", + "marigold", + "zapfchancery", + NULL +}; + +static const char* aImplScriptSearchList[] = +{ + "script", + "signet", + "handwriting", + "calligraphy", + NULL +}; + +static const char* aImplSymbolMatchList[] = +{ + "marlett", + "monotypesorts", + "msoutlook", + NULL +}; + +static const char* aImplSymbolSearchList[] = +{ + "symbol", + "bats", + "dings", + "math", + NULL +}; + +static const char* aImplTypeList[] = +{ + "black", + "bold", + "condensed", + "expanded", + "narrow", + "outline", + NULL +}; + +// ======================================================================= + +static const char* aImplSearchScriptList[] = +{ + "ce", + "we", + "cyr", + "tur", + "wt", + "greek", + "wl", + NULL +}; + +// ----------------------------------------------------------------------- + +struct ImplScriptSearchList +{ + const char* mpScript; + rtl_Script meScript; +}; + +static void ImplCutScriptAndSpaces( XubString& rName ) +{ + rName.EraseLeadingAndTrailingChars( ' ' ); + + USHORT nLen = rName.Len(); + if ( nLen < 3 ) + return; + + // Scriptname must be the last part of the fontname and + // looks like "fontname (scriptname)". So there can only be a + // script name at the and of the fontname, when the last char is + // ')'. + if ( rName.GetChar( nLen-1 ) == ')' ) + { + int nOpen = 1; + nLen -= 2; + while ( nLen ) + { + if ( rName.GetChar( nLen ) == '(' ) + { + nOpen--; + if ( !nOpen && nLen && (rName.GetChar( nLen-1 ) == ' ') ) + { + XubString aScript = rName.Copy( nLen+1, rName.Len()-1-nLen-1 ); + rName.Erase( nLen-1 ); + return; + } + } + if ( rName.GetChar( nLen ) == ')' ) + nOpen++; + nLen--; + } + } + + // For compatibility with older version we must search for a + // script name at the end of a fontname without brakets + USHORT nSpacePos = rName.SearchBackward( ' ' ); + if ( nSpacePos && (nSpacePos != STRING_NOTFOUND) ) + { + XubString aScript = rName.Copy( nSpacePos+1 ); + const char** pScript = aImplSearchScriptList; + while ( *pScript ) + { + if ( aScript.EqualsAscii( *pScript ) ) + { + rName.Erase( nSpacePos ); + break; + } + pScript++; + } + } +} + +// ======================================================================= + +#if 0 + +static const ImplFontNameAttr* ImplFindFontAttr( const XubString& rFontName ) +{ + const ImplFontNameAttr* pList; + + pList = aImplFullList; + while ( pList->mpName ) + { + if ( rFontName.EqualsAscii( pList->mpName ) ) + return pList; + pList++; + } + + pList = aImplMatchList; + while ( pList->mpName ) + { + if ( ImplStrFullMatch( rFontName, pList->mpName ) ) + return pList; + pList++; + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +static void ImplGetFontAttr( const XubString& rFontName, + FontFamily& rFamily, CharSet& rCharSet, + FontPitch& rPitch ) +{ + if ( (rFamily == FAMILY_DONTKNOW) || (rPitch == PITCH_DONTKNOW) || + (rCharSet == CHARSET_DONTKNOW) ) + { + } +} + +#endif + +// ======================================================================= + +BOOL ImplTestFontName( const XubString& rName, + const sal_Char** pMatchList, + const sal_Char** pSearchList ) +{ + const char** pAlias; + + pAlias = pMatchList; + while ( *pAlias ) + { + if ( ImplStrFullMatch( rName, *pAlias ) ) + return TRUE; + pAlias++; + } + + pAlias = pSearchList; + while ( *pAlias ) + { + if ( rName.SearchAscii( *pAlias ) != STRING_NOTFOUND ) + return TRUE; + pAlias++; + } + + return FALSE; +} + +// ======================================================================= + +static void ImplFontAttrFromName( const XubString& rFontName, + FontFamily& rFamily, CharSet& rCharSet, + FontPitch& rPitch ) +{ + if ( rFamily == FAMILY_DONTKNOW ) + { + if ( ImplTestFontName( rFontName, aImplRomanMatchList, aImplRomanSearchList ) ) + rFamily = FAMILY_ROMAN; + else if ( ImplTestFontName( rFontName, aImplSwissMatchList, aImplSwissSearchList ) ) + rFamily = FAMILY_SWISS; + else if ( ImplTestFontName( rFontName, aImplScriptMatchList, aImplScriptSearchList ) ) + rFamily = FAMILY_SCRIPT; + } + + if ( rPitch == PITCH_DONTKNOW ) + { + if ( ImplTestFontName( rFontName, aImplFixedMatchList, aImplFixedSearchList ) ) + rPitch = PITCH_FIXED; + } + + if ( rCharSet == RTL_TEXTENCODING_DONTKNOW ) + { + if ( ImplTestFontName( rFontName, aImplSymbolMatchList, aImplSymbolSearchList ) ) + rCharSet = RTL_TEXTENCODING_SYMBOL; + } +} + +// ======================================================================= + +static const char* aImplStdSwissList[] = +{ + "helvetica", + "arial", + "lucida sans", + "lucidasans", + "lucida", + "geneva", + "helmet", + NULL +}; + +static const char* aImplStdRomanList[] = +{ + "times", + "times new roman", + "timesnewroman", + "roman", + "lucida serif", + "lucidaserif", + "lucida bright", + "lucidabright", + "bookman", + "garamond", + "timmons", + NULL +}; + +static const char* aImplStdFixedList[] = +{ + "courier", + "courier new", + "lucida typewriter", + "lucidatypewriter", + "lucida sans typewriter", + "lucidasanstypewriter", + NULL +}; + +static const char* aImplStdScriptList[] = +{ + "zapf chancery", + "zapfchancery", + "lucida calligraphy", + "lucidacalligraphy", + "lucida handwriting", + "lucidahandwriting", + "arioso", + "script", + "marigold", + NULL +}; + +static const char* aImplStdSymbolList[] = +{ + "starbats", + "symbol", + "zapf dingbats", + "zapfdingbats", + "wingdings", + "lucida dingbats", + "lucidadingbats", + "lucida sans dingbats", + "lucidasansdingbats", + NULL +}; + +// ======================================================================= + +void ImplFreeOutDevFontData() +{ + ImplSVData* pSVData = ImplGetSVData(); + ImplFontSubstEntry* pEntry = pSVData->maGDIData.mpFirstFontSubst; + while ( pEntry ) + { + ImplFontSubstEntry* pNext = pEntry->mpNext; + delete pEntry; + pEntry = pNext; + } +} + +// ======================================================================= + +static ImplFontData* ImplFindScript( ImplDevFontListData* pData, + rtl_Script eScript ) +{ + // Testen, ob ein Font mit einem entsprechendem + // Script vorhanden ist + ImplFontData* pCurFontData = pData->mpFirst; + while ( pCurFontData ) + { + // Detect Unicode Font !!! + if ( pData->maMatchName.EqualsAscii( "arial unicode ms" ) ) + return pCurFontData; + if ( eScript == pCurFontData->meScript ) + return pCurFontData; + pCurFontData = pCurFontData->mpNext; + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +/* !!! UNICODE - Duerfte nicht mehr gebraucht werden !!! +static rtl_TextEncoding ImplGetFakeEncoding( rtl_TextEncoding eEncoding ) +{ + rtl_TextEncoding eSystemEncoding = GetSystemCharSet(); + // MS_1252 und 8859_1 sind kompatible + if ( ((eEncoding == RTL_TEXTENCODING_MS_1252) || + (eEncoding == RTL_TEXTENCODING_ISO_8859_1)) && + ((eSystemEncoding == RTL_TEXTENCODING_MS_1252) || + (eSystemEncoding == RTL_TEXTENCODING_ISO_8859_1)) ) + return eEncoding; + else + { + // Wir testen, ob beide Zeichensaetze dem gleichem Script + // entsprechen, um so der Applikation das gleiche Encoding + // vorzugaukeln. Dies ist beispielsweise bei Russisch wichtig + // da hier Fonts mit unterschiedlichem Encoding auftauchen + // koennen. + rtl_Script eSrcScript; + rtl_Script eSystemScript; + rtl_TextEncodingInfo aTEncInfo; + aTEncInfo.StructSize = sizeof( aTEncInfo ); + aTEncInfo.Script = SCRIPT_DONTKNOW; + if ( !rtl_getTextEncodingInfo( eEncoding, &aTEncInfo ) ) + return eEncoding; + else + eSrcScript = aTEncInfo.Script; + aTEncInfo.Script = SCRIPT_DONTKNOW; + if ( !rtl_getTextEncodingInfo( eSystemEncoding, &aTEncInfo ) ) + return eEncoding; + else + eSystemScript = aTEncInfo.Script; + if ( eSrcScript == eSystemScript ) + eEncoding = eSystemEncoding; + } + + return eEncoding; +} +*/ + +// ======================================================================= + +void OutputDevice::BeginFontSubstitution() +{ + ImplSVData* pSVData = ImplGetSVData(); + pSVData->maGDIData.mbFontSubChanged = FALSE; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::EndFontSubstitution() +{ + ImplSVData* pSVData = ImplGetSVData(); + if ( pSVData->maGDIData.mbFontSubChanged ) + { + ImplUpdateAllFontData( FALSE ); + + Application* pApp = GetpApp(); + DataChangedEvent aDCEvt( DATACHANGED_FONTSUBSTITUTION ); + pApp->DataChanged( aDCEvt ); + pApp->NotifyAllWindows( aDCEvt ); + pSVData->maGDIData.mbFontSubChanged = FALSE; + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::AddFontSubstitute( const XubString& rFontName, + const XubString& rReplaceFontName, + USHORT nFlags ) +{ + ImplSVData* pSVData = ImplGetSVData(); + ImplFontSubstEntry* pEntry = new ImplFontSubstEntry; + + pEntry->maName = rFontName; + pEntry->maReplaceName = rReplaceFontName; + pEntry->maMatchName = rFontName; + pEntry->maMatchReplaceName = rReplaceFontName; + pEntry->mnFlags = nFlags; + pEntry->mpNext = pSVData->maGDIData.mpFirstFontSubst; + pEntry->maMatchName.ToLowerAscii(); + pEntry->maMatchReplaceName.ToLowerAscii(); + ImplCutScriptAndSpaces( pEntry->maMatchName ); + ImplCutScriptAndSpaces( pEntry->maMatchReplaceName ); + pSVData->maGDIData.mpFirstFontSubst = pEntry; + pSVData->maGDIData.mbFontSubChanged = TRUE; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::RemoveFontSubstitute( USHORT n ) +{ + ImplSVData* pSVData = ImplGetSVData(); + ImplFontSubstEntry* pEntry = pSVData->maGDIData.mpFirstFontSubst; + ImplFontSubstEntry* pPrev = NULL; + USHORT nCount = 0; + while ( pEntry ) + { + if ( nCount == n ) + { + pSVData->maGDIData.mbFontSubChanged = TRUE; + if ( pPrev ) + pPrev->mpNext = pEntry->mpNext; + else + pSVData->maGDIData.mpFirstFontSubst = pEntry->mpNext; + delete pEntry; + break; + } + + nCount++; + pPrev = pEntry; + pEntry = pEntry->mpNext; + } +} + +// ----------------------------------------------------------------------- + +USHORT OutputDevice::GetFontSubstituteCount() +{ + ImplSVData* pSVData = ImplGetSVData(); + ImplFontSubstEntry* pEntry = pSVData->maGDIData.mpFirstFontSubst; + USHORT nCount = 0; + while ( pEntry ) + { + nCount++; + pEntry = pEntry->mpNext; + } + + return nCount; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::GetFontSubstitute( USHORT n, + XubString& rFontName, + XubString& rReplaceFontName, + USHORT& rFlags ) +{ + ImplSVData* pSVData = ImplGetSVData(); + ImplFontSubstEntry* pEntry = pSVData->maGDIData.mpFirstFontSubst; + USHORT nCount = 0; + while ( pEntry ) + { + if ( nCount == n ) + { + rFontName = pEntry->maName; + rReplaceFontName = pEntry->maReplaceName; + rFlags = pEntry->mnFlags; + break; + } + + nCount++; + pEntry = pEntry->mpNext; + } +} + +// ----------------------------------------------------------------------- + +static BOOL ImplFontSubstitute( XubString& rFontName, + USHORT nFlags1, USHORT nFlags2 ) +{ + ImplSVData* pSVData = ImplGetSVData(); + ImplFontSubstEntry* pEntry = pSVData->maGDIData.mpFirstFontSubst; + while ( pEntry ) + { + if ( ((pEntry->mnFlags & nFlags1) == nFlags2) && + (pEntry->maMatchName == rFontName) ) + { + rFontName = pEntry->maMatchReplaceName; + return TRUE; + } + + pEntry = pEntry->mpNext; + } + + return FALSE; +} + +// ======================================================================= + +ImplDevFontList::ImplDevFontList() : + List( CONTAINER_MAXBLOCKSIZE, 96, 32 ) +{ +#if 0 + mbIsInitMatchData = FALSE; +#endif +} + +// ----------------------------------------------------------------------- + +ImplDevFontList::~ImplDevFontList() +{ + // Alle Eintraege loeschen + ImplDevFontListData* pEntry = First(); + while ( pEntry ) + { + // Liste der Font loeschen + ImplFontData* pFontData = pEntry->mpFirst; + do + { + ImplFontData* pTempFontData = pFontData; + pFontData = pFontData->mpNext; + delete pTempFontData; + } + while ( pFontData ); + // Entry loeschen + delete pEntry; + + pEntry = Next(); + } +} + +// ----------------------------------------------------------------------- + +static StringCompare ImplCompareFontDataWithoutSize( const ImplFontData* pEntry1, + const ImplFontData* pEntry2 ) +{ + // Vergleichen nach CharSet, Groesse, Breite, Weight, Italic, StyleName + if ( pEntry1->meCharSet < pEntry2->meCharSet ) + return COMPARE_LESS; + else if ( pEntry1->meCharSet > pEntry2->meCharSet ) + return COMPARE_GREATER; + + if ( pEntry1->meWidthType < pEntry2->meWidthType ) + return COMPARE_LESS; + else if ( pEntry1->meWidthType > pEntry2->meWidthType ) + return COMPARE_GREATER; + + if ( pEntry1->meWeight < pEntry2->meWeight ) + return COMPARE_LESS; + else if ( pEntry1->meWeight > pEntry2->meWeight ) + return COMPARE_GREATER; + + if ( pEntry1->meItalic < pEntry2->meItalic ) + return COMPARE_LESS; + else if ( pEntry1->meItalic > pEntry2->meItalic ) + return COMPARE_GREATER; + + return pEntry1->maStyleName.CompareTo( pEntry2->maStyleName ); +} + +// ----------------------------------------------------------------------- + +static StringCompare ImplCompareFontData( const ImplFontData* pEntry1, + const ImplFontData* pEntry2 ) +{ + StringCompare eComp = ImplCompareFontDataWithoutSize( pEntry1, pEntry2 ); + if ( eComp != COMPARE_EQUAL ) + return eComp; + + if ( pEntry1->mnHeight < pEntry2->mnHeight ) + return COMPARE_LESS; + else if ( pEntry1->mnHeight > pEntry2->mnHeight ) + return COMPARE_GREATER; + + if ( pEntry1->mnWidth < pEntry2->mnWidth ) + return COMPARE_LESS; + else if ( pEntry1->mnWidth > pEntry2->mnWidth ) + return COMPARE_GREATER; + + return COMPARE_EQUAL; +} + +// ----------------------------------------------------------------------- + +void ImplDevFontList::Add( ImplFontData* pNewData ) +{ + XubString aSearchName = pNewData->maName; + aSearchName.ToLowerAscii(); + + // Query Script for FontTest + rtl_TextEncodingInfo aTEncInfo; + aTEncInfo.StructSize = sizeof( aTEncInfo ); + aTEncInfo.Script = SCRIPT_DONTKNOW; + rtl_getTextEncodingInfo( pNewData->meCharSet, &aTEncInfo ); + pNewData->meScript = aTEncInfo.Script; + + // Add Font + ULONG nIndex; + ImplDevFontListData* pFoundData = ImplFind( aSearchName, &nIndex ); + BOOL bDelete = FALSE; + + if ( !pFoundData ) + { + pFoundData = new ImplDevFontListData; + pFoundData->maName = pNewData->maName; + pFoundData->maMatchName = aSearchName; + pFoundData->maMatchName2 = aSearchName; + pFoundData->mpFirst = pNewData; +#if 0 + pFoundData->mbScalable = FALSE; + ImplStrEraseAllSymbols( pFoundData->maMatchName2 ); +/* + pFoundData->meMatchFamily = pNewData->meFamily; + pFoundData->meMatchPitch = pNewData->mePitch; + CharSet eCharSet = pNewData->meCharSet; + ImplFontAttrFromName( pFoundData->maMatchName2, pFoundData->meMatchFamily, + eCharSet, pFoundData->meMatchPitch ); + pFoundData->mbSymbol = eCharSet == RTL_TEXTENCODING_SYMBOL; +*/ +#else + pFoundData->meMatchFamily = pNewData->meFamily; + pFoundData->meMatchPitch = pNewData->mePitch; + pFoundData->mnMatch = 0; + CharSet eCharSet = pNewData->meCharSet; + ImplStrEraseAllSymbols( pFoundData->maMatchName2 ); + ImplFontAttrFromName( pFoundData->maMatchName2, pFoundData->meMatchFamily, + eCharSet, pFoundData->meMatchPitch ); + pFoundData->mbSymbol = eCharSet == RTL_TEXTENCODING_SYMBOL; +#endif + + pNewData->mpNext = NULL; + Insert( pFoundData, nIndex ); + } + else + { + // Name ersetzen (spart Speicherplatz) + pNewData->maName = pFoundData->maName; + + BOOL bInsert = TRUE; + ImplFontData* pPrev = NULL; + ImplFontData* pTemp = pFoundData->mpFirst; + do + { + StringCompare eComp = ImplCompareFontData( pNewData, pTemp ); + if ( eComp != COMPARE_GREATER ) + { + // Wenn Font gleich ist, nehmen wir einen Devicefont, + // oder ignorieren den Font + if ( eComp == COMPARE_EQUAL ) + { + // Wir nehmen den Font mit der besseren Quality, + // ansonsten ziehen wir den Device-Font vor + if ( (pNewData->mnQuality > pTemp->mnQuality) || + ((pNewData->mnQuality == pTemp->mnQuality) && + (pNewData->mbDevice && !pTemp->mbDevice)) ) + { + pNewData->mpNext = pTemp->mpNext; + if ( pPrev ) + pPrev->mpNext = pNewData; + else + pFoundData->mpFirst = pNewData; + delete pTemp; + } + else + { + bDelete = TRUE; + delete pNewData; + } + + bInsert = FALSE; + } + break; + } + + pPrev = pTemp; + pTemp = pTemp->mpNext; + } + while ( pTemp ); + + if ( bInsert ) + { + pNewData->mpNext = pTemp; + if ( pPrev ) + pPrev->mpNext = pNewData; + else + pFoundData->mpFirst = pNewData; + } + } + + // Match zusammenzaehlen + if ( !bDelete ) + { +#if 0 + if ( (pNewData->meType == TYPE_SCALABLE) && (pNewData->mnHeight == 0) ) + pFoundData->mbScalable = TRUE; +#else + if ( (pNewData->meType == TYPE_SCALABLE) && (pNewData->mnHeight == 0) ) + { + if ( pNewData->meWidthType == WIDTH_NORMAL ) + pFoundData->mnMatch += 30; + else + pFoundData->mnMatch += 3; + if ( pNewData->meItalic == ITALIC_NONE ) + pFoundData->mnMatch += 20; + else + pFoundData->mnMatch += 2; + if ( (pNewData->meWeight == WEIGHT_NORMAL) || (pNewData->meWeight == WEIGHT_MEDIUM) ) + pFoundData->mnMatch += 10; + else + pFoundData->mnMatch += 1; + } +#endif + } +} + +// ----------------------------------------------------------------------- + +ImplDevFontListData* ImplDevFontList::ImplFind( const XubString& rFontName, ULONG* pIndex ) const +{ + ULONG nCount = Count(); + if ( !nCount ) + { + if ( pIndex ) + *pIndex = LIST_APPEND; + return NULL; + } + + // Fonts in der Liste suchen + ImplDevFontListData* pCompareData; + ImplDevFontListData* pFoundData = NULL; + ULONG nLow = 0; + ULONG nHigh = nCount-1; + ULONG nMid; + StringCompare eCompare; + + do + { + nMid = (nLow + nHigh) / 2; + pCompareData = Get( nMid ); + eCompare = rFontName.CompareTo( pCompareData->maMatchName ); + if ( eCompare == COMPARE_LESS ) + { + if ( !nMid ) + break; + nHigh = nMid-1; + } + else + { + if ( eCompare == COMPARE_GREATER ) + nLow = nMid + 1; + else + { + pFoundData = pCompareData; + break; + } + } + } + while ( nLow <= nHigh ); + + if ( pIndex ) + { + eCompare = rFontName.CompareTo( pCompareData->maMatchName ); + if ( eCompare == COMPARE_GREATER ) + *pIndex = (nMid+1); + else + *pIndex = nMid; + } + + return pFoundData; +} + +// ----------------------------------------------------------------------- + +ImplDevFontListData* ImplDevFontList::FindFont( const XubString& rFontName ) const +{ + XubString aName = rFontName; + aName.ToLowerAscii(); + ImplCutScriptAndSpaces( aName ); + return ImplFind( aName ); +} + +// ----------------------------------------------------------------------- + +ImplDevFontListData* ImplDevFontList::FindStdFont( const sal_Char** pStdFontNames, + rtl_Script eScript ) const +{ + // We want a scalable font with a system script + ImplDevFontListData* pRasterFoundData = NULL; + ImplDevFontListData* pWrongScriptRasterData = NULL; + ImplDevFontListData* pWrongScriptData = NULL; + while ( *pStdFontNames ) + { + XubString aStdName( *pStdFontNames, RTL_TEXTENCODING_ASCII_US ); + ImplDevFontListData* pFoundData = ImplFind( aStdName ); + if ( pFoundData ) + { + if ( (eScript == SCRIPT_SYMBOL) || + ImplFindScript( pFoundData, eScript ) ) + { + if ( pFoundData->mpFirst->meType != TYPE_RASTER ) + return pFoundData; + else if ( !pRasterFoundData ) + pRasterFoundData = pFoundData; + } + else + { + if ( pFoundData->mpFirst->meType != TYPE_RASTER ) + { + if ( !pWrongScriptData ) + pWrongScriptData = pFoundData; + } + else + { + if ( !pWrongScriptRasterData ) + pWrongScriptRasterData = pFoundData; + } + } + } + pStdFontNames++; + } + + // Wenn keine passende Schrift, dann die Reihenfolge: + // - passender Zeichensatz + // - Skalierbar + // - eine passende Schrift die nicht skalierbar und den + // falschen Zeichensatz hat + // - keine + if ( pRasterFoundData ) + return pRasterFoundData; + else if ( pWrongScriptData ) + return pWrongScriptData; + else + return pWrongScriptRasterData; +} + +// ----------------------------------------------------------------------- + +void ImplDevFontList::Clear() +{ + // Alle Eintraege loeschen + ImplDevFontListData* pEntry = First(); + while ( pEntry ) + { + // Liste der Font loeschen + ImplFontData* pFontData = pEntry->mpFirst; + do + { + ImplFontData* pTempFontData = pFontData; + pFontData = pFontData->mpNext; + delete pTempFontData; + } + while ( pFontData ); + // Entry loeschen + delete pEntry; + + pEntry = Next(); + } + List::Clear(); + + // Standard-Fonts loeschen + for ( USHORT i = 0; i < IMPL_STDFONT_COUNT; i++ ) + mpStdFontAry[i] = NULL; +#if 0 + mbIsInitMatchData = FALSE; +#endif +} + +// ----------------------------------------------------------------------- + +#if 0 +void ImplDevFontList::InitMatchData() +{ + if ( mbIsInitMatchData ) + return; + mbIsInitMatchData = TRUE; +/* + // Fuer alle Eintraege die Matchdaten ermitteln + ImplDevFontListData* pEntry = First(); + while ( pEntry ) + { + ImplFontData* pFontData = pEntry->mpFirst; + + pEntry = Next(); + } +*/ +} +#endif + +// ----------------------------------------------------------------------- + +void ImplDevFontList::InitStdFonts() +{ + rtl_Script eSystemScript; + rtl_TextEncodingInfo aTextEncInfo; + aTextEncInfo.StructSize = sizeof( aTextEncInfo ); + aTextEncInfo.Script = SCRIPT_DONTKNOW; + rtl_getTextEncodingInfo( gsl_getSystemTextEncoding(), &aTextEncInfo ); + eSystemScript = aTextEncInfo.Script; + + mpStdFontAry[IMPL_STDFONT_SWISS] = FindStdFont( aImplStdSwissList, eSystemScript ); + mpStdFontAry[IMPL_STDFONT_ROMAN] = FindStdFont( aImplStdRomanList, eSystemScript ); + mpStdFontAry[IMPL_STDFONT_FIXED] = FindStdFont( aImplStdFixedList, eSystemScript ); + mpStdFontAry[IMPL_STDFONT_SCRIPT] = FindStdFont( aImplStdScriptList, eSystemScript ); + mpStdFontAry[IMPL_STDFONT_SYMBOL] = FindStdFont( aImplStdSymbolList, SCRIPT_SYMBOL ); +} + +// ======================================================================= + +void ImplGetDevSizeList::Add( long nNewHeight ) +{ + ULONG n = Count(); + if ( !n || (nNewHeight > Get( n-1 )) ) + Insert( (void*)nNewHeight, LIST_APPEND ); + else + { + for ( ULONG i=0 ; i < n; i++ ) + { + long nHeight = Get( i ); + + if ( nNewHeight <= nHeight ) + { + if ( nNewHeight != nHeight ) + Insert( (void*)nNewHeight, i ); + break; + } + } + } +} + +// ======================================================================= + +ImplFontEntry::~ImplFontEntry() +{ + if ( mpWidthAry ) + delete mpWidthAry; + + if ( mpKernPairs ) + delete mpKernPairs; + + if ( mpKernInfo ) + delete mpKernInfo; +} + +// ======================================================================= + +ImplFontCache::ImplFontCache( BOOL bPrinter ) +{ + mpFirstEntry = NULL; + mnRef0Count = 0; + mbPrinter = bPrinter; +} + +// ----------------------------------------------------------------------- + +ImplFontCache::~ImplFontCache() +{ + // Alle Eintraege loeschen + ImplFontEntry* pTemp; + ImplFontEntry* pEntry = mpFirstEntry; + while ( pEntry ) + { + pTemp = pEntry->mpNext; + delete pEntry; + pEntry = pTemp; + } +} + +// ----------------------------------------------------------------------- + +ImplFontEntry* ImplFontCache::Get( ImplDevFontList* pFontList, + const Font& rFont, const Size& rSize ) +{ + const XubString& rName = rFont.GetName(); + const XubString& rStyleName = rFont.GetStyleName(); + long nWidth = rSize.Width(); + long nHeight = rSize.Height(); + FontFamily eFamily = rFont.GetFamily(); + CharSet eCharSet = rFont.GetCharSet(); + FontWeight eWeight = rFont.GetWeight(); + FontItalic eItalic = rFont.GetItalic(); + FontPitch ePitch = rFont.GetPitch(); + short nOrientation = (short)(rFont.GetOrientation() % 3600); + BOOL bShadow = rFont.IsShadow(); + BOOL bOutline = rFont.IsOutline(); + + // Groesse anpassen + if ( nHeight < 0 ) + nHeight = -nHeight; + if ( nWidth < 0 ) + nWidth = -nWidth; + + // Eintrag suchen + ImplFontEntry* pPrevEntry = NULL; + ImplFontEntry* pEntry = mpFirstEntry; + while ( pEntry ) + { + ImplFontSelectData* pFontSelData = &(pEntry->maFontSelData); + if ( (nHeight == pFontSelData->mnHeight) && + (eWeight == pFontSelData->meWeight) && + (eItalic == pFontSelData->meItalic) && + (rName == pFontSelData->maName) && + (rStyleName == pFontSelData->maStyleName) && + (eCharSet == pFontSelData->meCharSet) && + (eFamily == pFontSelData->meFamily) && + (ePitch == pFontSelData->mePitch) && + (nWidth == pFontSelData->mnWidth) && + (nOrientation == pFontSelData->mnOrientation) ) + { + if ( !pEntry->mnRefCount ) + mnRef0Count--; + + pEntry->mnRefCount++; + + // Entry nach vorne bringen + if ( pPrevEntry ) + { + pPrevEntry->mpNext = pEntry->mpNext; + pEntry->mpNext = mpFirstEntry; + mpFirstEntry = pEntry; + } + + return pEntry; + } + + pPrevEntry = pEntry; + pEntry = pEntry->mpNext; + } + + // Wir suchen zuerst ueber den Namen den passenden Font + XubString aLowerFontName = rName; + XubString aFirstName; + XubString aTempName; + XubString aTempName2; + ImplDevFontListData* pFoundData; + ImplDevFontListData* pTempFoundData; + xub_StrLen nFirstNameIndex = 0; + xub_StrLen nIndex = 0; + USHORT nSubstFlags1 = FONT_SUBSTITUTE_ALWAYS; + USHORT nSubstFlags2 = FONT_SUBSTITUTE_ALWAYS; + rtl_Script eScript = SCRIPT_DONTKNOW; + rtl_Script eCharSetScript; + rtl_TextEncodingInfo aTextEncInfo; + aTextEncInfo.StructSize = sizeof( aTextEncInfo ); + aTextEncInfo.Script = SCRIPT_DONTKNOW; + rtl_getTextEncodingInfo( eCharSet, &aTextEncInfo ); + eCharSetScript = aTextEncInfo.Script; + if ( mbPrinter ) + nSubstFlags1 |= FONT_SUBSTITUTE_SCREENONLY; + aLowerFontName.ToLowerAscii(); + pTempFoundData = NULL; + do + { + aTempName = aLowerFontName.GetToken( 0, ';', nIndex ); + ImplCutScriptAndSpaces( aTempName ); + if ( !aFirstName.Len() ) + { + aFirstName = aTempName; + nFirstNameIndex = nIndex; + } + ImplFontSubstitute( aTempName, nSubstFlags1, nSubstFlags2 ); + pFoundData = pFontList->ImplFind( aTempName ); + if ( pFoundData ) + { + if ( eCharSetScript != SCRIPT_DONTKNOW ) + { + if ( !pTempFoundData ) + { + aTempName2 = aTempName; + pTempFoundData = pFoundData; + } + + // Testen, ob ein Font mit einem entsprechendem + // Script vorhanden ist + if ( ImplFindScript( pFoundData, eCharSetScript ) ) + { + aLowerFontName = aTempName; + break; + } + else + pFoundData = NULL; + } + else + { + aLowerFontName = aTempName; + break; + } + } + } + while ( nIndex != STRING_NOTFOUND ); + if ( !pFoundData && pTempFoundData ) + { + pFoundData = pTempFoundData; + aLowerFontName = aTempName2; + } + + // Danach versuchen wir es nocheinmal unter Beruecksichtigung + // der gloablen Fontersetzungstabelle, wobei wir jetzt auch + // die Fonts nehmen, die ersetzt werden sollen, wenn sie + // nicht vorhanden sind + if ( !pFoundData ) + { + nSubstFlags1 &= ~FONT_SUBSTITUTE_ALWAYS; + nSubstFlags2 &= ~FONT_SUBSTITUTE_ALWAYS; + nIndex = 0; + do + { + aTempName = aLowerFontName.GetToken( 0, ';', nIndex ); + ImplCutScriptAndSpaces( aTempName ); + if ( ImplFontSubstitute( aTempName, nSubstFlags1, nSubstFlags2 ) ) + { + pFoundData = pFontList->ImplFind( aTempName ); + if ( pFoundData ) + { + aLowerFontName = aTempName; + break; + } + } + } + while ( nIndex != STRING_NOTFOUND ); + } + + // Wenn kein Font mit dem entsprechenden Namen existiert, versuchen + // wir ueber den Namen und die Attribute einen passenden Font zu + // finden + ULONG nFontCount = pFontList->Count(); + if ( !pFoundData && nFontCount ) + { +#if 0 + pFontList->InitMatchData(); + + // 1. Token vom Fontnamen nehmen und Sonderzeichen entfernen + XubString aNoSymbolName = aFirstName; + ImplCutScriptAndSpaces( aNoSymbolName ); + ImplStrEraseAllSymbols( aNoSymbolName ); + + // Script evtl. aus CharSet gewinnen, wenn nicht ueber den Fontnamen + // ermittelt werden konnte + if ( eScript == SCRIPT_DONTKNOW ) + eScript = eCharSetScript; + + // wir versuchen zuerst einen Font zu finden, der ueber den Namen + // matched + ULONG nTestMatch; + ULONG nBestMatch = 0; + for ( ULONG i = 0; i < nFontCount; i++ ) + { + ImplDevFontListData* pData = pFontList->Get( i ); + + nTestMatch = 0; + + // Wir wollen schon Zeichen erkennen + if ( eScript != SCRIPT_DONTKNOW ) + { + if ( ImplFindScript( pData, eScript ) ) + nTestMatch += 1000000000; + } + + // skalierbare Schriften haben schon einen echten Vorteil + // gegenueber nicht skalierbaren Schriften + if ( pData->mbScalable ) + nTestMatch += 500000000; + +/* + // Wir gehen davon aus, wenn der Name groesstenteils matcht, + // das er schon zur richtigen Familie gehoert + + + // Beim matchen ignorieren wir alle Sonderzeichen + ULONG nTestMatch = ImplStrMatch( aNoSymbolName, pData->maMatchName2 ); + if ( nTestMatch >= nBestMatch ) + { + // Match nur erlaubt, wenn auch die Attribute uebereinstimmen + BOOL bTestFamily = pData->meMatchFamily != FAMILY_DONTKNOW; + BOOL bTestSymbol = pData->mbSymbol; + BOOL bTestFixed = pData->meMatchPitch == PITCH_FIXED; + if ( (bFixed == bTestFixed) && (bSymbol == bTestSymbol) && + (!bFamily || !bTestFamily || (eSearchFamily == pData->meMatchFamily)) ) + { + xub_StrLen nAttrMatch = 0; + // Die Anzahl der uebereinstimmenden Attribute zaehlen + const char** pTypeList = aImplTypeList; + while ( *pTypeList ) + { + if ( (aNoSymbolName.Search( *pTypeList ) != STRING_NOTFOUND) && + (pData->maMatchName2.Search( *pTypeList ) != STRING_NOTFOUND) ) + nAttrMatch++; + pTypeList++; + } + + // Wenn beide Matches gleich gut sind, + // entscheiden die uebereinstimmenden Attribute + if ( nBestMatch == nTestMatch ) + { + if ( (nAttrMatch > nBestAttrMatch) || + ((nAttrMatch == nBestAttrMatch) && + (pData->maMatchName2.Len() < nBestStrLen)) ) + { + pFoundData = pData; + nBestMatch = nTestMatch; + nBestAttrMatch = nAttrMatch; + nBestStrLen = pData->maMatchName2.Len(); + } + } + else + { + pFoundData = pData; + nBestMatch = nTestMatch; + nBestAttrMatch = nAttrMatch; + nBestStrLen = pData->maMatchName2.Len(); + } + } + } +*/ + + if ( nTestMatch > nBestMatch ) + { + pFoundData = pData; + nBestMatch = nTestMatch; + } + } + + if ( !pFoundData ) + { + pFoundData = pFontList->GetStandardFont( IMPL_STDFONT_ROMAN ); + // Wenn alles nichts hilft, nehmen wir den ersten + if ( !pFoundData ) + pFontList->Get( 0 ); + } +#else + // 1. Token vom Fontnamen nehmen und Sonderzeichen entfernen + XubString aNoSymbolName = aFirstName; + ImplStrEraseAllSymbols( aNoSymbolName ); + + // Suchattribute ermitteln + BOOL bFamily; + BOOL bSymbol; + BOOL bFixed; + FontFamily eSearchFamily = eFamily; + CharSet eSearchCharSet = eCharSet; + FontPitch eSearchPitch = ePitch; + ImplFontAttrFromName( aNoSymbolName, eSearchFamily, eSearchCharSet, eSearchPitch ); + bFamily = eSearchFamily != FAMILY_DONTKNOW; + bSymbol = eSearchCharSet == RTL_TEXTENCODING_SYMBOL; + bFixed = eSearchPitch == PITCH_FIXED; + // Solange in der Namesliste suchen, bis wir auswertbare + // Attribute gefunden haben + xub_StrLen nTempIndex = nFirstNameIndex; + while ( (nTempIndex != STRING_NOTFOUND) && !bFamily && !bFixed && !bSymbol ) + { + aTempName = aLowerFontName.GetToken( 0, ';', nTempIndex ); + ImplCutScriptAndSpaces( aTempName ); + if ( !aTempName.Len() ) + break; + ImplStrEraseAllSymbols( aTempName ); + ImplFontAttrFromName( aTempName, eSearchFamily, eSearchCharSet, eSearchPitch ); + bFamily = eSearchFamily != FAMILY_DONTKNOW; + bSymbol = eSearchCharSet == RTL_TEXTENCODING_SYMBOL; + bFixed = eSearchPitch == PITCH_FIXED; + } + aLowerFontName = aFirstName; + + // wir versuchen zuerst einen Font zu finden, der ueber den Namen + // matched + ULONG i; + xub_StrLen nBestMatch = 5; + xub_StrLen nBestAttrMatch = 0; + xub_StrLen nBestStrLen = 0xFFFF; + for ( i = 0; i < nFontCount; i++ ) + { + ImplDevFontListData* pData = pFontList->Get( i ); + // Beim matchen ignorieren wir alle Sonderzeichen + xub_StrLen nTestMatch = ImplStrMatch( aNoSymbolName, pData->maMatchName2 ); + if ( nTestMatch >= nBestMatch ) + { + // Match nur erlaubt, wenn auch die Attribute uebereinstimmen + BOOL bTestFamily = pData->meMatchFamily != FAMILY_DONTKNOW; + BOOL bTestSymbol = pData->mbSymbol; + BOOL bTestFixed = pData->meMatchPitch == PITCH_FIXED; + if ( (bFixed == bTestFixed) && (bSymbol == bTestSymbol) && + (!bFamily || !bTestFamily || (eSearchFamily == pData->meMatchFamily)) ) + { + xub_StrLen nAttrMatch = 0; + // Die Anzahl der uebereinstimmenden Attribute zaehlen + const char** pTypeList = aImplTypeList; + while ( *pTypeList ) + { + if ( (aNoSymbolName.SearchAscii( *pTypeList ) != STRING_NOTFOUND) && + (pData->maMatchName2.SearchAscii( *pTypeList ) != STRING_NOTFOUND) ) + nAttrMatch++; + pTypeList++; + } + + // Wenn beide Matches gleich gut sind, + // entscheiden die uebereinstimmenden Attribute + if ( nBestMatch == nTestMatch ) + { + if ( (nAttrMatch > nBestAttrMatch) || + ((nAttrMatch == nBestAttrMatch) && + (pData->maMatchName2.Len() < nBestStrLen)) ) + { + pFoundData = pData; + nBestMatch = nTestMatch; + nBestAttrMatch = nAttrMatch; + nBestStrLen = pData->maMatchName2.Len(); + } + } + else + { + pFoundData = pData; + nBestMatch = nTestMatch; + nBestAttrMatch = nAttrMatch; + nBestStrLen = pData->maMatchName2.Len(); + } + } + } + } + + // Wenn wir immer noch keinen passenden Font gefunden haben, versuchen + // wir es ueber die Attribute + if ( !pFoundData ) + { + if ( bFixed ) + { + pFoundData = pFontList->GetStandardFont( IMPL_STDFONT_FIXED ); + if ( !pFoundData ) + { + nBestMatch = 0; + for ( i = 0; i < nFontCount; i++ ) + { + ImplDevFontListData* pData = pFontList->Get( i ); + if ( (pData->meMatchPitch == PITCH_FIXED) && + !pData->mbSymbol && + (pData->meMatchFamily != FAMILY_DECORATIVE) ) + { + if ( pData->mnMatch > nBestMatch ) + { + pFoundData = pData; + nBestMatch = pData->mnMatch; + } + } + } + } + } + + if ( bFamily && !pFoundData ) + { + if ( eSearchFamily == FAMILY_SWISS ) + pFoundData = pFontList->GetStandardFont( IMPL_STDFONT_SWISS ); + else if ( eSearchFamily == FAMILY_ROMAN ) + pFoundData = pFontList->GetStandardFont( IMPL_STDFONT_ROMAN ); + else if ( eSearchFamily == FAMILY_SCRIPT ) + pFoundData = pFontList->GetStandardFont( IMPL_STDFONT_SCRIPT ); + if ( !pFoundData ) + { + nBestMatch = 0; + for ( i = 0; i < nFontCount; i++ ) + { + ImplDevFontListData* pData = pFontList->Get( i ); + if ( (pData->meMatchFamily == eSearchFamily) && + !pData->mbSymbol && + (pData->meMatchPitch != PITCH_FIXED) ) + { + if ( pData->mnMatch > nBestMatch ) + { + pFoundData = pData; + nBestMatch = pData->mnMatch; + } + } + } + } + } + + if ( bSymbol && !pFoundData ) + { + pFoundData = pFontList->GetStandardFont( IMPL_STDFONT_SYMBOL ); + if ( !pFoundData ) + { + nBestMatch = 0; + for ( i = 0; i < nFontCount; i++ ) + { + ImplDevFontListData* pData = pFontList->Get( i ); + if ( pData->mbSymbol ) + { + if ( pData->mnMatch > nBestMatch ) + { + pFoundData = pData; + nBestMatch = pData->mnMatch; + } + } + } + } + } + + if ( !pFoundData ) + { + pFoundData = pFontList->GetStandardFont( IMPL_STDFONT_ROMAN ); + // Wenn alles nichts hilft, nehmen wir den ersten + if ( !pFoundData ) + pFontList->Get( 0 ); + } + } +#endif + } + + // Script evtl. aus CharSet gewinnen, wenn nicht ueber den Fontnamen + // ermittelt werden konnte + if ( eScript == SCRIPT_DONTKNOW ) + eScript = eCharSetScript; + + // Jetzt suchen wir den Font ueber die Attribute + ImplFontData* pFontData = NULL; + if ( pFoundData ) + { + ULONG nBestMatch = 0; // Der groessere Wert ist der bessere + ULONG nBestHeightMatch = 0; // Der kleinere Wert ist der bessere + ULONG nBestWidthMatch = 0; // Der kleinere Wert ist der bessere + ULONG nMatch; + ULONG nHeightMatch; + ULONG nWidthMatch; + ImplFontData* pCurFontData; + +// !!!!! Wegen Office-Fehler !!!! +// XubString aCompareStyleName = rStyleName; +// aCompareStyleName.ToLowerAscii(); + + // Vorallem wegen OS2-System-Standard-Fonts vergleichen wir + // den FontNamen mit FontName + StyleName, damit + // WarpSans Bold auch einen fetten Font ergibt + const xub_Unicode* pCompareStyleName = NULL; + if ( (aLowerFontName.Len() > pFoundData->maMatchName.Len()) && + aLowerFontName.Equals( pFoundData->maMatchName, 0, pFoundData->maMatchName.Len() ) ) + pCompareStyleName = aLowerFontName.GetBuffer()+pFoundData->maMatchName.Len()+1; + + pCurFontData = pFoundData->mpFirst; + while ( pCurFontData ) + { + nMatch = 0; + nHeightMatch = 0; + nWidthMatch = 0; + +// if ( aCompareStyleName.Len() && +// aCompareStyleName.EqualsIgnoreCaseAscii( pCurFontData->maStyleName ) ) +// nMatch += 120000; + if ( pCompareStyleName && + pCurFontData->maStyleName.EqualsIgnoreCaseAscii( pCompareStyleName ) ) + nMatch += 120000; + + if ( eCharSet != RTL_TEXTENCODING_DONTKNOW ) + { + if ( eCharSet == pCurFontData->meCharSet ) + nMatch += 60000; + } + + if ( eScript == pCurFontData->meScript ) + nMatch += 30000; + + if ( (ePitch != PITCH_DONTKNOW) && (ePitch == pCurFontData->mePitch) ) + nMatch += 15000; + + if ( (eFamily != FAMILY_DONTKNOW) && (eFamily == pCurFontData->meFamily) ) + nMatch += 7500; + + // Normale Schriftbreiten bevorzugen, da wir noch keine Daten + // von den Applikationen bekommen + if ( pCurFontData->meWidthType == WIDTH_NORMAL ) + nMatch += 3750; + + if ( eWeight != WEIGHT_DONTKNOW ) + { + USHORT nReqWeight; + USHORT nGivenWeight; + USHORT nWeightDiff; + // schmale Fonts werden bei nicht Bold vor fetten + // Fonts bevorzugt + if ( eWeight > WEIGHT_MEDIUM ) + nReqWeight = ((USHORT)eWeight)+100; + else + nReqWeight = (USHORT)eWeight; + if ( pCurFontData->meWeight > WEIGHT_MEDIUM ) + nGivenWeight = ((USHORT)pCurFontData->meWeight)+100; + else + nGivenWeight = (USHORT)pCurFontData->meWeight; + if ( nReqWeight > nGivenWeight ) + nWeightDiff = nReqWeight-nGivenWeight; + else + nWeightDiff = nGivenWeight-nReqWeight; + + if ( nWeightDiff == 0 ) + nMatch += 1000; + else if ( nWeightDiff == 1 ) + nMatch += 700; + else if ( nWeightDiff < 50 ) + nMatch += 200; + } + if ( eItalic == ITALIC_NONE ) + { + if ( pCurFontData->meItalic == ITALIC_NONE ) + nMatch += 900; + } + else + { + if ( eItalic == pCurFontData->meItalic ) + nMatch += 900; + else if ( pCurFontData->meItalic != ITALIC_NONE ) + nMatch += 600; + } + + if ( pCurFontData->mbDevice ) + nMatch += 40; + if ( pCurFontData->meType == TYPE_SCALABLE ) + { + if ( nOrientation ) + nMatch += 80; + else + { + if ( nWidth ) + nMatch += 25; + else + nMatch += 5; + } + } + else + { + if ( nHeight == pCurFontData->mnHeight ) + { + nMatch += 20; + if ( nWidth == pCurFontData->mnWidth ) + nMatch += 10; + } + else + { + // Dann kommt die Size-Abweichung in die + // Bewertung rein. Hier bevorzugen wir + // nach Moeglichkeit den kleineren Font + if ( nHeight < pCurFontData->mnHeight ) + nHeightMatch += pCurFontData->mnHeight-nHeight; + else + nHeightMatch += (nHeight-pCurFontData->mnHeight-nHeight)+10000; + if ( nWidth && pCurFontData->mnWidth && (nWidth != pCurFontData->mnWidth) ) + { + if ( nWidth < pCurFontData->mnWidth ) + nWidthMatch += pCurFontData->mnWidth-nWidth; + else + nWidthMatch += nWidth-pCurFontData->mnWidth-nWidth; + } + } + } + + if ( nMatch > nBestMatch ) + { + pFontData = pCurFontData; + nBestMatch = nMatch; + nBestHeightMatch = nHeightMatch; + nBestWidthMatch = nWidthMatch; + } + else if ( nMatch == nBestMatch ) + { + // Wenn 2 gleichwertig sind, kommt die Size-Bewertung + // Hier gewinnt der jenige, der die niedrigere Abweichung + // in der Groesse hat (also den kleinsten Match) + if ( nHeightMatch < nBestHeightMatch ) + { + pFontData = pCurFontData; + nBestHeightMatch = nHeightMatch; + nBestWidthMatch = nWidthMatch; + } + else if ( nHeightMatch == nBestHeightMatch ) + { + if ( nWidthMatch < nBestWidthMatch ) + { + pFontData = pCurFontData; + nBestWidthMatch = nWidthMatch; + } + } + } + + pCurFontData = pCurFontData->mpNext; + } + } + + // Daten initialisieren und in die Liste aufnehmen + pEntry = new ImplFontEntry; + pEntry->mbInit = FALSE; + pEntry->mnRefCount = 1; + pEntry->mpNext = mpFirstEntry; + pEntry->mnWidthAryCount = 0; + pEntry->mnWidthArySize = 0; + pEntry->mpWidthAry = NULL; + pEntry->mpKernPairs = NULL; + pEntry->mpKernInfo = NULL; + pEntry->mnOwnOrientation = 0; + pEntry->mnOrientation = 0; + mpFirstEntry = pEntry; + + // Font-Selection-Daten setzen + ImplFontSelectData* pFontSelData = &(pEntry->maFontSelData); + pFontSelData->mpFontData = pFontData; + pFontSelData->mpSysSelData = NULL; + pFontSelData->maName = rName; + pFontSelData->maStyleName = rStyleName; + pFontSelData->mnWidth = nWidth; + pFontSelData->mnHeight = nHeight; + pFontSelData->meFamily = eFamily; + pFontSelData->meCharSet = eCharSet; + pFontSelData->meWidthType = WIDTH_DONTKNOW; + pFontSelData->meWeight = eWeight; + pFontSelData->meItalic = eItalic; + pFontSelData->mePitch = ePitch; + pFontSelData->mnOrientation = nOrientation; + + return pEntry; +} + +// ----------------------------------------------------------------------- + +void ImplFontCache::Release( ImplFontEntry* pEntry ) +{ + pEntry->mnRefCount--; + + if ( !pEntry->mnRefCount ) + { + if ( mnRef0Count >= MAXFONT_CACHE ) + { + // Letzten Entry mit RefCount 0 loeschen + ImplFontEntry* pPrevDelEntry = mpFirstEntry; + ImplFontEntry* pDelEntry = pPrevDelEntry->mpNext; + USHORT nCurRef0Count = !(pPrevDelEntry->mnRefCount); + while ( pDelEntry ) + { + if ( !pDelEntry->mnRefCount ) + nCurRef0Count++; + + if ( nCurRef0Count >= MAXFONT_CACHE ) + { + pPrevDelEntry->mpNext = pDelEntry->mpNext; + delete pDelEntry; + break; + } + + pPrevDelEntry = pDelEntry; + pDelEntry = pDelEntry->mpNext; + } + } + else + mnRef0Count++; + } +} + +// ----------------------------------------------------------------------- + +void ImplFontCache::Clear() +{ + // Alle Eintraege loeschen + ImplFontEntry* pTemp; + ImplFontEntry* pEntry = mpFirstEntry; + while ( pEntry ) + { + DBG_ASSERT( !pEntry->mnRefCount, "ImplFontCache::Clear() - Font in use" ); + pTemp = pEntry->mpNext; + delete pEntry; + pEntry = pTemp; + } + + mpFirstEntry = NULL; + mnRef0Count = 0; +} + +// ======================================================================= + +class ImplTextLineInfo +{ +private: + long mnWidth; + xub_StrLen mnIndex; + xub_StrLen mnLen; + +public: + ImplTextLineInfo( long nWidth, xub_StrLen nIndex, xub_StrLen nLen ) + { + mnWidth = nWidth; + mnIndex = nIndex; + mnLen = nLen; + } + + long GetWidth() const { return mnWidth; } + xub_StrLen GetIndex() const { return mnIndex; } + xub_StrLen GetLen() const { return mnLen; } +}; + +#define MULTITEXTLINEINFO_RESIZE 16 +typedef ImplTextLineInfo* PImplTextLineInfo; + +class ImplMultiTextLineInfo +{ +private: + PImplTextLineInfo* mpLines; + xub_StrLen mnLines; + xub_StrLen mnSize; + +public: + ImplMultiTextLineInfo(); + ~ImplMultiTextLineInfo(); + + void AddLine( ImplTextLineInfo* pLine ); + void Clear(); + + ImplTextLineInfo* GetLine( USHORT nLine ) const + { return mpLines[nLine]; } + xub_StrLen Count() const { return mnLines; } + +private: + ImplMultiTextLineInfo( const ImplMultiTextLineInfo& ); + ImplMultiTextLineInfo& operator=( const ImplMultiTextLineInfo& ); +}; + +ImplMultiTextLineInfo::ImplMultiTextLineInfo() +{ + mpLines = new PImplTextLineInfo[MULTITEXTLINEINFO_RESIZE]; + mnLines = 0; + mnSize = MULTITEXTLINEINFO_RESIZE; +} + +ImplMultiTextLineInfo::~ImplMultiTextLineInfo() +{ + for ( xub_StrLen i = 0; i < mnLines; i++ ) + delete mpLines[i]; + delete mpLines; +} + +void ImplMultiTextLineInfo::AddLine( ImplTextLineInfo* pLine ) +{ + if ( mnSize == mnLines ) + { + mnSize += MULTITEXTLINEINFO_RESIZE; + PImplTextLineInfo* pNewLines = new PImplTextLineInfo[mnSize]; + memcpy( pNewLines, mpLines, mnLines*sizeof(PImplTextLineInfo) ); + mpLines = pNewLines; + } + + mpLines[mnLines] = pLine; + mnLines++; +} + +void ImplMultiTextLineInfo::Clear() +{ + for ( xub_StrLen i = 0; i < mnLines; i++ ) + delete mpLines[i]; + mnLines = 0; +} + +// ======================================================================= + +void OutputDevice::ImplInitFont() +{ + DBG_TESTSOLARMUTEX(); + + if ( mbInitFont ) + { +#ifndef REMOTE_APPSERVER + mpFontEntry->mnSetFontFlags = mpGraphics->SetFont( &(mpFontEntry->maFontSelData) ); + mbInitFont = FALSE; +#else + ImplFontEntry* pFontEntry = mpFontEntry; + RemoteFont aFont; + + if ( pFontEntry->maFontSelData.mpFontData ) + { + aFont.maName = pFontEntry->maFontSelData.mpFontData->maName; + aFont.maStyleName = pFontEntry->maFontSelData.mpFontData->maStyleName; + } + else + { + aFont.maName = pFontEntry->maFontSelData.maName; + aFont.maStyleName = pFontEntry->maFontSelData.maStyleName; + } + aFont.mnWidth = pFontEntry->maFontSelData.mnWidth; + aFont.mnHeight = pFontEntry->maFontSelData.mnHeight; + aFont.meFamily = pFontEntry->maFontSelData.meFamily; + aFont.meCharSet = pFontEntry->maFontSelData.meCharSet; + aFont.meWidthType = pFontEntry->maFontSelData.meWidthType; + aFont.meWeight = pFontEntry->maFontSelData.meWeight; + aFont.meItalic = pFontEntry->maFontSelData.meItalic; + aFont.mePitch = pFontEntry->maFontSelData.mePitch; + aFont.mnOrientation = pFontEntry->maFontSelData.mnOrientation; + mpGraphics->SetFont( aFont ); + pFontEntry->mnSetFontFlags = 0; + mbInitFont = FALSE; +#endif + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplInitTextColor() +{ + DBG_TESTSOLARMUTEX(); + + if ( mbInitTextColor ) + { +#ifndef REMOTE_APPSERVER + mpGraphics->SetTextColor( ImplColorToSal( GetTextColor() ) ); +#else + mpGraphics->SetTextColor( GetTextColor() ); +#endif + mbInitTextColor = FALSE; + } +} + +// ----------------------------------------------------------------------- + +int OutputDevice::ImplNewFont() +{ + DBG_TESTSOLARMUTEX(); + + if ( !mbNewFont ) + return TRUE; + + mbNewFont = FALSE; + +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return FALSE; + } + SalGraphics* pGraphics = mpGraphics; +#else + // Da wegen Clipping hier NULL zurueckkommen kann, koennen wir nicht + // den Rueckgabewert nehmen + ImplGetServerGraphics(); + ImplServerGraphics* pGraphics = mpGraphics; +#endif + + // Groesse umrechnen + Size aSize = ImplLogicToDevicePixel( maFont.GetSize() ); + if ( !aSize.Height() ) + { + // Nur dann Defaultgroesse setzen, wenn Fonthoehe auch in logischen + // Koordinaaten 0 ist + if ( maFont.GetSize().Height() ) + aSize.Height() = 1; + else + aSize.Height() = (12*mnDPIY)/72; + } + + // Neuen Font besorgen + ImplFontEntry* pOldEntry = mpFontEntry; + mpFontEntry = mpFontCache->Get( mpFontList, maFont, aSize ); + ImplFontEntry* pFontEntry = mpFontEntry; + + // Feststellen, ob Font neu selektiert werden muss + if ( pFontEntry != pOldEntry ) + mbInitFont = TRUE; + + // these two may be filled in remote version + ImplKernPairData* pKernPairs = NULL; + long nKernPairs = 0; + // Wenn Font nicht initialisiert ist, dann sofort selektieren + if ( !pFontEntry->mbInit ) + { + ImplInitFont(); + + // und die Font-Daten besorgen + if ( pGraphics ) + { + pFontEntry->mbInit = TRUE; + + pFontEntry->maMetric.mnWidth = pFontEntry->maFontSelData.mnWidth; + pFontEntry->maMetric.meFamily = pFontEntry->maFontSelData.meFamily; + pFontEntry->maMetric.meCharSet = pFontEntry->maFontSelData.meCharSet; + pFontEntry->maMetric.meWeight = pFontEntry->maFontSelData.meWeight; + pFontEntry->maMetric.meItalic = pFontEntry->maFontSelData.meItalic; + pFontEntry->maMetric.mePitch = pFontEntry->maFontSelData.mePitch; + pFontEntry->maMetric.mnOrientation = pFontEntry->maFontSelData.mnOrientation; + if ( pFontEntry->maFontSelData.mpFontData ) + { + pFontEntry->maMetric.meType = pFontEntry->maFontSelData.mpFontData->meType; + pFontEntry->maMetric.maName = pFontEntry->maFontSelData.mpFontData->maName; + pFontEntry->maMetric.maStyleName= pFontEntry->maFontSelData.mpFontData->maStyleName; + pFontEntry->maMetric.mbDevice = pFontEntry->maFontSelData.mpFontData->mbDevice; + } + else + { + pFontEntry->maMetric.meType = TYPE_DONTKNOW; + pFontEntry->maMetric.maName = pFontEntry->maFontSelData.maName.GetToken( 0 ); + pFontEntry->maMetric.maStyleName= pFontEntry->maFontSelData.maStyleName; + pFontEntry->maMetric.mbDevice = FALSE; + } + pFontEntry->maMetric.mnSuperscriptSize = 0; + pFontEntry->maMetric.mnSuperscriptOffset = 0; + pFontEntry->maMetric.mnSubscriptSize = 0; + pFontEntry->maMetric.mnSubscriptOffset = 0; + pFontEntry->maMetric.mnUnderlineSize = 0; + pFontEntry->maMetric.mnUnderlineOffset = 0; + pFontEntry->maMetric.mnBUnderlineSize = 0; + pFontEntry->maMetric.mnBUnderlineOffset = 0; + pFontEntry->maMetric.mnDUnderlineSize = 0; + pFontEntry->maMetric.mnDUnderlineOffset1 = 0; + pFontEntry->maMetric.mnDUnderlineOffset2 = 0; + pFontEntry->maMetric.mnWUnderlineSize = 0; + pFontEntry->maMetric.mnWUnderlineOffset = 0; + pFontEntry->maMetric.mnStrikeoutSize = 0; + pFontEntry->maMetric.mnStrikeoutOffset = 0; + pFontEntry->maMetric.mnBStrikeoutSize = 0; + pFontEntry->maMetric.mnBStrikeoutOffset = 0; + pFontEntry->maMetric.mnDStrikeoutSize = 0; + pFontEntry->maMetric.mnDStrikeoutOffset1 = 0; + pFontEntry->maMetric.mnDStrikeoutOffset2 = 0; +#ifndef REMOTE_APPSERVER + pGraphics->GetFontMetric( &(pFontEntry->maMetric) ); + pFontEntry->mnWidthFactor = pGraphics->GetCharWidth( 0, CHARCACHE_STD-1, pFontEntry->maWidthAry ); +#else + long nFactor = 0; + + pGraphics->GetFontMetric( + pFontEntry->maMetric, + nFactor, 0, CHARCACHE_STD-1, pFontEntry->maWidthAry, + maFont.IsKerning(), &pKernPairs, nKernPairs + ); + pFontEntry->mnWidthFactor = nFactor; +#endif + if ( !pFontEntry->mnWidthFactor ) + { + memset( pFontEntry->maWidthAry, 0, sizeof(long)*(CHARCACHE_STD-1) ); + pFontEntry->mnWidthFactor = 1; + } + + pFontEntry->mbFixedFont = pFontEntry->maMetric.mePitch == PITCH_FIXED; + pFontEntry->mnLineHeight = pFontEntry->maMetric.mnAscent+pFontEntry->maMetric.mnDescent; + pFontEntry->mbInitKernPairs = FALSE; + pFontEntry->mnKernPairs = nKernPairs; + + if ( pFontEntry->maFontSelData.mnOrientation && !pFontEntry->maMetric.mnOrientation && + (meOutDevType != OUTDEV_PRINTER) ) + { + pFontEntry->mnOwnOrientation = pFontEntry->maFontSelData.mnOrientation; + pFontEntry->mnOrientation = pFontEntry->mnOwnOrientation; + } + else + pFontEntry->mnOrientation = pFontEntry->maMetric.mnOrientation; + } + } + + // Wenn Kerning gewuenscht ist, die Kerning-Werte ermitteln + if ( maFont.IsKerning() ) + { + ImplInitKerningPairs( pKernPairs, nKernPairs ); + mbKerning = (pFontEntry->mnKernPairs) != 0; + } + else + mbKerning = FALSE; + + // Je nach TextAlign den TextOffset berechnen + TextAlign eAlign = maFont.GetAlign(); + if ( eAlign == ALIGN_BASELINE ) + { + mnTextOffX = 0; + mnTextOffY = 0; + } + else if ( eAlign == ALIGN_TOP ) + { + long nOrientation = pFontEntry->mnOrientation; + if ( nOrientation ) + { + double nRad = ((double)nOrientation * F_2PI) / 3600.0; + long nOff = pFontEntry->maMetric.mnAscent; + mnTextOffX = (long)(nOff * sin( nRad )); + mnTextOffY = (long)(nOff * cos( nRad )); + } + else + { + mnTextOffX = 0; + mnTextOffY = pFontEntry->maMetric.mnAscent; + } + } + else // eAlign == ALIGN_BOTTOM + { + long nOrientation = pFontEntry->mnOrientation; + if ( nOrientation ) + { + double nRad = ((double)nOrientation * F_2PI) / 3600.0; + long nOff = pFontEntry->maMetric.mnDescent; + mnTextOffX = (long)(nOff - (nOff * sin( nRad ))); + nOff = -nOff; + mnTextOffY = (long)(nOff * cos( nRad )); + } + else + { + mnTextOffX = 0; + mnTextOffY = -pFontEntry->maMetric.mnDescent; + } + } + + mbTextLines = ((maFont.GetUnderline() != UNDERLINE_NONE) && (maFont.GetUnderline() != UNDERLINE_DONTKNOW)) || + ((maFont.GetStrikeout() != STRIKEOUT_NONE) && (maFont.GetStrikeout() != STRIKEOUT_DONTKNOW)); + mbTextSpecial = maFont.IsShadow() || maFont.IsOutline(); + + if ( pOldEntry ) + mpFontCache->Release( pOldEntry ); + + return TRUE; +} + +// ----------------------------------------------------------------------- + +long OutputDevice::ImplGetCharWidth( sal_Unicode c ) const +{ + USHORT nChar = (USHORT)c; + if ( nChar < CHARCACHE_STD ) + return mpFontEntry->maWidthAry[nChar]; + + ImplFontEntry* pFontEntry = mpFontEntry; + ImplWidthInfoData* pInfo; + ImplWidthInfoData* pWidthAry = pFontEntry->mpWidthAry; + USHORT nWidthCount = pFontEntry->mnWidthAryCount; + USHORT nInsIndex; + + if ( nWidthCount ) + { + USHORT nLow; + USHORT nHigh; + USHORT nMid; + USHORT nCompareChar; + + nLow = 0; + nHigh = nWidthCount-1; + do + { + nMid = (nLow+nHigh)/2; + pInfo = pWidthAry+nMid; + nCompareChar = pInfo->mnChar; + if ( nChar < nCompareChar ) + { + if ( !nMid ) + break; + nHigh = nMid-1; + } + else + { + if ( nChar > nCompareChar ) + nLow = nMid+1; + else + return pInfo->mnWidth; + } + } + while ( nLow <= nHigh ); + + if ( nChar > nCompareChar ) + nInsIndex = nMid+1; + else + nInsIndex = nMid; + } + else + { + pFontEntry->mnWidthArySize = WIDTHARY_INIT; + pFontEntry->mpWidthAry = new ImplWidthInfoData[pFontEntry->mnWidthArySize]; + pWidthAry = pFontEntry->mpWidthAry; + nInsIndex = 0; + } + + if ( nWidthCount == pFontEntry->mnWidthArySize ) + { + USHORT nOldSize = pFontEntry->mnWidthArySize; + pFontEntry->mnWidthArySize += WIDTHARY_RESIZE; + pFontEntry->mpWidthAry = new ImplWidthInfoData[pFontEntry->mnWidthArySize]; + memcpy( pFontEntry->mpWidthAry, pWidthAry, nOldSize*sizeof(ImplWidthInfoData) ); + delete pWidthAry; + pWidthAry = pFontEntry->mpWidthAry; + } + + // Um die Zeichenbreite zu ermitteln, brauchen wir einen Graphics und der + // Font muss natuerlich auch selektiert sein +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !((OutputDevice*)this)->ImplGetGraphics() ) + return 0; + } +#else + // Da wegen Clipping hier NULL zurueckkommen kann, koennen wir nicht + // den Rueckgabewert nehmen + ((OutputDevice*)this)->ImplGetServerGraphics(); +#endif + + if ( mbNewFont ) + ((OutputDevice*)this)->ImplNewFont(); + if ( mbInitFont ) + ((OutputDevice*)this)->ImplInitFont(); + + long nWidth; +#ifndef REMOTE_APPSERVER + long nWidthFactor = mpGraphics->GetCharWidth( nChar, nChar, &nWidth ); +#else + long nWidthFactor = pFontEntry->mnWidthFactor; + mpGraphics->GetCharWidth( nChar, nChar, &nWidth ); +#endif + if ( !nWidthFactor ) + return 0; + + DBG_ASSERT( (nWidthFactor == pFontEntry->mnWidthFactor), + "OutputDevice::ImplGetCharWidth() - other WidthFactor" ); + + // Breite in Liste einfuegen und zurueckgeben + pInfo = pWidthAry+nInsIndex; + memmove( pInfo+1, pInfo, (nWidthCount-nInsIndex)*sizeof(ImplWidthInfoData) ); + pFontEntry->mnWidthAryCount++; + pInfo->mnChar = nChar; + pInfo->mnWidth = nWidth; + return nWidth; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplInitKerningPairs( ImplKernPairData* pKernPairs, long nKernPairs ) +{ + if ( mbNewFont ) + { + if ( !ImplNewFont() ) + return; + } + + ImplFontEntry* pFontEntry = mpFontEntry; + if ( !pFontEntry->mbInitKernPairs ) + { + if ( mbInitFont ) + ImplInitFont(); + pFontEntry->mbInitKernPairs = TRUE; +#ifndef REMOTE_APPSERVER + pFontEntry->mnKernPairs = mpGraphics->GetKernPairs( 0, NULL ); + if ( pFontEntry->mnKernPairs ) + { + ImplKernInfoData* pKernInfo = new ImplKernInfoData; + pKernPairs = new ImplKernPairData[pFontEntry->mnKernPairs]; + memset( pKernPairs, 0, sizeof(ImplKernPairData)*pFontEntry->mnKernPairs ); + pFontEntry->mnKernPairs = mpGraphics->GetKernPairs( pFontEntry->mnKernPairs, pKernPairs ); + pFontEntry->mpKernInfo = pKernInfo; + pFontEntry->mpKernPairs = pKernPairs; + + // Wir akzeptieren erstmal nur max. 65535-Paare + USHORT nMaxKernPairs; + if ( pFontEntry->mnKernPairs > 0xFFFF ) + nMaxKernPairs = 0xFFFF; + else + nMaxKernPairs = (USHORT)pFontEntry->mnKernPairs; + memset( pKernInfo->maFirstAry, 0xFF, sizeof( pKernInfo->maFirstAry ) ); + memset( pKernInfo->maLastAry, 0, sizeof( pKernInfo->maLastAry ) ); + for ( USHORT i = 0; i < nMaxKernPairs; i++ ) + { + USHORT nFirst = pKernPairs[i].mnChar1; + if ( nFirst < 0xFF ) + { + if ( i < pKernInfo->maFirstAry[nFirst] ) + pKernInfo->maFirstAry[nFirst] = i; + pKernInfo->maLastAry[nFirst] = i; + } + } + } +#else + // Wir arbeiten erstmal nur mit USHORT + if( ! pKernPairs ) + nKernPairs = mpGraphics->GetKernPairs( &pKernPairs ); + if ( nKernPairs ) + { + ImplKernInfoData* pKernInfo = new ImplKernInfoData; + pFontEntry->mpKernInfo = pKernInfo; + pFontEntry->mpKernPairs = pKernPairs; + + // Wir akzeptieren erstmal nur max. 65535-Paare + USHORT nMaxKernPairs; + if( ! pFontEntry->mnKernPairs ) + pFontEntry->mnKernPairs = nKernPairs; + if ( pFontEntry->mnKernPairs > 0xFFFF ) + nMaxKernPairs = 0xFFFF; + else + nMaxKernPairs = (USHORT)pFontEntry->mnKernPairs; + memset( pKernInfo->maFirstAry, 0xFF, sizeof( pKernInfo->maFirstAry ) ); + memset( pKernInfo->maLastAry, 0, sizeof( pKernInfo->maLastAry ) ); + for ( USHORT i = 0; i < nMaxKernPairs; i++ ) + { + USHORT nFirst = pKernPairs[i].mnChar1; + if ( nFirst < 0xFF ) + { + if ( i < pKernInfo->maFirstAry[nFirst] ) + pKernInfo->maFirstAry[nFirst] = i; + pKernInfo->maLastAry[nFirst] = i; + } + } + } +#endif + } +} + +// ----------------------------------------------------------------------- + +long OutputDevice::ImplCalcKerning( const sal_Unicode* pStr, xub_StrLen nLen, + long* pDXAry, xub_StrLen nAryLen ) const +{ + if ( !nLen ) + return 0; + + ImplFontEntry* pEntry = mpFontEntry; + ImplKernPairData* pKernPairs = pEntry->mpKernPairs; + ImplKernInfoData* pKernInfo = pEntry->mpKernInfo; + long nWidth = 0; + +#ifdef DBG_UTIL + { + ImplKernPairData aTestPair; +#ifdef __LITTLEENDIAN + ULONG nTestComp = ((ULONG)((USHORT)0xAABB) << 16) | (USHORT)0xCCDD; +#else + ULONG nTestComp = ((ULONG)((USHORT)0xCCDD) << 16) | (USHORT)0xAABB; +#endif + aTestPair.mnChar1 = 0xCCDD; + aTestPair.mnChar2 = 0xAABB; + DBG_ASSERT( nTestComp == *((ULONG*)&aTestPair), "Code doesn't work in this Version" ); + } +#endif + + for ( USHORT i = 0; i < nLen-1; i++ ) + { + USHORT nIndex = (USHORT)(unsigned char)pStr[i]; + USHORT nFirst = pKernInfo->maFirstAry[nIndex]; + USHORT nLast = pKernInfo->maLastAry[nIndex]; +#ifdef __LITTLEENDIAN + ULONG nComp = ((ULONG)((USHORT)(unsigned char)pStr[i+1]) << 16) | nIndex; +#else + ULONG nComp = ((ULONG)nIndex << 16) | ((USHORT)(unsigned char)pStr[i+1]); +#endif + for ( USHORT j = nFirst; j <= nLast; j++ ) + { + if ( nComp == *((ULONG*)&(pKernPairs[j])) ) + { + long nAmount = pKernPairs[j].mnKern; + nWidth += nAmount; + if ( pDXAry ) + { + for ( USHORT n = i; n < nAryLen; n++ ) + pDXAry[n] += nAmount; + } + } + } + } + + return nWidth; +} + +// ----------------------------------------------------------------------- + +long OutputDevice::ImplGetTextWidth( const xub_Unicode* pStr, xub_StrLen nLen, + const long* pDX ) +{ + ImplFontEntry* pFontEntry = mpFontEntry; + long nFactor = pFontEntry->mnWidthFactor; + long nWidth = 0; + + if ( nLen ) + { + if ( pDX ) + { + if ( nLen > 1 ) + nWidth += pDX[nLen-2]; + nWidth += ImplGetCharWidth( pStr[nLen-1] ) / nFactor; + } + else + { + // Bei Fixed-Fonts reicht eine Multiplikation + if ( pFontEntry->mbFixedFont ) + nWidth = ImplGetCharWidth( 'A' ) * nLen; + else + { + const sal_Unicode* pTempStr = pStr; + xub_StrLen nTempLen = nLen; + while ( nTempLen ) + { + nWidth += ImplGetCharWidth( *pTempStr ); + nTempLen--; + pTempStr++; + } + } + nWidth /= nFactor; + + // Kerning beruecksichtigen + if ( mbKerning ) + nWidth += ImplCalcKerning( pStr, nLen, NULL, 0 ); + } + } + + return nWidth; +} + +// ----------------------------------------------------------------------- + +static void ImplRotatePos( long nOriginX, long nOriginY, long& rX, long& rY, + short nOrientation ) +{ + double nRealOrientation = nOrientation*F_PI1800; + double nCos = cos( nRealOrientation ); + double nSin = sin( nRealOrientation ); + + // Translation... + long nX = rX-nOriginX; + long nY = rY-nOriginY; + + // Rotation... + rX = ((long) ( nCos*nX + nSin*nY )) + nOriginX; + rY = ((long) - ( nSin*nX - nCos*nY )) + nOriginY; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplDrawTextRect( long nBaseX, long nBaseY, + long nX, long nY, long nWidth, long nHeight ) +{ + if ( mpFontEntry->mnOrientation ) + { + if ( !(mpFontEntry->mnOrientation % 900) ) + { + long nX2 = nX+nWidth; + long nY2 = nY+nHeight; + ImplRotatePos( nBaseX, nBaseY, nX, nY, mpFontEntry->mnOrientation ); + ImplRotatePos( nBaseX, nBaseY, nX2, nY2, mpFontEntry->mnOrientation ); + nWidth = nX2-nX; + nHeight = nY2-nY; + } + else + { + // Da Polygone kleiner gezeichnet werden + nHeight++; + nWidth++; + Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) ); + Polygon aPoly( aRect ); + aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation ); +#ifndef REMOTE_APPSERVER + ImplDrawPolygon( aPoly ); +#else + mpGraphics->DrawPolygon( aPoly ); +#endif + return; + } + } + +#ifndef REMOTE_APPSERVER + mpGraphics->DrawRect( nX, nY, nWidth, nHeight ); +#else + Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) ); + mpGraphics->DrawRect( aRect ); +#endif +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplDrawTextBackground( long nX, long nY, + const xub_Unicode* pStr, xub_StrLen nLen, + const long* pDXAry ) +{ +#ifndef REMOTE_APPSERVER + if ( mbLineColor || mbInitLineColor ) + { + mpGraphics->SetLineColor(); + mbInitLineColor = TRUE; + } + mpGraphics->SetFillColor( ImplColorToSal( GetTextFillColor() ) ); + mbInitFillColor = TRUE; + + ImplDrawTextRect( nX, nY, nX, nY-mpFontEntry->maMetric.mnAscent, + ImplGetTextWidth( pStr, nLen, pDXAry ), + mpFontEntry->mnLineHeight ); +#else + Color aOldLineColor = GetLineColor(); + Color aOldFillColor = GetFillColor(); + SetLineColor(); + SetFillColor( GetTextFillColor() ); + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); + ImplDrawTextRect( nX, nY, nX, nY-mpFontEntry->maMetric.mnAscent, + ImplGetTextWidth( pStr, nLen, pDXAry ), + mpFontEntry->mnLineHeight ); + SetLineColor( aOldLineColor ); + SetFillColor( aOldFillColor ); +#endif +} + +// ----------------------------------------------------------------------- + +Rectangle OutputDevice::ImplGetTextBoundRect( long nX, long nY, + const xub_Unicode* pStr, xub_StrLen nLen, + const long* pDXAry ) +{ + if( !nLen ) + return Rectangle(); + + if ( mbNewFont ) + ImplNewFont(); + + if ( mbInitFont ) + ImplInitFont(); + + long nBaseX = nX, nBaseY = nY; + long nWidth = ImplGetTextWidth( pStr, nLen, pDXAry ), nHeight = mpFontEntry->mnLineHeight; + + nY -= mpFontEntry->maMetric.mnAscent; + + if ( mpFontEntry->mnOrientation ) + { + if ( !(mpFontEntry->mnOrientation % 900) ) + { + long nX2 = nX+nWidth; + long nY2 = nY+nHeight; + ImplRotatePos( nBaseX, nBaseY, nX, nY, mpFontEntry->mnOrientation ); + ImplRotatePos( nBaseX, nBaseY, nX2, nY2, mpFontEntry->mnOrientation ); + nWidth = nX2-nX; + nHeight = nY2-nY; + } + else + { + // Da Polygone kleiner gezeichnet werden + nHeight++; + nWidth++; + Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) ); + Polygon aPoly( aRect ); + aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation ); + return aPoly.GetBoundRect(); + } + } + + return Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ); +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplInitTextLineSize() +{ + ImplFontEntry* pFontEntry = mpFontEntry; + long nLineHeight; + long nLineHeight2; + long nBLineHeight; + long nBLineHeight2; + long n2LineHeight; + long n2LineDY; + long n2LineDY2; + long nUnderlineOffset; + long nStrikeoutOffset; + + nLineHeight = ((mpFontEntry->maMetric.mnDescent*25)+50) / 100; + if ( !nLineHeight ) + nLineHeight = 1; + nLineHeight2 = nLineHeight / 2; + if ( !nLineHeight2 ) + nLineHeight2 = 1; + + nBLineHeight = ((mpFontEntry->maMetric.mnDescent*50)+50) / 100; + if ( nBLineHeight == nLineHeight ) + nBLineHeight++; + nBLineHeight2 = nBLineHeight/2; + if ( !nBLineHeight2 ) + nBLineHeight2 = 1; + + n2LineHeight = ((mpFontEntry->maMetric.mnDescent*16)+50) / 100; + if ( !n2LineHeight ) + n2LineHeight = 1; + n2LineDY = n2LineHeight; + if ( n2LineDY <= 0 ) + n2LineDY = 1; + n2LineDY2 = n2LineDY/2; + if ( !n2LineDY2 ) + n2LineDY2 = 1; + + nUnderlineOffset = mpFontEntry->maMetric.mnDescent/2 + 1; + nStrikeoutOffset = -((mpFontEntry->maMetric.mnAscent-mpFontEntry->maMetric.mnLeading)/3); + + if ( !pFontEntry->maMetric.mnUnderlineSize ) + { + pFontEntry->maMetric.mnUnderlineSize = nLineHeight; + pFontEntry->maMetric.mnUnderlineOffset = nUnderlineOffset - nLineHeight2; + } + if ( !pFontEntry->maMetric.mnBUnderlineSize ) + { + pFontEntry->maMetric.mnBUnderlineSize = nBLineHeight; + pFontEntry->maMetric.mnBUnderlineOffset = nUnderlineOffset - nBLineHeight2; + } + if ( !pFontEntry->maMetric.mnDUnderlineSize ) + { + pFontEntry->maMetric.mnDUnderlineSize = n2LineHeight; + pFontEntry->maMetric.mnDUnderlineOffset1 = nUnderlineOffset - n2LineDY2 - n2LineHeight; + pFontEntry->maMetric.mnDUnderlineOffset2 = pFontEntry->maMetric.mnDUnderlineOffset1 + n2LineDY + n2LineHeight; + } + if ( !pFontEntry->maMetric.mnWUnderlineSize ) + { + if ( mpFontEntry->maMetric.mnDescent < 6 ) + { + if ( (mpFontEntry->maMetric.mnDescent == 1) || + (mpFontEntry->maMetric.mnDescent == 2) ) + pFontEntry->maMetric.mnWUnderlineSize = mpFontEntry->maMetric.mnDescent; + else + pFontEntry->maMetric.mnWUnderlineSize = 3; + } + else + pFontEntry->maMetric.mnWUnderlineSize = ((mpFontEntry->maMetric.mnDescent*50)+50) / 100; + pFontEntry->maMetric.mnWUnderlineOffset = nUnderlineOffset; + } + if ( !pFontEntry->maMetric.mnStrikeoutSize ) + { + pFontEntry->maMetric.mnStrikeoutSize = nLineHeight; + pFontEntry->maMetric.mnStrikeoutOffset = nStrikeoutOffset - nLineHeight2; + } + if ( !pFontEntry->maMetric.mnBStrikeoutSize ) + { + pFontEntry->maMetric.mnBStrikeoutSize = nBLineHeight; + pFontEntry->maMetric.mnBStrikeoutOffset = nStrikeoutOffset - nBLineHeight2; + } + if ( !pFontEntry->maMetric.mnDStrikeoutSize ) + { + pFontEntry->maMetric.mnDStrikeoutSize = n2LineHeight; + pFontEntry->maMetric.mnDStrikeoutOffset1 = nStrikeoutOffset - n2LineDY2 - n2LineHeight; + pFontEntry->maMetric.mnDStrikeoutOffset2 = pFontEntry->maMetric.mnDStrikeoutOffset1 + n2LineDY + n2LineHeight; + } +} + +// ----------------------------------------------------------------------- + +static void ImplDrawWavePixel( long nOriginX, long nOriginY, + long nCurX, long nCurY, + short nOrientation, +#ifndef REMOTE_APPSERVER + SalGraphics* pGraphics, +#else + ImplServerGraphics* pGraphics, +#endif + BOOL bDrawPixAsRect, + long nPixWidth, long nPixHeight ) +{ + if ( nOrientation ) + ImplRotatePos( nOriginX, nOriginY, nCurX, nCurY, nOrientation ); + + if ( bDrawPixAsRect ) + { +#ifndef REMOTE_APPSERVER + pGraphics->DrawRect( nCurX, nCurY, nPixWidth, nPixHeight ); +#else + Point aPos( nCurX, nCurY ); + Size aSize( nPixWidth, nPixHeight ); + Rectangle aRect( aPos, aSize ); + pGraphics->DrawRect( aRect ); +#endif + } + else + { +#ifndef REMOTE_APPSERVER + pGraphics->DrawPixel( nCurX, nCurY ); +#else + Point aPos( nCurX, nCurY ); + pGraphics->DrawPixel( aPos ); +#endif + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplDrawWaveLine( long nBaseX, long nBaseY, + long nStartX, long nStartY, + long nWidth, long nHeight, + long nLineWidth, short nOrientation, + const Color& rColor ) +{ + if ( !nHeight ) + return; + + // Bei Hoehe von 1 Pixel reicht es, eine Linie auszugeben + if ( (nLineWidth == 1) && (nHeight == 1) ) + { +#ifndef REMOTE_APPSERVER + mpGraphics->SetLineColor( ImplColorToSal( rColor ) ); + mbInitLineColor = TRUE; +#else + Color aOldLineColor = GetLineColor(); + SetLineColor( rColor ); + if ( mbInitLineColor ) + ImplInitLineColor(); +#endif + + long nEndX = nStartX+nWidth; + long nEndY = nStartY; + if ( nOrientation ) + { + ImplRotatePos( nBaseX, nBaseY, nStartX, nStartY, nOrientation ); + ImplRotatePos( nBaseX, nBaseY, nEndX, nEndY, nOrientation ); + } +#ifndef REMOTE_APPSERVER + mpGraphics->DrawLine( nStartX, nStartY, nEndX, nEndY ); +#else + mpGraphics->DrawLine( Point( nStartX, nStartY ), Point( nEndX, nEndY ) ); +#endif + +#ifdef REMOTE_APPSERVER + SetLineColor( aOldLineColor ); +#endif + } + else + { + long nCurX = nStartX; + long nCurY = nStartY; + long nDiffX = 2; + long nDiffY = nHeight-1; + long nCount = nWidth; + long nOffY = -1; + long nFreq; + long i; + long nPixWidth; + long nPixHeight; + BOOL bDrawPixAsRect; +#ifdef REMOTE_APPSERVER + Color aOldLineColor = GetLineColor(); + Color aOldFillColor = GetFillColor(); +#endif + // Auf Druckern die Pixel per DrawRect() ausgeben + if ( (GetOutDevType() == OUTDEV_PRINTER) || (nLineWidth > 1) ) + { +#ifndef REMOTE_APPSERVER + if ( mbLineColor || mbInitLineColor ) + { + mpGraphics->SetLineColor(); + mbInitLineColor = TRUE; + } + mpGraphics->SetFillColor( ImplColorToSal( rColor ) ); + mbInitFillColor = TRUE; +#else + SetLineColor(); + SetFillColor( rColor ); + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); +#endif + bDrawPixAsRect = TRUE; + nPixWidth = nLineWidth; + nPixHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY; + } + else + { +#ifndef REMOTE_APPSERVER + mpGraphics->SetLineColor( ImplColorToSal( rColor ) ); + mbInitLineColor = TRUE; +#else + Color aOldLineColor = GetLineColor(); + SetLineColor( rColor ); + if ( mbInitLineColor ) + ImplInitLineColor(); +#endif + nPixWidth = 1; + nPixHeight = 1; + bDrawPixAsRect = FALSE; + } + + if ( !nDiffY ) + { + while ( nWidth ) + { + ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation, + mpGraphics, + bDrawPixAsRect, nPixWidth, nPixHeight ); + nCurX++; + nWidth--; + } + } + else + { + nCurY += nDiffY; + nFreq = nCount / (nDiffX+nDiffY); + while ( nFreq-- ) + { + for( i = nDiffY; i; --i ) + { + ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation, + mpGraphics, + bDrawPixAsRect, nPixWidth, nPixHeight ); + nCurX++; + nCurY += nOffY; + } + for( i = nDiffX; i; --i ) + { + ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation, + mpGraphics, + bDrawPixAsRect, nPixWidth, nPixHeight ); + nCurX++; + } + nOffY = -nOffY; + } + nFreq = nCount % (nDiffX+nDiffY); + if ( nFreq ) + { + for( i = nDiffY; i && nFreq; --i, --nFreq ) + { + ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation, + mpGraphics, + bDrawPixAsRect, nPixWidth, nPixHeight ); + nCurX++; + nCurY += nOffY; + } + for( i = nDiffX; i && nFreq; --i, --nFreq ) + { + ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation, + mpGraphics, + bDrawPixAsRect, nPixWidth, nPixHeight ); + nCurX++; + } + } + } + +#ifdef REMOTE_APPSERVER + SetLineColor( aOldLineColor ); + SetFillColor( aOldFillColor ); +#endif + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplDrawTextLine( long nBaseX, + long nX, long nY, long nWidth, + FontStrikeout eStrikeout, + FontUnderline eUnderline ) +{ + ImplFontEntry* pFontEntry = mpFontEntry; + Color aTextLineColor = GetTextLineColor(); + long nBaseY = nY; + long nLineHeight; + long nLinePos; + long nLinePos2; + long nLeft; + BOOL bNormalLines = TRUE; + + if ( !IsTextLineColor() ) + aTextLineColor = GetTextColor(); + + if ( (eUnderline == UNDERLINE_SMALLWAVE) || + (eUnderline == UNDERLINE_WAVE) || + (eUnderline == UNDERLINE_DOUBLEWAVE) || + (eUnderline == UNDERLINE_BOLDWAVE) ) + { + if ( !pFontEntry->maMetric.mnWUnderlineSize ) + ImplInitTextLineSize(); + nLineHeight = pFontEntry->maMetric.mnWUnderlineSize; + if ( (eUnderline == UNDERLINE_SMALLWAVE) && + (nLineHeight > 3) ) + nLineHeight = 3; + long nLineWidth = (mnDPIX/300); + if ( !nLineWidth ) + nLineWidth = 1; + if ( eUnderline == UNDERLINE_BOLDWAVE ) + nLineWidth *= 2; + nLinePos = nY + pFontEntry->maMetric.mnWUnderlineOffset - (nLineHeight / 2); + long nLineWidthHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY; + if ( eUnderline == UNDERLINE_DOUBLEWAVE ) + { + long nOrgLineHeight = nLineHeight; + nLineHeight /= 3; + if ( nLineHeight < 2 ) + { + if ( nOrgLineHeight > 1 ) + nLineHeight = 2; + else + nLineHeight = 1; + } + long nLineDY = nOrgLineHeight-(nLineHeight*2); + if ( nLineDY < nLineWidthHeight ) + nLineDY = nLineWidthHeight; + long nLineDY2 = nLineDY/2; + if ( !nLineDY2 ) + nLineDY2 = 1; + nLinePos -= nLineWidthHeight-nLineDY2; + ImplDrawWaveLine( nBaseX, nBaseY, nX, nLinePos, nWidth, nLineHeight, + nLineWidth, mpFontEntry->mnOrientation, aTextLineColor ); + nLinePos += nLineWidthHeight+nLineDY; + ImplDrawWaveLine( nBaseX, nBaseY, nX, nLinePos, nWidth, nLineHeight, + nLineWidth, mpFontEntry->mnOrientation, aTextLineColor ); + } + else + { + nLinePos -= nLineWidthHeight/2; + ImplDrawWaveLine( nBaseX, nBaseY, nX, nLinePos, nWidth, nLineHeight, + nLineWidth, mpFontEntry->mnOrientation, aTextLineColor ); + } + + if ( (eStrikeout == STRIKEOUT_NONE) || + (eStrikeout == STRIKEOUT_DONTKNOW) ) + bNormalLines = FALSE; + } + + if ( bNormalLines && + ((eStrikeout == STRIKEOUT_SLASH) || (eStrikeout == STRIKEOUT_X)) ) + { + BOOL bOldMap = IsMapModeEnabled(); + EnableMapMode( FALSE ); + Color aOldColor = GetTextColor(); + SetTextColor( aTextLineColor ); + ImplInitTextColor(); + xub_Unicode c; + if ( eStrikeout == STRIKEOUT_SLASH ) + c = '/'; + else /* ( eStrikeout == STRIKEOUT_X ) */ + c = 'X'; + // Strikeout-String zusammenbauen + XubString aStrikeoutText( c ); + aStrikeoutText += aStrikeoutText.GetChar( 0 ); + long nStrikeoutWidth = GetTextWidth( aStrikeoutText ); + long nChars = nWidth/(nStrikeoutWidth/2); + aStrikeoutText.Fill( (USHORT)(nChars+1), c ); + // String solange kuerzen, bis er nicht allzuweit uebersteht + long nMaxWidth = nStrikeoutWidth/4; + if ( nMaxWidth < 2 ) + nMaxWidth = 2; + nMaxWidth += nWidth; + long nFullStrikeoutWidth = GetTextWidth( aStrikeoutText ); + while ( (nFullStrikeoutWidth > nMaxWidth) && aStrikeoutText.Len() ) + { + aStrikeoutText.Erase( aStrikeoutText.Len()-1 ); + nFullStrikeoutWidth = GetTextWidth( aStrikeoutText ); + } + if ( mpFontEntry->mnOrientation ) + ImplRotatePos( nBaseX, nBaseY, nX, nY, mpFontEntry->mnOrientation ); + ImplDrawTextDirect( nX, nY, + aStrikeoutText.GetBuffer(), aStrikeoutText.Len(), + NULL, FALSE ); + SetTextColor( aOldColor ); + ImplInitTextColor(); + EnableMapMode( bOldMap ); + + if ( (eUnderline == UNDERLINE_NONE) || + (eUnderline == UNDERLINE_DONTKNOW) || + (eUnderline == UNDERLINE_SMALLWAVE) || + (eUnderline == UNDERLINE_WAVE) || + (eUnderline == UNDERLINE_DOUBLEWAVE) || + (eUnderline == UNDERLINE_BOLDWAVE) ) + bNormalLines = FALSE; + } + + if ( bNormalLines ) + { +#ifndef REMOTE_APPSERVER + if ( mbLineColor || mbInitLineColor ) + { + mpGraphics->SetLineColor(); + mbInitLineColor = TRUE; + } + mpGraphics->SetFillColor( ImplColorToSal( aTextLineColor ) ); + mbInitFillColor = TRUE; +#else + Color aOldLineColor = GetLineColor(); + Color aOldFillColor = GetFillColor(); + SetLineColor(); + SetFillColor( aTextLineColor ); + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); +#endif + + if ( eUnderline > UNDERLINE_LAST ) + eUnderline = UNDERLINE_SINGLE; + + if ( (eUnderline == UNDERLINE_SINGLE) || + (eUnderline == UNDERLINE_DOTTED) || + (eUnderline == UNDERLINE_DASH) || + (eUnderline == UNDERLINE_LONGDASH) || + (eUnderline == UNDERLINE_DASHDOT) || + (eUnderline == UNDERLINE_DASHDOTDOT) ) + { + if ( !pFontEntry->maMetric.mnUnderlineSize ) + ImplInitTextLineSize(); + nLineHeight = pFontEntry->maMetric.mnUnderlineSize; + nLinePos = nY + pFontEntry->maMetric.mnUnderlineOffset; + } + else if ( (eUnderline == UNDERLINE_BOLD) || + (eUnderline == UNDERLINE_BOLDDOTTED) || + (eUnderline == UNDERLINE_BOLDDASH) || + (eUnderline == UNDERLINE_BOLDLONGDASH) || + (eUnderline == UNDERLINE_BOLDDASHDOT) || + (eUnderline == UNDERLINE_BOLDDASHDOTDOT) ) + { + if ( !pFontEntry->maMetric.mnBUnderlineSize ) + ImplInitTextLineSize(); + nLineHeight = pFontEntry->maMetric.mnBUnderlineSize; + nLinePos = nY + pFontEntry->maMetric.mnBUnderlineOffset; + } + else if ( eUnderline == UNDERLINE_DOUBLE ) + { + if ( !pFontEntry->maMetric.mnDUnderlineSize ) + ImplInitTextLineSize(); + nLineHeight = pFontEntry->maMetric.mnDUnderlineSize; + nLinePos = nY + pFontEntry->maMetric.mnDUnderlineOffset1; + nLinePos2 = nY + pFontEntry->maMetric.mnDUnderlineOffset2; + } + else + nLineHeight = 0; + + if ( nLineHeight ) + { + nLeft = nX; + + if ( (eUnderline == UNDERLINE_SINGLE) || + (eUnderline == UNDERLINE_BOLD) ) + ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight ); + else if ( eUnderline == UNDERLINE_DOUBLE ) + { + ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight ); + ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight ); + } + else if ( (eUnderline == UNDERLINE_DOTTED) || + (eUnderline == UNDERLINE_BOLDDOTTED) ) + { + long nDotWidth = nLineHeight*mnDPIY; + nDotWidth += mnDPIY/2; + nDotWidth /= mnDPIY; + long nTempWidth = nDotWidth; + long nEnd = nLeft+nWidth; + while ( nLeft < nEnd ) + { + if ( nLeft+nTempWidth > nEnd ) + nTempWidth = nEnd-nLeft; + ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight ); + nLeft += nDotWidth*2; + } + } + else if ( (eUnderline == UNDERLINE_DASH) || + (eUnderline == UNDERLINE_LONGDASH) || + (eUnderline == UNDERLINE_BOLDDASH) || + (eUnderline == UNDERLINE_BOLDLONGDASH) ) + { + long nDotWidth = nLineHeight*mnDPIY; + nDotWidth += mnDPIY/2; + nDotWidth /= mnDPIY; + long nMinDashWidth; + long nMinSpaceWidth; + long nSpaceWidth; + long nDashWidth; + if ( (eUnderline == UNDERLINE_LONGDASH) || + (eUnderline == UNDERLINE_BOLDLONGDASH) ) + { + nMinDashWidth = nDotWidth*6; + nMinSpaceWidth = nDotWidth*2; + nDashWidth = 200; + nSpaceWidth = 100; + } + else + { + nMinDashWidth = nDotWidth*4; + nMinSpaceWidth = (nDotWidth*150)/100; + nDashWidth = 100; + nSpaceWidth = 50; + } + nDashWidth = ((nDashWidth*mnDPIX)+1270)/2540; + nSpaceWidth = ((nSpaceWidth*mnDPIX)+1270)/2540; + // DashWidth wird gegebenenfalls verbreitert, wenn + // die dicke der Linie im Verhaeltnis zur Laenge + // zu dick wird + if ( nDashWidth < nMinDashWidth ) + nDashWidth = nMinDashWidth; + if ( nSpaceWidth < nMinSpaceWidth ) + nSpaceWidth = nMinSpaceWidth; + long nTempWidth = nDashWidth; + long nEnd = nLeft+nWidth; + while ( nLeft < nEnd ) + { + if ( nLeft+nTempWidth > nEnd ) + nTempWidth = nEnd-nLeft; + ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight ); + nLeft += nDashWidth+nSpaceWidth; + } + } + else if ( (eUnderline == UNDERLINE_DASHDOT) || + (eUnderline == UNDERLINE_BOLDDASHDOT) ) + { + long nDotWidth = nLineHeight*mnDPIY; + nDotWidth += mnDPIY/2; + nDotWidth /= mnDPIY; + long nDashWidth = ((100*mnDPIX)+1270)/2540; + long nMinDashWidth = nDotWidth*4; + // DashWidth wird gegebenenfalls verbreitert, wenn + // die dicke der Linie im Verhaeltnis zur Laenge + // zu dick wird + if ( nDashWidth < nMinDashWidth ) + nDashWidth = nMinDashWidth; + long nTempDotWidth = nDotWidth; + long nTempDashWidth = nDashWidth; + long nEnd = nLeft+nWidth; + while ( nLeft < nEnd ) + { + if ( nLeft+nTempDotWidth > nEnd ) + nTempDotWidth = nEnd-nLeft; + ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight ); + nLeft += nDotWidth*2; + if ( nLeft > nEnd ) + break; + if ( nLeft+nTempDashWidth > nEnd ) + nTempDashWidth = nEnd-nLeft; + ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight ); + nLeft += nDashWidth+nDotWidth; + } + } + else if ( (eUnderline == UNDERLINE_DASHDOTDOT) || + (eUnderline == UNDERLINE_BOLDDASHDOTDOT) ) + { + long nDotWidth = nLineHeight*mnDPIY; + nDotWidth += mnDPIY/2; + nDotWidth /= mnDPIY; + long nDashWidth = ((100*mnDPIX)+1270)/2540; + long nMinDashWidth = nDotWidth*4; + // DashWidth wird gegebenenfalls verbreitert, wenn + // die dicke der Linie im Verhaeltnis zur Laenge + // zu dick wird + if ( nDashWidth < nMinDashWidth ) + nDashWidth = nMinDashWidth; + long nTempDotWidth = nDotWidth; + long nTempDashWidth = nDashWidth; + long nEnd = nLeft+nWidth; + while ( nLeft < nEnd ) + { + if ( nLeft+nTempDotWidth > nEnd ) + nTempDotWidth = nEnd-nLeft; + ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight ); + nLeft += nDotWidth*2; + if ( nLeft > nEnd ) + break; + if ( nLeft+nTempDotWidth > nEnd ) + nTempDotWidth = nEnd-nLeft; + ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight ); + nLeft += nDotWidth*2; + if ( nLeft > nEnd ) + break; + if ( nLeft+nTempDashWidth > nEnd ) + nTempDashWidth = nEnd-nLeft; + ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight ); + nLeft += nDashWidth+nDotWidth; + } + } + } + + if ( eStrikeout > STRIKEOUT_LAST ) + eStrikeout = STRIKEOUT_SINGLE; + + if ( eStrikeout == STRIKEOUT_SINGLE ) + { + if ( !pFontEntry->maMetric.mnStrikeoutSize ) + ImplInitTextLineSize(); + nLineHeight = pFontEntry->maMetric.mnStrikeoutSize; + nLinePos = nY + pFontEntry->maMetric.mnStrikeoutOffset; + } + else if ( eStrikeout == STRIKEOUT_BOLD ) + { + if ( !pFontEntry->maMetric.mnBStrikeoutSize ) + ImplInitTextLineSize(); + nLineHeight = pFontEntry->maMetric.mnBStrikeoutSize; + nLinePos = nY + pFontEntry->maMetric.mnBStrikeoutOffset; + } + else if ( eStrikeout == STRIKEOUT_DOUBLE ) + { + if ( !pFontEntry->maMetric.mnDStrikeoutSize ) + ImplInitTextLineSize(); + nLineHeight = pFontEntry->maMetric.mnDStrikeoutSize; + nLinePos = nY + pFontEntry->maMetric.mnDStrikeoutOffset1; + nLinePos2 = nY + pFontEntry->maMetric.mnDStrikeoutOffset2; + } + else + nLineHeight = 0; + + if ( nLineHeight ) + { + nLeft = nX; + + if ( (eStrikeout == STRIKEOUT_SINGLE) || + (eStrikeout == STRIKEOUT_BOLD) ) + ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight ); + else if ( eStrikeout == STRIKEOUT_DOUBLE ) + { + ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight ); + ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight ); + } + } + +#ifdef REMOTE_APPSERVER + SetLineColor( aOldLineColor ); + SetFillColor( aOldFillColor ); +#endif + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplDrawTextLines( long nX, long nY, + const sal_Unicode* pStr, xub_StrLen nLen, + const long* pDXAry, + FontStrikeout eStrikeout, + FontUnderline eUnderline, + BOOL bWordLine ) +{ + if ( bWordLine ) + { + ::rtl::OUString aText( pStr, nLen ); + uno::Reference < text::XBreakIterator > xBI = vcl::unohelper::CreateBreakIterator(); + uno::Reference< linguistic::XHyphenator > xHyph; + text::LineBreakHyphenationOptions aHyphOptions( xHyph, 1 ); + text::LineBreakUserOptions aUserOptions; + + text::Boundary aBoundary = xBI->getWordBoundary( aText, 0, GetSettings().GetLocale(), text::WordType::ANYWORD_IGNOREWHITESPACES, TRUE ); + while ( ( aBoundary.startPos >= 0 ) && ( aBoundary.startPos < nLen ) ) + { + xub_StrLen nWordEnd = Max( (xub_StrLen)aBoundary.endPos, nLen ); + long nTempX = ImplGetTextWidth( pStr, aBoundary.startPos, pDXAry ); + long nWidth = ImplGetTextWidth( pStr+aBoundary.startPos, aBoundary.endPos-aBoundary.startPos, pDXAry ); + ImplDrawTextLine( nX, nX + nTempX, nY, nWidth, eStrikeout, eUnderline ); + aBoundary = xBI->nextWord( aText, aBoundary.endPos, GetSettings().GetLocale(), text::WordType::ANYWORD_IGNOREWHITESPACES ); + } + } + else + { + ImplDrawTextLine( nX, nX, nY, ImplGetTextWidth( pStr, nLen, pDXAry ), eStrikeout, eUnderline ); + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplDrawMnemonicLine( long nX, long nY, xub_Unicode c ) +{ + ImplDrawTextLines( nX, nY, &c, 1, NULL, STRIKEOUT_NONE, UNDERLINE_SINGLE, FALSE ); +} + +// ----------------------------------------------------------------------- + +BOOL OutputDevice::ImplDrawRotateText( long nX, long nY, + const xub_Unicode* pStr, xub_StrLen nLen, + const long* pDXAry ) +{ + if ( !mpOutDevData ) + ImplInitOutDevData(); + if ( !mpOutDevData->mpRotateDev ) + mpOutDevData->mpRotateDev = new VirtualDevice( *this, 1 ); + VirtualDevice* pVDev = mpOutDevData->mpRotateDev; + long nWidth = ImplGetTextWidth( pStr, nLen, pDXAry ); + long nHeight = mpFontEntry->mnLineHeight; + Size aSize( nWidth, nHeight ); + + if ( pVDev->SetOutputSizePixel( aSize ) ) + { + Font aFont( GetFont() ); + Bitmap aBmp; + long nOff; + + nX -= mnTextOffX; + nY -= mnTextOffY; + if ( GetTextAlign() == ALIGN_TOP ) + { + nOff = 0L; + nY += mpFontEntry->maMetric.mnAscent; + } + else if ( GetTextAlign() == ALIGN_BOTTOM ) + { + nOff = mpFontEntry->maMetric.mnAscent; + nY += -mpFontEntry->maMetric.mnDescent; + } + else + nOff = mpFontEntry->maMetric.mnAscent; + + aFont.SetShadow( FALSE ); + aFont.SetOutline( FALSE ); + aFont.SetOrientation( 0 ); + aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) ); + pVDev->SetFont( aFont ); + // Da Farben und Alignment noch im Font haengen, muessen diese jedesmal + // gesetzt werden + pVDev->SetTextAlign( ALIGN_TOP ); + pVDev->SetTextColor( Color( COL_BLACK ) ); + pVDev->SetTextFillColor(); + pVDev->ImplNewFont(); + pVDev->ImplInitFont(); + pVDev->ImplInitTextColor(); + pVDev->ImplDrawText( 0, 0, pStr, nLen, pDXAry ); + + aBmp = pVDev->GetBitmap( Point(), aSize ); + if ( !!aBmp && aBmp.Rotate( mpFontEntry->mnOwnOrientation, COL_WHITE ) ) + { + Point aTempPoint; + Polygon aPoly( Rectangle( aTempPoint, aSize ) ); + long nOldOffX = mnOutOffX; + long nOldOffY = mnOutOffY; + BOOL bOldMap = mbMap; + + aTempPoint.Y() = nOff; + aPoly.Rotate( aTempPoint, mpFontEntry->mnOwnOrientation ); + const Rectangle aBound( aPoly.GetBoundRect() ); + + mnOutOffX = 0L; + mnOutOffY = 0L; + mbMap = FALSE; + + DrawMask( Point( nX + aBound.Left(), + nY + aBound.Top() - mpFontEntry->maMetric.mnAscent ), + aBmp, GetTextColor() ); + + mnOutOffX = nOldOffX; + mnOutOffY = nOldOffY; + mbMap = bOldMap; + } + + return TRUE; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplDrawTextDirect( long nX, long nY, + const xub_Unicode* pStr, xub_StrLen nLen, + const long* pDXAry, + BOOL bTextLines ) +{ + BOOL bDraw = FALSE; + ImplFontEntry* pFontEntry = mpFontEntry; + if ( pFontEntry->mnOwnOrientation ) + bDraw = ImplDrawRotateText( nX, nY, pStr, nLen, pDXAry ); + if ( !bDraw ) + { + if ( !pDXAry ) + { +#ifndef REMOTE_APPSERVER + if ( pFontEntry->mnSetFontFlags & SAL_SETFONT_USEDRAWTEXTARRAY ) + { + long* pCharWidthAry = pFontEntry->maWidthAry; + long nFactor = pFontEntry->mnWidthFactor; + long nOffset = 0; + long aStackAry[128]; + long* pTempDXAry = (long*)ImplGetStackBuffer( sizeof(long)*(nLen-1), aStackAry, sizeof( aStackAry ) ); + for ( USHORT i = 0; i < nLen-1; i++ ) + { + nOffset += ImplGetCharWidth( pStr[i] ); + pTempDXAry[i] = nOffset / nFactor; + } + mpGraphics->DrawTextArray( nX, nY, pStr, nLen, pTempDXAry ); + ImplReleaseStackBuffer( pTempDXAry, aStackAry ); + } + else +#endif + mpGraphics->DrawText( nX, nY, pStr, nLen ); + } + else + { +#ifndef REMOTE_APPSERVER + if ( pFontEntry->mnSetFontFlags & SAL_SETFONT_USEDRAWTEXT ) + { + long* pCharWidthAry = pFontEntry->maWidthAry; + long nFactor = pFontEntry->mnWidthFactor; + long nOffset = 0; + long nDiff; + long nTempX = nX; + const sal_Unicode* pTempStr = pStr; + xub_StrLen nCombineChars = 1; + for ( xub_StrLen i = 0; i < nLen-1; i++ ) + { + nOffset += ImplGetCharWidth( pStr[i] ); + nDiff = (nOffset/nFactor) - pDXAry[i]; + if ( (nDiff < -1) || (nDiff > 0) ) + { + mpGraphics->DrawText( nTempX, nY, pTempStr, nCombineChars ); + nTempX = nX+pDXAry[i]; + nOffset = pDXAry[i]*nFactor; + pTempStr += nCombineChars; + nCombineChars = 1; + } + else + nCombineChars++; + } + mpGraphics->DrawText( nTempX, nY, pTempStr, nCombineChars ); + } + else +#endif + mpGraphics->DrawTextArray( nX, nY, pStr, nLen, pDXAry ); + } + + if ( bTextLines ) + { + ImplDrawTextLines( nX, nY, pStr, nLen, pDXAry, + maFont.GetStrikeout(), + maFont.GetUnderline(), + maFont.IsWordLineMode() ); + } + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplDrawSpecialText( long nX, long nY, + const xub_Unicode* pStr, xub_StrLen nLen, + const long* pDXAry ) +{ + Color aOldColor = GetTextColor(); + Color aOldTextLineColor = GetTextLineColor(); + + if ( maFont.IsShadow() ) + { + long nOff = 1 + ((mpFontEntry->mnLineHeight-24)/24); + if ( maFont.IsOutline() ) + nOff++; + SetTextLineColor(); + if ( GetTextColor().GetColor() == COL_BLACK ) + SetTextColor( Color( COL_LIGHTGRAY ) ); + else + SetTextColor( Color( COL_BLACK ) ); + ImplInitTextColor(); + ImplDrawTextDirect( nX+nOff, nY+nOff, pStr, nLen, pDXAry, mbTextLines ); + SetTextColor( aOldColor ); + SetTextLineColor( aOldTextLineColor ); + ImplInitTextColor(); + + if ( !maFont.IsOutline() ) + ImplDrawTextDirect( nX, nY, pStr, nLen, pDXAry, mbTextLines ); + } + + if ( maFont.IsOutline() ) + { + ImplDrawTextDirect( nX-1, nY+1, pStr, nLen, pDXAry, mbTextLines ); + ImplDrawTextDirect( nX, nY+1, pStr, nLen, pDXAry, mbTextLines ); + ImplDrawTextDirect( nX+1, nY+1, pStr, nLen, pDXAry, mbTextLines ); + ImplDrawTextDirect( nX-1, nY, pStr, nLen, pDXAry, mbTextLines ); + ImplDrawTextDirect( nX+1, nY, pStr, nLen, pDXAry, mbTextLines ); + ImplDrawTextDirect( nX-1, nY-1, pStr, nLen, pDXAry, mbTextLines ); + ImplDrawTextDirect( nX, nY-1, pStr, nLen, pDXAry, mbTextLines ); + ImplDrawTextDirect( nX+1, nY-1, pStr, nLen, pDXAry, mbTextLines ); + + SetTextColor( Color( COL_WHITE ) ); + SetTextLineColor( Color( COL_WHITE ) ); + ImplInitTextColor(); + ImplDrawTextDirect( nX, nY, pStr, nLen, pDXAry, mbTextLines ); + SetTextColor( aOldColor ); + SetTextLineColor( aOldTextLineColor ); + ImplInitTextColor(); + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplDrawText( long nX, long nY, + const xub_Unicode* pStr, xub_StrLen nLen, const long* pDXAry ) +{ + nX += mnTextOffX; + nY += mnTextOffY; + + if ( IsTextFillColor() ) + ImplDrawTextBackground( nX, nY, pStr, nLen, pDXAry ); + + if ( mbTextSpecial ) + ImplDrawSpecialText( nX, nY, pStr, nLen, pDXAry ); + else + ImplDrawTextDirect( nX, nY, pStr, nLen, pDXAry, mbTextLines ); +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplFillDXAry( long* pDXAry, + const xub_Unicode* pStr, xub_StrLen nLen, long nWidth ) +{ + ImplFontEntry* pFontEntry = mpFontEntry; + long* pCharWidthAry = pFontEntry->maWidthAry; + long nFactor = pFontEntry->mnWidthFactor; + + // Breiten-Array fuer errechnete Werte mit den Breiten der einzelnen + // Character fuellen + xub_StrLen i; + long nSum = 0; + for ( i = 0; i < nLen; i++ ) + { + // Characterbreiten ueber Array holen + nSum += ImplGetCharWidth( pStr[i] ); + pDXAry[i] = nSum / nFactor; + } + nSum /= nFactor; + + // Differenz zwischen Soll- und Ist-Laenge errechnen + // Zusaetzliche Pixel per Character errechnen + // Anzahl der zusaetzlich verbliebenen Pixel errechnen + long nDelta = (long)nWidth - nSum; + long nDeltaPerChar = 0; + long nDeltaRest = 0; + if ( nLen > 1 ) + { + nDeltaPerChar = nDelta / (long)(nLen-1); + nDeltaRest = nDelta % (long)(nLen-1); + } + long nDeltaRestAbs = Abs( nDeltaRest ); + + long nErrorSum = nDeltaRestAbs; + long nDeltaSum = 0; + for ( i = 0; i < nLen-1; i++, nErrorSum += nDeltaRestAbs ) + { + nDeltaSum += nDeltaPerChar; + if ( nErrorSum >= nLen-1 ) + { + nErrorSum -= nLen-1; + if ( nDeltaRest > 0 ) + nDeltaSum++; + else if ( nDeltaRest < 0 ) + nDeltaSum--; + } + pDXAry[i] += nDeltaSum; + } +} + +// ----------------------------------------------------------------------- + +long OutputDevice::ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo, + long nWidth, const XubString& rStr, + USHORT nStyle ) const +{ + DBG_ASSERT( nWidth >= 0, "ImplGetTextLines: nWidth <= 0!" ); + + long nMaxLineWidth = 0; + rLineInfo.Clear(); + if ( rStr.Len() && ( nWidth > 0 ) ) + { + ::rtl::OUString aText( rStr ); + uno::Reference < text::XBreakIterator > xBI; + uno::Reference< linguistic::XHyphenator > xHyph; + text::LineBreakHyphenationOptions aHyphOptions( xHyph, 1 ); + text::LineBreakUserOptions aUserOptions; + + USHORT nPos = 0; + USHORT nLen = rStr.Len(); + while ( nPos < nLen ) + { + xub_StrLen nBreakPos = nPos; + while ( ( nBreakPos < nLen ) && ( rStr.GetChar( nBreakPos ) != _CR ) && ( rStr.GetChar( nBreakPos ) != _LF ) ) + nBreakPos++; + + long nLineWidth = GetTextWidth( rStr, nPos, nBreakPos-nPos ); + if ( ( nLineWidth > nWidth ) && ( nStyle & TEXT_DRAW_WORDBREAK ) ) + { + if ( !xBI.is() ) + xBI = vcl::unohelper::CreateBreakIterator(); + + xub_StrLen nSoftBreak = GetTextBreak( rStr, nWidth, nPos, nBreakPos - nPos ); + DBG_ASSERT( nSoftBreak < nBreakPos, "Break?!" ); + text::LineBreakResults aLBR = xBI->getLineBreak( aText, nSoftBreak, GetSettings().GetLocale(), nPos, aHyphOptions, aUserOptions ); + nBreakPos = aLBR.breakIndex; + if ( nBreakPos <= nPos ) + nBreakPos = nSoftBreak; + nLineWidth = GetTextWidth( rStr, nPos, nBreakPos-nPos ); + } + + if ( nLineWidth > nMaxLineWidth ) + nMaxLineWidth = nLineWidth; + + if ( ( rStr.GetChar( nBreakPos ) == _CR ) || ( rStr.GetChar( nBreakPos ) == _LF ) ) + { + nBreakPos++; + // CR/LF? + if ( ( nPos < nLen ) && ( rStr.GetChar( nBreakPos ) == _LF ) && ( rStr.GetChar( nBreakPos-1 ) == _CR ) ) + nBreakPos++; + } + + if ( nBreakPos == nPos ) + nBreakPos++; + + rLineInfo.AddLine( new ImplTextLineInfo( nLineWidth, nPos, nBreakPos-nPos ) ); + + nPos = nBreakPos; + } + } + + return nMaxLineWidth; +} + +// ======================================================================= + +void OutputDevice::SetFont( const Font& rNewFont ) +{ + DBG_TRACE( "OutputDevice::SetFont()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rNewFont, Font, NULL ); + + Font aFont( rNewFont ); + + if ( mnDrawMode & (DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT | DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT | + DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL | DRAWMODE_GRAYFILL | DRAWMODE_NOFILL | + DRAWMODE_GHOSTEDFILL) ) + { + Color aTextColor( aFont.GetColor() ); + if ( mnDrawMode & DRAWMODE_BLACKTEXT ) + aTextColor = Color( COL_BLACK ); + else if ( mnDrawMode & DRAWMODE_WHITETEXT ) + aTextColor = Color( COL_WHITE ); + else if ( mnDrawMode & DRAWMODE_GRAYTEXT ) + { + const UINT8 cLum = aTextColor.GetLuminance(); + aTextColor = Color( cLum, cLum, cLum ); + } + if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT ) + { + aTextColor = Color( (aTextColor.GetRed() >> 1 ) | 0x80, + (aTextColor.GetGreen() >> 1 ) | 0x80, + (aTextColor.GetBlue() >> 1 ) | 0x80 ); + } + aFont.SetColor( aTextColor ); + + BOOL bTransFill = aFont.IsTransparent(); + if ( !bTransFill ) + { + Color aTextFillColor( aFont.GetFillColor() ); + if ( mnDrawMode & DRAWMODE_BLACKFILL ) + aTextFillColor = Color( COL_BLACK ); + else if ( mnDrawMode & DRAWMODE_WHITEFILL ) + aTextFillColor = Color( COL_WHITE ); + else if ( mnDrawMode & DRAWMODE_GRAYFILL ) + { + const UINT8 cLum = aTextFillColor.GetLuminance(); + aTextFillColor = Color( cLum, cLum, cLum ); + } + else if ( mnDrawMode & DRAWMODE_NOFILL ) + { + aTextFillColor = Color( COL_TRANSPARENT ); + bTransFill = TRUE; + } + if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) ) + { + aTextFillColor = Color( (aTextFillColor.GetRed() >> 1) | 0x80, + (aTextFillColor.GetGreen() >> 1) | 0x80, + (aTextFillColor.GetBlue() >> 1) | 0x80 ); + } + aFont.SetFillColor( aTextFillColor ); + } + } + + if ( mpMetaFile ) + { + const Color& rTextFillColor = aFont.GetFillColor(); + + mpMetaFile->AddAction( new MetaFontAction( aFont ) ); + mpMetaFile->AddAction( new MetaTextAlignAction( aFont.GetAlign() ) ); + mpMetaFile->AddAction( new MetaTextColorAction( aFont.GetColor() ) ); + mpMetaFile->AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) ); + } + + if ( !maFont.IsSameInstance( aFont ) ) + { + if ( maFont.GetColor() != aFont.GetColor() ) + mbInitTextColor = TRUE; + maFont = aFont; + mbNewFont = TRUE; + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetTextColor( const Color& rColor ) +{ + DBG_TRACE( "OutputDevice::SetTextColor()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + Color aColor( rColor ); + + if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT | + DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT ) ) + { + if ( mnDrawMode & DRAWMODE_BLACKTEXT ) + aColor = Color( COL_BLACK ); + else if ( mnDrawMode & DRAWMODE_WHITETEXT ) + aColor = Color( COL_WHITE ); + else if ( mnDrawMode & DRAWMODE_GRAYTEXT ) + { + const UINT8 cLum = aColor.GetLuminance(); + aColor = Color( cLum, cLum, cLum ); + } + + if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT ) + { + aColor = Color( (aColor.GetRed() >> 1) | 0x80, + (aColor.GetGreen() >> 1) | 0x80, + (aColor.GetBlue() >> 1) | 0x80 ); + } + } + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaTextColorAction( aColor ) ); + + if ( maFont.GetColor() != aColor ) + { + maFont.SetColor( aColor ); + mbInitTextColor = TRUE; + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetTextFillColor() +{ + DBG_TRACE( "OutputDevice::SetTextFillColor()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaTextFillColorAction( Color(), FALSE ) ); + + if ( maFont.GetColor() != Color( COL_TRANSPARENT ) ) + maFont.SetFillColor( Color( COL_TRANSPARENT ) ); + if ( !maFont.IsTransparent() ) + maFont.SetTransparent( TRUE ); +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetTextFillColor( const Color& rColor ) +{ + DBG_TRACE( "OutputDevice::SetTextFillColor()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + Color aColor( rColor ); + BOOL bTransFill = ImplIsColorTransparent( aColor ); + + if ( !bTransFill ) + { + if ( mnDrawMode & ( DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL | + DRAWMODE_GRAYFILL | DRAWMODE_NOFILL | + DRAWMODE_GHOSTEDFILL ) ) + { + if ( mnDrawMode & DRAWMODE_BLACKFILL ) + aColor = Color( COL_BLACK ); + else if ( mnDrawMode & DRAWMODE_WHITEFILL ) + aColor = Color( COL_WHITE ); + else if ( mnDrawMode & DRAWMODE_GRAYFILL ) + { + const UINT8 cLum = aColor.GetLuminance(); + aColor = Color( cLum, cLum, cLum ); + } + else if ( mnDrawMode & DRAWMODE_NOFILL ) + { + aColor = Color( COL_TRANSPARENT ); + bTransFill = TRUE; + } + if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) ) + { + aColor = Color( (aColor.GetRed() >> 1) | 0x80, + (aColor.GetGreen() >> 1) | 0x80, + (aColor.GetBlue() >> 1) | 0x80 ); + } + } + } + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaTextFillColorAction( aColor, TRUE ) ); + + if ( maFont.GetFillColor() != aColor ) + maFont.SetFillColor( aColor ); + if ( maFont.IsTransparent() != bTransFill ) + maFont.SetTransparent( bTransFill ); +} + +// ----------------------------------------------------------------------- + +Color OutputDevice::GetTextFillColor() const +{ + if ( maFont.IsTransparent() ) + return Color( COL_TRANSPARENT ); + else + return maFont.GetFillColor(); +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetTextLineColor() +{ + DBG_TRACE( "OutputDevice::SetTextLineColor()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaTextLineColorAction( Color(), FALSE ) ); + + maTextLineColor = Color( COL_TRANSPARENT ); +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetTextLineColor( const Color& rColor ) +{ + DBG_TRACE( "OutputDevice::SetTextLineColor()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + Color aColor( rColor ); + + if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT | + DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT ) ) + { + if ( mnDrawMode & DRAWMODE_BLACKTEXT ) + aColor = Color( COL_BLACK ); + else if ( mnDrawMode & DRAWMODE_WHITETEXT ) + aColor = Color( COL_WHITE ); + else if ( mnDrawMode & DRAWMODE_GRAYTEXT ) + { + const UINT8 cLum = aColor.GetLuminance(); + aColor = Color( cLum, cLum, cLum ); + } + + if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT ) + { + aColor = Color( (aColor.GetRed() >> 1) | 0x80, + (aColor.GetGreen() >> 1) | 0x80, + (aColor.GetBlue() >> 1) | 0x80 ); + } + } + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaTextLineColorAction( aColor, TRUE ) ); + + maTextLineColor = aColor; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetTextAlign( TextAlign eAlign ) +{ + DBG_TRACE( "OutputDevice::SetTextAlign()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaTextAlignAction( eAlign ) ); + + if ( maFont.GetAlign() != eAlign ) + { + maFont.SetAlign( eAlign ); + mbNewFont = TRUE; + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawTextLine( const Point& rPos, long nWidth, + FontStrikeout eStrikeout, + FontUnderline eUnderline ) +{ + DBG_TRACE( "OutputDevice::DrawTextLine()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaTextLineAction( rPos, nWidth, eStrikeout, eUnderline ) ); + + if ( ((eUnderline == UNDERLINE_NONE) || (eUnderline == UNDERLINE_DONTKNOW)) && + ((eStrikeout == STRIKEOUT_NONE) || (eStrikeout == STRIKEOUT_DONTKNOW)) ) + return; + + if ( !IsDeviceOutputNecessary() ) + return; + +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; +#else + if ( !ImplGetServerGraphics() ) + return; +#endif + + if ( mbNewFont ) + { + if ( !ImplNewFont() ) + return; + } + + Point aPos = ImplLogicToDevicePixel( rPos ); + nWidth = ImplLogicWidthToDevicePixel( nWidth ); + aPos.X() += mnTextOffX; + aPos.Y() += mnTextOffY; + ImplDrawTextLine( aPos.X(), aPos.X(), aPos.Y(), nWidth, eStrikeout, eUnderline ); +} + +// ------------------------------------------------------------------------ + +void OutputDevice::DrawWaveLine( const Point& rStartPos, const Point& rEndPos, + USHORT nStyle ) +{ + DBG_TRACE( "OutputDevice::DrawWaveLine()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + +#ifndef REMOTE_APPSERVER + if ( !IsDeviceOutputNecessary() ) + return; + + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; + + Point aStartPt = ImplLogicToDevicePixel( rStartPos ); + Point aEndPt = ImplLogicToDevicePixel( rEndPos ); + long nStartX = aStartPt.X(); + long nStartY = aStartPt.Y(); + long nEndX = aEndPt.X(); + long nEndY = aEndPt.Y(); + short nOrientation = 0; + + if ( (nStartY != nEndY) || (nStartX > nEndX) ) + { + long nDX = nEndX - nStartX; + double nO = atan2( -nEndY + nStartY, ((nDX == 0L) ? 0.000000001 : nDX) ); + nO /= F_PI1800; + nOrientation = (short)nO; + ImplRotatePos( nStartX, nStartY, nEndX, nEndY, -nOrientation ); + } + + long nWaveHeight; + if ( nStyle == WAVE_NORMAL ) + { + nWaveHeight = 3; + nStartY++; + nEndY++; + } + else if( nStyle == WAVE_SMALL ) + { + nWaveHeight = 2; + nStartY++; + nEndY++; + } + else // WAVE_FLAT + nWaveHeight = 1; + + ImplDrawWaveLine( nStartX, nStartY, nStartX, nStartY, + nEndX-nStartX, nWaveHeight, 1, + nOrientation, GetLineColor() ); +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + if ( mbInitLineColor ) + ImplInitLineColor(); + + Point aPos1 = ImplLogicToDevicePixel( rStartPos ); + Point aPos2 = ImplLogicToDevicePixel( rEndPos ); + pGraphics->DrawWaveLine( aPos1, aPos2, nStyle ); + } +#endif +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawText( const Point& rStartPt, const XubString& rStr, + xub_StrLen nIndex, xub_StrLen nLen ) +{ + DBG_TRACE( "OutputDevice::DrawText()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) ); + + if ( !IsDeviceOutputNecessary() ) + return; + + // String-Laenge fuer die Ermittlung der Groesse setzen + if ( (ULONG)nLen+nIndex > rStr.Len() ) + { + if ( nIndex < rStr.Len() ) + nLen = rStr.Len()-nIndex; + else + nLen = 0; + } + + // Ist die Ausgabe leer, dann mache nichts + if ( !nLen ) + return; + +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; +#else + if ( !ImplGetServerGraphics() ) + return; +#endif + + if ( mbNewFont ) + ImplNewFont(); + if ( mbInitFont ) + ImplInitFont(); + if ( mbInitTextColor ) + ImplInitTextColor(); + + Point aStartPt = ImplLogicToDevicePixel( rStartPt ); + + // Pointer auf den String-Buffer setzen und um den Index korrigieren + const sal_Unicode* pStr = rStr.GetBuffer(); + pStr += nIndex; + + if ( mbKerning ) + { + ImplFontEntry* pFontEntry = mpFontEntry; + long* pCharWidthAry = pFontEntry->maWidthAry; + long nFactor = pFontEntry->mnWidthFactor; + USHORT i; + + // DX-Array berechnen + long nOffset = 0; + long aStackAry[128]; + long* pDXAry = (long*)ImplGetStackBuffer( sizeof(long)*(nLen-1), aStackAry, sizeof( aStackAry ) ); + for ( i = 0; i < nLen-1; i++ ) + { + nOffset += pCharWidthAry[(unsigned char)pStr[i]]; + pDXAry[i] = nOffset / nFactor; + } + ImplCalcKerning( pStr, nLen, pDXAry, nLen-1 ); + ImplDrawText( aStartPt.X(), aStartPt.Y(), pStr, nLen, pDXAry ); + ImplReleaseStackBuffer( pDXAry, aStackAry ); + } + else + ImplDrawText( aStartPt.X(), aStartPt.Y(), pStr, nLen, NULL ); +} + +// ----------------------------------------------------------------------- + +long OutputDevice::GetTextWidth( const XubString& rStr, + xub_StrLen nIndex, xub_StrLen nLen ) const +{ + DBG_TRACE( "OutputDevice::GetTextWidth()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mbNewFont ) + { + if ( !((OutputDevice*)this)->ImplNewFont() ) + return 0; + } + + ImplFontEntry* pFontEntry = mpFontEntry; + long nWidth = 0; + + if ( nIndex < rStr.Len() ) + { + // String-Laenge fuer die Ermittlung der Groesse setzen + if ( (ULONG)nLen+nIndex > rStr.Len() ) + nLen = rStr.Len()-nIndex; + + if ( nLen ) + { + long* pCharWidthAry = pFontEntry->maWidthAry; + + // Bei Fixed-Fonts reicht eine Multiplikation + if ( pFontEntry->mbFixedFont ) + { + nWidth = pCharWidthAry['A'] * nLen; + nWidth /= pFontEntry->mnWidthFactor; + } + else + { + const sal_Unicode* pStr = rStr.GetBuffer(); + const sal_Unicode* pTempStr; + USHORT nTempLen; + pStr += nIndex; + pTempStr = pStr; + nTempLen = nLen; + while ( nTempLen ) + { + nWidth += ImplGetCharWidth( *pTempStr ); + nTempLen--; + pTempStr++; + } + nWidth /= pFontEntry->mnWidthFactor; + + // Kerning beruecksichtigen (tun wir nur bei Fonts ohne feste Breite) + if ( mbKerning ) + nWidth += ImplCalcKerning( pStr, nLen, NULL, 0 ); + } + } + } + + if ( mbMap ) + nWidth = ImplDevicePixelToLogicWidth( nWidth ); + + return nWidth; +} + +// ----------------------------------------------------------------------- + +long OutputDevice::GetTextHeight() const +{ + DBG_TRACE( "OutputDevice::GetTextHeight()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mbNewFont ) + { + if ( !((OutputDevice*)this)->ImplNewFont() ) + return 0; + } + + long nHeight = mpFontEntry->mnLineHeight; + + if ( mbMap ) + nHeight = ImplDevicePixelToLogicHeight( nHeight ); + + return nHeight; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawTextArray( const Point& rStartPt, const XubString& rStr, + const long* pDXAry, + xub_StrLen nIndex, xub_StrLen nLen ) +{ + DBG_TRACE( "OutputDevice::DrawTextArray()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) ); + + if ( !IsDeviceOutputNecessary() ) + return; + + // String-Laenge fuer die Ermittlung der Groesse setzen + if ( (ULONG)nLen+nIndex > rStr.Len() ) + { + if ( nIndex < rStr.Len() ) + nLen = rStr.Len()-nIndex; + else + nLen = 0; + } + + // Ist die Ausgabe leer, dann mache nichts + if ( !nLen ) + return; + + // Bei keinem Pos-Array, DrawText benutzen + if ( !pDXAry || (nLen < 2) ) + { + // hier Aufrufen, damit keine doppelte MetaFile Aufzeichnung + DrawText( rStartPt, rStr, nIndex, nLen ); + return; + } + +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; +#else + if ( !ImplGetServerGraphics() ) + return; +#endif + + if ( mbNewFont ) + { + if ( !ImplNewFont() ) + return; + } + if ( mbInitFont ) + ImplInitFont(); + if ( mbInitTextColor ) + ImplInitTextColor(); + + // Pointer auf den String-Buffer setzen und um den Index korrigieren + const sal_Unicode* pStr = rStr.GetBuffer(); + pStr += nIndex; + + Point aStartPt = ImplLogicToDevicePixel( rStartPt ); + if ( mbMap ) + { + long nLogStartX = rStartPt.X(); + long nPixStartX = aStartPt.X(); + long aStackAry[128]; + long* pPixDXAry = (long*)ImplGetStackBuffer( sizeof(long)*(nLen-1), aStackAry, sizeof( aStackAry ) ); + for ( xub_StrLen i = 0; i < (nLen-1); i++ ) + pPixDXAry[i] = ImplLogicXToDevicePixel( nLogStartX+pDXAry[i] )-nPixStartX; + ImplDrawText( aStartPt.X(), aStartPt.Y(), pStr, nLen, pPixDXAry ); + ImplReleaseStackBuffer( pPixDXAry, aStackAry ); + } + else + ImplDrawText( aStartPt.X(), aStartPt.Y(), pStr, nLen, pDXAry ); +} + +// ----------------------------------------------------------------------- + +long OutputDevice::GetTextArray( const UniString& rStr, long* pDXAry, + xub_StrLen nIndex, xub_StrLen nLen ) const +{ + DBG_TRACE( "OutputDevice::GetTextArray()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( !pDXAry ) + return GetTextWidth( rStr, nIndex, nLen ); + + // String-Laenge fuer die Ermittlung der Groesse setzen + if ( (ULONG)nLen+nIndex > rStr.Len() ) + { + if ( nIndex < rStr.Len() ) + nLen = rStr.Len()-nIndex; + else + nLen = 0; + } + + if ( !nLen ) + return 0; + + if ( mbNewFont ) + { + if ( !((OutputDevice*)this)->ImplNewFont() ) + return 0; + } + + ImplFontEntry* pFontEntry = mpFontEntry; + long* pCharWidthAry = pFontEntry->maWidthAry; + long nFactor = pFontEntry->mnWidthFactor; + const sal_Unicode* pTempStr; + const sal_Unicode* pStr; + long nOffset = 0; + xub_StrLen i; + pStr = rStr.GetBuffer(); + pStr += nIndex; + pTempStr = pStr; + + // Breiten ermitteln + for ( i = 0; i < nLen; i++ ) + { + nOffset += ImplGetCharWidth( *pTempStr ); + pDXAry[i] = nOffset / nFactor; + pTempStr++; + } + + // Kerning beruecksichtigen + if ( mbKerning ) + ImplCalcKerning( pStr, nLen, pDXAry, nLen ); + + // Breite und Hoehe ermitteln + long nWidth = pDXAry[nLen-1]; + + // Wenn MapMode gesetzt, dann Werte umrechnen + if ( mbMap ) + { + for ( i = 0; i < nLen; i++ ) + pDXAry[i] = ImplDevicePixelToLogicWidth( pDXAry[i] ); + + nWidth = ImplDevicePixelToLogicWidth( nWidth ); + } + + return nWidth; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawStretchText( const Point& rStartPt, ULONG nWidth, + const UniString& rStr, + xub_StrLen nIndex, xub_StrLen nLen ) +{ + DBG_TRACE( "OutputDevice::DrawStretchText()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaStretchTextAction( rStartPt, nWidth, rStr, nIndex, nLen ) ); + + if ( !IsDeviceOutputNecessary() ) + return; + + // String-Laenge fuer die Ermittlung der Groesse setzen + if ( (ULONG)nLen+nIndex > rStr.Len() ) + { + if ( nIndex < rStr.Len() ) + nLen = rStr.Len()-nIndex; + else + nLen = 0; + } + + // Ist die Ausgabe leer, dann mache nichts + if ( !nLen ) + return; + +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; +#else + if ( !ImplGetServerGraphics() ) + return; +#endif + + if ( mbNewFont ) + { + if ( !ImplNewFont() ) + return; + } + if ( mbInitFont ) + ImplInitFont(); + if ( mbInitTextColor ) + ImplInitTextColor(); + + Point aStartPt = ImplLogicToDevicePixel( rStartPt ); + nWidth = ImplLogicWidthToDevicePixel( nWidth ); + + // Pointer auf den String-Buffer setzen und um den Index korrigieren + const sal_Unicode* pStr = rStr.GetBuffer(); + pStr += nIndex; + + // Breiten-Array fuer errechnete Werte allocieren und + // mit den Breiten der einzelnen Character fuellen lassen + long aStackAry[128]; + long* pDXAry = (long*)ImplGetStackBuffer( sizeof(long)*nLen, aStackAry, sizeof( aStackAry ) ); + ImplFillDXAry( pDXAry, pStr, nLen, (long)nWidth ); + ImplDrawText( aStartPt.X(), aStartPt.Y(), pStr, nLen, pDXAry ); + ImplReleaseStackBuffer( pDXAry, aStackAry ); +} + +// ----------------------------------------------------------------------- + +xub_StrLen OutputDevice::GetTextBreak( const XubString& rStr, long nTextWidth, + xub_StrLen nIndex, xub_StrLen nLen, + long nCharExtra ) const +{ + DBG_TRACE( "OutputDevice::GetTextBreak()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( nIndex > rStr.Len() ) + return 0; + + if ( mbNewFont ) + { + if ( !((OutputDevice*)this)->ImplNewFont() ) + return 0; + } + + ImplFontEntry* pFontEntry = mpFontEntry; + long* pCharWidthAry = pFontEntry->maWidthAry; + long nFactor = pFontEntry->mnWidthFactor; + const sal_Unicode* pStr; + long nCalcWidth = 0; + xub_StrLen nLastIndex; + + if ( mbMap ) + { + nTextWidth = ImplLogicWidthToDevicePixel( nTextWidth*10 ); + nTextWidth *= nFactor; + nTextWidth /= 10; + if ( nCharExtra ) + { + nCharExtra = ImplLogicWidthToDevicePixel( nCharExtra*10 ); + nCharExtra *= nFactor; + nCharExtra /= 10; + } + } + else + { + nCharExtra *= nFactor; + nTextWidth *= nFactor; + } + + // Letzte Index-Position ermitteln + if ( (ULONG)nIndex+nLen > rStr.Len() ) + nLastIndex = rStr.Len(); + else + nLastIndex = nIndex + nLen; + + pStr = rStr.GetBuffer(); + pStr += nIndex; + while ( nIndex < nLastIndex ) + { + nCalcWidth += ImplGetCharWidth( *pStr ); + + if ( nCalcWidth > nTextWidth ) + return nIndex; + + // Kerning beruecksichtigen + if ( mbKerning ) + nCalcWidth += ImplCalcKerning( pStr, 2, NULL, 0 )*nFactor; + nCalcWidth += nCharExtra; + + nIndex++; + pStr++; + } + + return STRING_LEN; +} + +// ----------------------------------------------------------------------- + +xub_StrLen OutputDevice::GetTextBreak( const XubString& rStr, long nTextWidth, + sal_Unicode nExtraChar, xub_StrLen& rExtraCharPos, + xub_StrLen nIndex, xub_StrLen nLen, + long nCharExtra ) const +{ + DBG_TRACE( "OutputDevice::GetTextBreak()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( nIndex > rStr.Len() ) + return 0; + + if ( mbNewFont ) + { + if ( !((OutputDevice*)this)->ImplNewFont() ) + return 0; + } + + ImplFontEntry* pFontEntry = mpFontEntry; + long* pCharWidthAry = pFontEntry->maWidthAry; + long nFactor = pFontEntry->mnWidthFactor; + const sal_Unicode* pStr; + long nTextWidth2; + long nCalcWidth = 0; + xub_StrLen nIndex2 = STRING_LEN; + xub_StrLen nLastIndex; + + if ( mbMap ) + { + nTextWidth = ImplLogicWidthToDevicePixel( nTextWidth*10 ); + nTextWidth *= nFactor; + nTextWidth /= 10; + if ( nCharExtra ) + { + nCharExtra = ImplLogicWidthToDevicePixel( nCharExtra*10 ); + nCharExtra *= nFactor; + nCharExtra /= 10; + } + } + else + { + nCharExtra *= nFactor; + nTextWidth *= nFactor; + } + + // Letzte Index-Position ermitteln + if ( (ULONG)nIndex+nLen > rStr.Len() ) + nLastIndex = rStr.Len(); + else + nLastIndex = nIndex + nLen; + + nTextWidth2 = nTextWidth - ImplGetCharWidth( nExtraChar ) - nCharExtra; + + pStr = rStr.GetBuffer(); + pStr += nIndex; + while ( nIndex < nLastIndex ) + { + nCalcWidth += ImplGetCharWidth( *pStr ); + + if ( nCalcWidth > nTextWidth2 ) + { + if ( nIndex2 == STRING_LEN ) + nIndex2 = nIndex; + } + if ( nCalcWidth > nTextWidth ) + { + if ( nIndex2 == STRING_LEN ) + rExtraCharPos = nIndex; + else + rExtraCharPos = nIndex2; + return nIndex; + } + + // Kerning beruecksichtigen + if ( mbKerning ) + nCalcWidth += ImplCalcKerning( pStr, 2, NULL, 0 )*nFactor; + nCalcWidth += nCharExtra; + + nIndex++; + pStr++; + } + + rExtraCharPos = nIndex2; + return STRING_LEN; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::GetCharWidth( sal_Unicode nFirstChar, sal_Unicode nLastChar, + long* pWidthAry ) const +{ + DBG_TRACE( "OutputDevice::GetCharWidth()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_ASSERT( nFirstChar <= nLastChar, "OutputDevice::GetCharWidth(): nFirst > nLast" ); + + if ( mbNewFont ) + { + if ( !((OutputDevice*)this)->ImplNewFont() ) + return; + } + + long nFactor = mpFontEntry->mnWidthFactor; + sal_Unicode nCharCount = nLastChar-nFirstChar+1; + + if ( mbMap ) + { + while ( nCharCount ) + { + *pWidthAry = ImplDevicePixelToLogicWidth( ImplGetCharWidth( nFirstChar ) ) / nFactor; + pWidthAry++; + nFirstChar++; + nCharCount--; + } + } + else + { + while ( nCharCount ) + { + *pWidthAry = ImplGetCharWidth( nFirstChar ) / nFactor; + pWidthAry++; + nFirstChar++; + nCharCount--; + } + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawText( const Rectangle& rRect, + const XubString& rStr, USHORT nStyle ) +{ + DBG_TRACE( "OutputDevice::DrawText( const Rectangle& )" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaTextRectAction( rRect, rStr, nStyle ) ); + + if ( !IsDeviceOutputNecessary() || !rStr.Len() || rRect.IsEmpty() ) + return; + + // Vorsichtshalber hier auch schon Aufrufen, da ImplDrawMnemonicLine() + // dies nicht macht +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; +#else + if ( !ImplGetServerGraphics() ) + return; +#endif + + Color aOldTextColor; + Color aOldTextFillColor; + BOOL bRestoreFillColor; + if ( nStyle & TEXT_DRAW_DISABLE ) + { + aOldTextColor = GetTextColor(); + if ( IsTextFillColor() ) + { + bRestoreFillColor = TRUE; + aOldTextFillColor = GetTextFillColor(); + } + else + bRestoreFillColor = FALSE; + SetTextColor( GetSettings().GetStyleSettings().GetLightColor() ); + Rectangle aRect = rRect; + aRect.Move( 1, 1 ); + DrawText( aRect, rStr, nStyle & ~TEXT_DRAW_DISABLE ); + SetTextColor( GetSettings().GetStyleSettings().GetShadowColor() ); + } + + long nWidth = rRect.GetWidth(); + long nHeight = rRect.GetHeight(); + + if ( ((nWidth <= 0) || (nHeight <= 0)) && (nStyle & TEXT_DRAW_CLIP) ) + return; + + XubString aStr = rStr; + Point aPos = rRect.TopLeft(); + long nTextHeight = GetTextHeight(); + TextAlign eAlign = GetTextAlign(); + xub_StrLen nMnemonicPos = STRING_NOTFOUND; + + if ( nStyle & TEXT_DRAW_MNEMONIC ) + aStr = GetNonMnemonicString( aStr, nMnemonicPos ); + + // Mehrzeiligen Text behandeln wir anders + if ( nStyle & TEXT_DRAW_MULTILINE ) + { + XubString aLastLine; + ImplMultiTextLineInfo aMultiLineInfo; + ImplTextLineInfo* pLineInfo; + long nMaxTextWidth; + xub_StrLen i; + xub_StrLen nLines; + xub_StrLen nFormatLines; + + if ( nTextHeight ) + { + nMaxTextWidth = ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle ); + nLines = (xub_StrLen)(nHeight/nTextHeight); + nFormatLines = aMultiLineInfo.Count(); + if ( !nLines ) + nLines = 1; + if ( nFormatLines > nLines ) + { + if ( nStyle & TEXT_DRAW_ENDELLIPSIS ) + { + // Letzte Zeile zusammenbauen und kuerzen + nFormatLines = nLines-1; + pLineInfo = aMultiLineInfo.GetLine( nFormatLines ); + aLastLine = aStr.Copy( pLineInfo->GetIndex() ); + aLastLine.ConvertLineEnd( LINEEND_LF ); + // Alle LineFeed's durch Spaces ersetzen + xub_StrLen nLastLineLen = aLastLine.Len(); + for ( i = 0; i < nLastLineLen; i++ ) + { + if ( aLastLine.GetChar( i ) == _LF ) + aLastLine.SetChar( i, ' ' ); + } + aLastLine = GetEllipsisString( aLastLine, nWidth, nStyle ); + nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM); + nStyle |= TEXT_DRAW_TOP; + } + } + else + { + if ( nMaxTextWidth <= nWidth ) + nStyle &= ~TEXT_DRAW_CLIP; + } + + // Muss in der Hoehe geclippt werden? + if ( nFormatLines*nTextHeight > nHeight ) + nStyle |= TEXT_DRAW_CLIP; + + // Clipping setzen + if ( nStyle & TEXT_DRAW_CLIP ) + { + Push( PUSH_CLIPREGION ); + IntersectClipRegion( rRect ); + } + + // Vertikales Alignment + if ( nStyle & TEXT_DRAW_BOTTOM ) + aPos.Y() += nHeight-(nFormatLines*nTextHeight); + else if ( nStyle & TEXT_DRAW_VCENTER ) + aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2; + + // Font Alignment + if ( eAlign == ALIGN_BOTTOM ) + aPos.Y() += nTextHeight; + else if ( eAlign == ALIGN_BASELINE ) + aPos.Y() += GetFontMetric().GetAscent(); + + // Alle Zeilen ausgeben, bis auf die letzte + for ( i = 0; i < nFormatLines; i++ ) + { + pLineInfo = aMultiLineInfo.GetLine( i ); + if ( nStyle & TEXT_DRAW_RIGHT ) + aPos.X() += nWidth-pLineInfo->GetWidth(); + else if ( nStyle & TEXT_DRAW_CENTER ) + aPos.X() += (nWidth-pLineInfo->GetWidth())/2; + xub_StrLen nIndex = pLineInfo->GetIndex(); + xub_StrLen nLineLen = pLineInfo->GetLen(); + DrawText( aPos, aStr, nIndex, nLineLen ); + if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) ) + { + if ( (nMnemonicPos >= nIndex) && (nMnemonicPos < nIndex+nLineLen) ) + { + long nMnemonicX; + long nMnemonicY; + xub_Unicode cMnemonic; + Point aTempPos = LogicToPixel( aPos ); + cMnemonic = aStr.GetChar( nMnemonicPos ); + nMnemonicX = mnOutOffX + aTempPos.X() + ImplLogicWidthToDevicePixel( GetTextWidth( aStr, nIndex, nMnemonicPos-nIndex ) ); + nMnemonicY = mnOutOffY + aTempPos.Y() + ImplLogicWidthToDevicePixel( GetFontMetric().GetAscent() ); + ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, cMnemonic ); + } + } + aPos.Y() += nTextHeight; + aPos.X() = rRect.Left(); + } + + // Gibt es noch eine letzte Zeile, dann diese linksbuendig ausgeben, + // da die Zeile gekuerzt wurde + if ( aLastLine.Len() ) + DrawText( aPos, aLastLine ); + + // Clipping zuruecksetzen + if ( nStyle & TEXT_DRAW_CLIP ) + Pop(); + } + } + else + { + long nTextWidth = GetTextWidth( aStr ); + + // Evt. Text kuerzen + if ( nTextWidth > nWidth ) + { + if ( nStyle & TEXT_DRAW_ELLIPSIS ) + { + aStr = GetEllipsisString( aStr, nWidth, nStyle ); + nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT); + nStyle |= TEXT_DRAW_LEFT; + nTextWidth = GetTextWidth( aStr ); + } + } + else + { + if ( nTextHeight <= nHeight ) + nStyle &= ~TEXT_DRAW_CLIP; + } + + // Vertikales Alignment + if ( nStyle & TEXT_DRAW_RIGHT ) + aPos.X() += nWidth-nTextWidth; + else if ( nStyle & TEXT_DRAW_CENTER ) + aPos.X() += (nWidth-nTextWidth)/2; + + // Font Alignment + if ( eAlign == ALIGN_BOTTOM ) + aPos.Y() += nTextHeight; + else if ( eAlign == ALIGN_BASELINE ) + aPos.Y() += GetFontMetric().GetAscent(); + + if ( nStyle & TEXT_DRAW_BOTTOM ) + aPos.Y() += nHeight-nTextHeight; + else if ( nStyle & TEXT_DRAW_VCENTER ) + aPos.Y() += (nHeight-nTextHeight)/2; + + long nMnemonicX; + long nMnemonicY; + xub_Unicode cMnemonic; + if ( nMnemonicPos != STRING_NOTFOUND ) + { + Point aTempPos = LogicToPixel( aPos ); + cMnemonic = aStr.GetChar( nMnemonicPos ); + nMnemonicX = mnOutOffX + aTempPos.X() + ImplLogicWidthToDevicePixel( GetTextWidth( aStr, 0, nMnemonicPos ) ); + nMnemonicY = mnOutOffY + aTempPos.Y() + ImplLogicWidthToDevicePixel( GetFontMetric().GetAscent() ); + } + + if ( nStyle & TEXT_DRAW_CLIP ) + { + Push( PUSH_CLIPREGION ); + IntersectClipRegion( rRect ); + DrawText( aPos, aStr ); + if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) ) + { + if ( nMnemonicPos != STRING_NOTFOUND ) + ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, cMnemonic ); + } + Pop(); + } + else + { + DrawText( aPos, aStr ); + if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) ) + { + if ( nMnemonicPos != STRING_NOTFOUND ) + ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, cMnemonic ); + } + } + } + + if ( nStyle & TEXT_DRAW_DISABLE ) + { + SetTextColor( aOldTextColor ); + if ( bRestoreFillColor ) + SetTextFillColor( aOldTextFillColor ); + } +} + +// ----------------------------------------------------------------------- + +Rectangle OutputDevice::GetTextRect( const Rectangle& rRect, + const XubString& rStr, USHORT nStyle, + TextRectInfo* pInfo ) const +{ + DBG_TRACE( "OutputDevice::GetTextRect()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + Rectangle aRect = rRect; + XubString aStr = rStr; + xub_StrLen nLines; + long nWidth = rRect.GetWidth(); + long nMaxWidth; + long nTextHeight = GetTextHeight(); + + if ( nStyle & TEXT_DRAW_MNEMONIC ) + aStr = GetNonMnemonicString( aStr ); + + if ( nStyle & TEXT_DRAW_MULTILINE ) + { + ImplMultiTextLineInfo aMultiLineInfo; + ImplTextLineInfo* pLineInfo; + xub_StrLen nFormatLines; + xub_StrLen i; + + nMaxWidth = 0; + ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle ); + nFormatLines = aMultiLineInfo.Count(); + if ( !nTextHeight ) + nTextHeight = 1; + nLines = (USHORT)(aRect.GetHeight()/nTextHeight); + if ( pInfo ) + pInfo->mnLineCount = nFormatLines; + if ( !nLines ) + nLines = 1; + if ( nFormatLines <= nLines ) + nLines = nFormatLines; + else + { + if ( !(nStyle & TEXT_DRAW_ENDELLIPSIS) ) + nLines = nFormatLines; + else + { + if ( pInfo ) + pInfo->mbEllipsis = TRUE; + nMaxWidth = nWidth; + } + } + if ( pInfo ) + { + BOOL bMaxWidth = nMaxWidth == 0; + pInfo->mnMaxWidth = 0; + for ( i = 0; i < nLines; i++ ) + { + pLineInfo = aMultiLineInfo.GetLine( i ); + if ( bMaxWidth && (pLineInfo->GetWidth() > nMaxWidth) ) + nMaxWidth = pLineInfo->GetWidth(); + if ( pLineInfo->GetWidth() > pInfo->mnMaxWidth ) + pInfo->mnMaxWidth = pLineInfo->GetWidth(); + } + } + else if ( !nMaxWidth ) + { + for ( i = 0; i < nLines; i++ ) + { + pLineInfo = aMultiLineInfo.GetLine( i ); + if ( pLineInfo->GetWidth() > nMaxWidth ) + nMaxWidth = pLineInfo->GetWidth(); + } + } + } + else + { + nLines = 1; + nMaxWidth = GetTextWidth( aStr ); + + if ( pInfo ) + { + pInfo->mnLineCount = 1; + pInfo->mnMaxWidth = nMaxWidth; + } + + if ( (nMaxWidth > nWidth) && (nStyle & TEXT_DRAW_ELLIPSIS) ) + { + if ( pInfo ) + pInfo->mbEllipsis = TRUE; + nMaxWidth = nWidth; + } + } + + if ( nStyle & TEXT_DRAW_RIGHT ) + aRect.Left() = aRect.Right()-nMaxWidth+1; + else if ( nStyle & TEXT_DRAW_CENTER ) + { + aRect.Left() += (nWidth-nMaxWidth)/2; + aRect.Right() = aRect.Left()+nMaxWidth-1; + } + else + aRect.Right() = aRect.Left()+nMaxWidth-1; + + if ( nStyle & TEXT_DRAW_BOTTOM ) + aRect.Top() = aRect.Bottom()-(nTextHeight*nLines)+1; + else if ( nStyle & TEXT_DRAW_VCENTER ) + { + aRect.Top() += (aRect.GetHeight()-(nTextHeight*nLines))/2; + aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1; + } + else + aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1; + + return aRect; +} + +// ----------------------------------------------------------------------- + +static BOOL ImplIsCharIn( xub_Unicode c, const sal_Char* pStr ) +{ + while ( *pStr ) + { + if ( *pStr == c ) + return TRUE; + pStr++; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +XubString OutputDevice::GetEllipsisString( const XubString& rStr, long nMaxWidth, + USHORT nStyle ) const +{ + DBG_TRACE( "OutputDevice::GetEllipsisString()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + XubString aStr = rStr; + xub_StrLen nIndex = GetTextBreak( aStr, nMaxWidth ); + + if ( nIndex != STRING_LEN ) + { + if ( nStyle & TEXT_DRAW_ENDELLIPSIS ) + { + aStr.Erase( nIndex ); + if ( nIndex > 1 ) + { + aStr.AppendAscii( "..." ); + while ( aStr.Len() && (GetTextWidth( aStr ) > nMaxWidth) ) + { + if ( (nIndex > 1) || (nIndex == aStr.Len()) ) + nIndex--; + aStr.Erase( nIndex, 1 ); + } + } + + if ( !aStr.Len() && (nStyle & TEXT_DRAW_CLIP) ) + aStr += rStr.GetChar( 0 ); + } + else if ( nStyle & (TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS) ) + { + static sal_Char const aPathSepChars[] = "\\/:"; + static sal_Char const aNewsSepChars[] = "."; + const sal_Char* pSepChars; + + if ( nStyle & TEXT_DRAW_PATHELLIPSIS ) + pSepChars = aPathSepChars; + else + pSepChars = aNewsSepChars; + + // Letztes Teilstueck ermitteln + xub_StrLen nLastContent = rStr.Len(); + while ( nLastContent ) + { + nLastContent--; + if ( ImplIsCharIn( rStr.GetChar( nLastContent ), pSepChars ) ) + break; + } + while ( nLastContent && + ImplIsCharIn( rStr.GetChar( nLastContent-1 ), pSepChars ) ) + nLastContent--; + + XubString aLastStr( rStr, nLastContent, rStr.Len() ); + XubString aTempLastStr( RTL_CONSTASCII_USTRINGPARAM( "..." ) ); + aTempLastStr += aLastStr; + if ( GetTextWidth( aTempLastStr ) > nMaxWidth ) + aStr = GetEllipsisString( rStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS ); + else + { + USHORT nFirstContent = 0; + while ( nFirstContent < nLastContent ) + { + nFirstContent++; + if ( ImplIsCharIn( rStr.GetChar( nFirstContent ), pSepChars ) ) + break; + } + while ( (nFirstContent < nLastContent) && + ImplIsCharIn( rStr.GetChar( nFirstContent ), pSepChars ) ) + nFirstContent++; + + if ( nFirstContent >= nLastContent ) + aStr = GetEllipsisString( rStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS ); + else + { + if ( nFirstContent > 4 ) + nFirstContent = 4; + XubString aFirstStr( rStr, 0, nFirstContent ); + aFirstStr.AppendAscii( "..." ); + XubString aTempStr = aFirstStr; + aTempStr += aLastStr; + if ( GetTextWidth( aTempStr ) > nMaxWidth ) + aStr = GetEllipsisString( rStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS ); + else + { + do + { + aStr = aTempStr; + while ( nFirstContent < nLastContent ) + { + nLastContent--; + if ( ImplIsCharIn( rStr.GetChar( nLastContent ), pSepChars ) ) + break; + } + while ( (nFirstContent < nLastContent) && + ImplIsCharIn( rStr.GetChar( nLastContent-1 ), pSepChars ) ) + nLastContent--; + + if ( nFirstContent < nLastContent ) + { + XubString aTempLastStr( rStr, nLastContent, rStr.Len() ); + aTempStr = aFirstStr; + aTempStr += aTempLastStr; + if ( GetTextWidth( aTempStr ) > nMaxWidth ) + break; + } + } + while ( nFirstContent < nLastContent ); + } + } + } + } + } + + return aStr; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawCtrlText( const Point& rPos, const XubString& rStr, + xub_StrLen nIndex, xub_StrLen nLen, + USHORT nStyle ) +{ + DBG_TRACE( "OutputDevice::DrawCtrlText()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( !IsDeviceOutputNecessary() || (nIndex >= rStr.Len()) ) + return; + + // Vorsichtshalber hier auch schon Aufrufen, da ImplDrawMnemonicLine() + // dies nicht macht +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; +#else + if ( !ImplGetServerGraphics() ) + return; +#endif + + XubString aStr = rStr; + xub_StrLen nMnemonicPos = STRING_NOTFOUND; + long nMnemonicX; + long nMnemonicY; + xub_Unicode cMnemonic; + if ( nStyle & TEXT_DRAW_MNEMONIC ) + { + aStr = GetNonMnemonicString( aStr, nMnemonicPos ); + if ( nMnemonicPos != STRING_NOTFOUND ) + { + if ( nMnemonicPos < nIndex ) + nIndex--; + else if ( (nLen < STRING_LEN) && + (nMnemonicPos >= nIndex) && (nMnemonicPos < (ULONG)(nIndex+nLen)) ) + nLen--; + Point aTempPos = LogicToPixel( rPos ); + cMnemonic = aStr.GetChar( nMnemonicPos ); + nMnemonicX = mnOutOffX + aTempPos.X() + ImplLogicWidthToDevicePixel( GetTextWidth( aStr, 0, nMnemonicPos ) ); + nMnemonicY = mnOutOffY + aTempPos.Y() + ImplLogicWidthToDevicePixel( GetFontMetric().GetAscent() ); + } + } + + if ( nStyle & TEXT_DRAW_DISABLE ) + { + Color aOldTextColor; + Color aOldTextFillColor; + BOOL bRestoreFillColor; + aOldTextColor = GetTextColor(); + if ( IsTextFillColor() ) + { + bRestoreFillColor = TRUE; + aOldTextFillColor = GetTextFillColor(); + } + else + bRestoreFillColor = FALSE; + SetTextColor( GetSettings().GetStyleSettings().GetLightColor() ); + DrawText( Point( rPos.X()+1, rPos.Y()+1 ), aStr, nIndex, nLen ); + if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) ) + { + if ( nMnemonicPos != STRING_NOTFOUND ) + ImplDrawMnemonicLine( nMnemonicX+1, nMnemonicY+1, cMnemonic ); + } + SetTextColor( GetSettings().GetStyleSettings().GetShadowColor() ); + DrawText( rPos, aStr, nIndex, nLen ); + if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) ) + { + if ( nMnemonicPos != STRING_NOTFOUND ) + ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, cMnemonic ); + } + SetTextColor( aOldTextColor ); + if ( bRestoreFillColor ) + SetTextFillColor( aOldTextFillColor ); + } + else + { + DrawText( rPos, aStr, nIndex, nLen ); + if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) ) + { + if ( nMnemonicPos != STRING_NOTFOUND ) + ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, cMnemonic ); + } + } +} + +// ----------------------------------------------------------------------- + +long OutputDevice::GetCtrlTextWidth( const XubString& rStr, + xub_StrLen nIndex, xub_StrLen nLen, + USHORT nStyle ) const +{ + DBG_TRACE( "OutputDevice::GetCtrlTextSize()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( nStyle & TEXT_DRAW_MNEMONIC ) + { + xub_StrLen nMnemonicPos; + XubString aStr = GetNonMnemonicString( rStr, nMnemonicPos ); + if ( nMnemonicPos != STRING_NOTFOUND ) + { + if ( nMnemonicPos < nIndex ) + nIndex--; + else if ( (nLen < STRING_LEN) && + (nMnemonicPos >= nIndex) && (nMnemonicPos < (ULONG)(nIndex+nLen)) ) + nLen--; + } + return GetTextWidth( aStr, nIndex, nLen ); + } + else + return GetTextWidth( rStr, nIndex, nLen ); +} + +// ----------------------------------------------------------------------- + +XubString OutputDevice::GetNonMnemonicString( const XubString& rStr, xub_StrLen& rMnemonicPos ) +{ + XubString aStr = rStr; + xub_StrLen nLen = aStr.Len(); + xub_StrLen i = 0; + + rMnemonicPos = STRING_NOTFOUND; + while ( i < nLen ) + { + if ( aStr.GetChar( i ) == '~' ) + { + if ( aStr.GetChar( i+1 ) != '~' ) + { + if ( rMnemonicPos == STRING_NOTFOUND ) + rMnemonicPos = i; + aStr.Erase( i, 1 ); + nLen--; + } + else + { + aStr.Erase( i, 1 ); + nLen--; + i++; + } + } + else + i++; + } + + return aStr; +} + +// ----------------------------------------------------------------------- + +USHORT OutputDevice::GetDevFontCount() const +{ + DBG_TRACE( "OutputDevice::GetDevFontCount()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + // Wenn wir schon eine Liste der Fonts haben, dann nicht iterieren + if ( mpGetDevFontList ) + return (USHORT)mpGetDevFontList->Count(); + + ((OutputDevice*)this)->mpGetDevFontList = new ImplGetDevFontList; + + // Fill Fontlist + ImplDevFontListData* pFontListData = mpFontList->First(); + while ( pFontListData ) + { + ImplFontData* pLastData = NULL; + ImplFontData* pData = pFontListData->mpFirst; + while ( pData ) + { + // Compare with the last font, because we wan't in the list + // only fonts, that have different attributes, but not + // different sizes + if ( !pLastData || + (ImplCompareFontDataWithoutSize( pLastData, pData ) != 0) ) + mpGetDevFontList->Add( pData ); + + pLastData = pData; + pData = pData->mpNext; + } + + pFontListData = mpFontList->Next(); + } + + return (USHORT)mpGetDevFontList->Count(); +} + +// ----------------------------------------------------------------------- + +FontInfo OutputDevice::GetDevFont( USHORT nDevFont ) const +{ + DBG_TRACE( "OutputDevice::GetDevFont()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + FontInfo aFontInfo; + USHORT nCount = GetDevFontCount(); + + // Wertebereich ueberpruefen + if ( nDevFont < nCount ) + { + ImplFontData* pData = mpGetDevFontList->Get( nDevFont ); + aFontInfo.SetName( pData->maName ); + aFontInfo.SetStyleName( pData->maStyleName ); +// !!! UNICODE !!! aFontInfo.SetCharSet( ImplGetFakeEncoding( pData->meCharSet ) ); + aFontInfo.SetCharSet( pData->meCharSet ); + aFontInfo.SetFamily( pData->meFamily ); + aFontInfo.SetPitch( pData->mePitch ); + aFontInfo.SetWeight( pData->meWeight ); + aFontInfo.SetItalic( pData->meItalic ); + aFontInfo.mpImplMetric->meType = pData->meType; + aFontInfo.mpImplMetric->mbDevice = pData->mbDevice; + } + + return aFontInfo; +} + +// ----------------------------------------------------------------------- + +USHORT OutputDevice::GetDevFontSizeCount( const Font& rFont ) const +{ + DBG_TRACE( "OutputDevice::GetDevFontSizeCount()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + XubString aFontName = rFont.GetName(); + + // Wenn die Liste schon existiert und der FontName sich nicht + // unterscheidet, dann brauchen wir Sie nicht neu erzeugen + if ( mpGetDevSizeList ) + { + if ( mpGetDevSizeList->GetFontName() == aFontName ) + return (USHORT)mpGetDevSizeList->Count(); + else + { + mpGetDevSizeList->Clear(); + mpGetDevSizeList->SetFontName( aFontName ); + } + } + else + ((OutputDevice*)this)->mpGetDevSizeList = new ImplGetDevSizeList( aFontName ); + + // Fonts aus unserer Fontliste in die GetDevFontSizeListe eintragen + ImplDevFontListData* pFontListData = mpFontList->FindFont( aFontName ); + if ( pFontListData ) + { + ImplFontData* pData = pFontListData->mpFirst; + do + { + mpGetDevSizeList->Add( pData->mnHeight ); + pData = pData->mpNext; + } + while ( pData ); + } + + return (USHORT)mpGetDevSizeList->Count(); +} + +// ----------------------------------------------------------------------- + +Size OutputDevice::GetDevFontSize( const Font& rFont, USHORT nSize ) const +{ + DBG_TRACE( "OutputDevice::GetDevFontSize()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + USHORT nCount = GetDevFontSizeCount( rFont ); + + // Wertebereich ueberpruefen + if ( nSize >= nCount ) + return Size(); + + // Wenn MapMode gesetzt ist, wird auf ,5-Points gerundet + Size aSize( 0, mpGetDevSizeList->Get( nSize ) ); + if ( mbMap ) + { + aSize.Height() *= 10; + MapMode aMap( MAP_10TH_INCH, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) ); + aSize = PixelToLogic( aSize, aMap ); + aSize.Height() += 5; + aSize.Height() /= 10; + long nRound = aSize.Height() % 5; + if ( nRound >= 3 ) + aSize.Height() += (5-nRound); + else + aSize.Height() -= nRound; + aSize.Height() *= 10; + aSize = LogicToPixel( aSize, aMap ); + aSize = PixelToLogic( aSize ); + aSize.Height() += 5; + aSize.Height() /= 10; + } + return aSize; +} + +// ----------------------------------------------------------------------- + +BOOL OutputDevice::IsFontAvailable( const XubString& rFontName ) const +{ + DBG_TRACE( "OutputDevice::IsFontAvailable()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + return (mpFontList->FindFont( rFontName ) != 0); +} + +// ----------------------------------------------------------------------- + +FontMetric OutputDevice::GetFontMetric() const +{ + DBG_TRACE( "OutputDevice::GetFontMetric()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + FontMetric aMetric; + + if ( mbNewFont ) + { + if ( !((OutputDevice*)this)->ImplNewFont() ) + return aMetric; + } + + ImplFontEntry* pEntry = mpFontEntry; + ImplFontMetricData* pMetric = &(pEntry->maMetric); + + // Mappen und StarView Struktur fuellen + aMetric.Font::operator=( maFont ); + + // Fontdaten ermitteln und setzen + aMetric.SetName( pMetric->maName ); + aMetric.SetStyleName( pMetric->maStyleName ); + aMetric.SetSize( PixelToLogic( Size( pMetric->mnWidth, pMetric->mnAscent+pMetric->mnDescent-pMetric->mnLeading ) ) ); + aMetric.SetCharSet( pMetric->meCharSet ); + aMetric.SetFamily( pMetric->meFamily ); + aMetric.SetPitch( pMetric->mePitch ); + aMetric.SetWeight( pMetric->meWeight ); + aMetric.SetItalic( pMetric->meItalic ); + if ( pEntry->mnOwnOrientation ) + aMetric.SetOrientation( pEntry->mnOwnOrientation ); + else + aMetric.SetOrientation( pMetric->mnOrientation ); + if ( !mbKerning ) + aMetric.SetKerning( FALSE ); + + // restliche Metricen setzen + aMetric.mpImplMetric->meType = pMetric->meType; + aMetric.mpImplMetric->mbDevice = pMetric->mbDevice; + aMetric.mpImplMetric->mnAscent = ImplDevicePixelToLogicHeight( pMetric->mnAscent ); + aMetric.mpImplMetric->mnDescent = ImplDevicePixelToLogicHeight( pMetric->mnDescent ); + aMetric.mpImplMetric->mnLeading = ImplDevicePixelToLogicHeight( pMetric->mnLeading ); + aMetric.mpImplMetric->mnLineHeight = ImplDevicePixelToLogicHeight( pMetric->mnAscent+pMetric->mnDescent ); + aMetric.mpImplMetric->mnSlant = ImplDevicePixelToLogicHeight( pMetric->mnSlant ); + aMetric.mpImplMetric->mnFirstChar = pMetric->mnFirstChar; + aMetric.mpImplMetric->mnLastChar = pMetric->mnLastChar; + + return aMetric; +} + +// ----------------------------------------------------------------------- + +FontMetric OutputDevice::GetFontMetric( const Font& rFont ) const +{ + // Uebergebenen Font selektieren, Metric abfragen und alten wieder + // selektieren + Font aOldFont = GetFont(); + ((OutputDevice*)this)->SetFont( rFont ); + FontMetric aMetric( GetFontMetric() ); + ((OutputDevice*)this)->SetFont( aOldFont ); + return aMetric; +} + +// ----------------------------------------------------------------------- + +ULONG OutputDevice::GetKerningPairCount() const +{ + DBG_TRACE( "OutputDevice::GetKerningPairCount()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + ((OutputDevice*)this)->ImplInitKerningPairs(); + return mpFontEntry->mnKernPairs; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::GetKerningPairs( ULONG nPairs, KerningPair* pKernPairs ) const +{ + DBG_TRACE( "OutputDevice::GetKerningPairs()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + ((OutputDevice*)this)->ImplInitKerningPairs(); + if ( nPairs > mpFontEntry->mnKernPairs ) + nPairs = mpFontEntry->mnKernPairs; + if ( nPairs ) + memcpy( pKernPairs, mpFontEntry->mpKernPairs, nPairs*sizeof( KerningPair ) ); +} + +// ----------------------------------------------------------------------- + +BOOL OutputDevice::GetGlyphBoundRect( xub_Unicode cChar, Rectangle& rRect, BOOL bOptimize ) +{ + DBG_TRACE( "OutputDevice::GetGlyphBoundRect()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + BOOL bRet = FALSE; + +#ifndef REMOTE_APPSERVER + if ( mpGraphics || ImplGetGraphics() ) + { + Font* pOldFont; + long nLeft, nTop, nWidth, nHeight; + long nFontWidth, nFontHeight; + long nOrgWidth, nOrgHeight; + + if ( bOptimize ) + { + pOldFont = new Font( GetFont() ); + + Font aFont( *pOldFont ); + Size aFontSize( LogicToPixel( aFont.GetSize() ) ); + + if ( aFontSize.Width() && aFontSize.Height() ) + { + const double fFactor = (double) aFontSize.Width() / aFontSize.Height(); + + if ( fFactor < 1.0 ) + { + aFontSize.Width() = FRound( fFactor * 500. ); + aFontSize.Height() = 500; + } + else + { + aFontSize.Width() = 500; + aFontSize.Height() = FRound( 500. / fFactor ); + } + + aFont.SetSize( PixelToLogic( aFontSize ) ); + ((OutputDevice*)this)->SetFont( aFont ); + nFontWidth = aFont.GetSize().Width(); + nFontHeight = aFont.GetSize().Height(); + nOrgWidth = pOldFont->GetSize().Width(); + nOrgHeight = pOldFont->GetSize().Height(); + } + else + { + aFont.SetSize( PixelToLogic( Size( 0, 500 ) ) ); + ((OutputDevice*)this)->SetFont( aFont ); + nFontWidth = nFontHeight = aFont.GetSize().Height(); + nOrgWidth = nOrgHeight = pOldFont->GetSize().Height(); + } + } + + if ( mbNewFont ) + ImplNewFont(); + if ( mbInitFont ) + ImplInitFont(); + + if ( mpGraphics->GetGlyphBoundRect( cChar, &nLeft, &nTop, &nWidth, &nHeight ) ) + { + if ( bOptimize ) + { + nLeft = ImplDevicePixelToLogicWidth( nLeft ) * nOrgWidth / nFontWidth; + nTop = ImplDevicePixelToLogicHeight( nTop ) * nOrgHeight / nFontHeight; + nWidth = ImplDevicePixelToLogicWidth( nWidth ) * nOrgWidth / nFontWidth; + nHeight = ImplDevicePixelToLogicHeight( nHeight ) * nOrgHeight / nFontHeight; + } + else + { + nLeft = ImplDevicePixelToLogicWidth( nLeft ); + nTop = ImplDevicePixelToLogicHeight( nTop ); + nWidth = ImplDevicePixelToLogicWidth( nWidth ); + nHeight = ImplDevicePixelToLogicHeight( nHeight ); + } + + rRect = Rectangle( Point( nLeft, nTop ), Size( nWidth, nHeight ) ); + bRet = TRUE; + } + + if ( bOptimize ) + { + ((OutputDevice*)this)->SetFont( *pOldFont ); + delete pOldFont; + } + + if ( !bRet && (OUTDEV_PRINTER != meOutDevType) ) + { + if ( bOptimize ) + { + if ( mbNewFont ) + ImplNewFont(); + if ( mbInitFont ) + ImplInitFont(); + } + + VirtualDevice* pVDev = new VirtualDevice( 1 ); + long nWidth = ImplGetTextWidth( &cChar, 1, NULL ); + long nHeight = mpFontEntry->mnLineHeight; + Point aOffset( nWidth >> 1, 8 ); + Size aSize( nWidth + ( aOffset.X() << 1 ), nHeight + ( aOffset.Y() << 1 ) ); + + if ( pVDev->SetOutputSizePixel( aSize ) ) + { + Font aFont( GetFont() ); + Bitmap aBmp; + + aFont.SetShadow( FALSE ); + aFont.SetOutline( FALSE ); + aFont.SetOrientation( 0 ); + aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) ); + + pVDev->SetFont( aFont ); + pVDev->SetTextAlign( ALIGN_TOP ); + pVDev->SetTextColor( Color( COL_BLACK ) ); + pVDev->SetTextFillColor(); + pVDev->ImplNewFont(); + pVDev->ImplInitFont(); + pVDev->ImplInitTextColor(); + pVDev->ImplDrawText( aOffset.X(), aOffset.Y(), &cChar, 1, NULL ); + aBmp = pVDev->GetBitmap( Point(), aSize ); + delete pVDev; + + BitmapReadAccess* pAcc = aBmp.AcquireReadAccess(); + + if ( pAcc ) + { + const long nW = pAcc->Width(); + const long nW1 = nW - 1L; + const long nH = pAcc->Height(); + long nRight, nBottom; + const BitmapColor aBlack( pAcc->GetBestMatchingColor( Color( COL_BLACK ) ) ); + BOOL bLineDone; + + nLeft = nW; + nTop = nH; + nRight = nBottom = -1L; + + for( long nY = 0L; nY < nH; nY++ ) + { + bLineDone = FALSE; + + for( long nX = 0L; ( nX < nW ) && !bLineDone; nX++ ) + { + if( pAcc->GetPixel( nY, nX ) == aBlack ) + { + // find y minimum + if( nY < nTop ) + nTop = nY; + + // find y maximum + if( nY > nBottom ) + nBottom = nY; + + // find x minimum + if( nX < nLeft ) + nLeft = nX; + + // find x maximum (last pixel in line) + for( long nX2 = nW1; nX2 >= nX; nX2-- ) + { + if( pAcc->GetPixel( nY, nX2 ) == aBlack ) + { + if( nX2 > nRight ) + nRight = nX2; + + bLineDone = TRUE; + break; + } + } + } + } + } + + if( nLeft < nW && nTop < nH && nRight > -1L && nBottom > -1L ) + { + nLeft -= aOffset.X(), nTop -= aOffset.Y(); + nRight -= aOffset.X(), nBottom -= aOffset.Y(); + + nWidth = ImplDevicePixelToLogicWidth( nRight - nLeft + 1L ); + nHeight = ImplDevicePixelToLogicHeight( nBottom - nTop + 1L ); + nLeft = ImplDevicePixelToLogicWidth( nLeft ); + nTop = ImplDevicePixelToLogicHeight( nTop ); + rRect = Rectangle( Point( nLeft, nTop ), Size( nWidth, nHeight ) ); + bRet = TRUE; + } + + aBmp.ReleaseAccess( pAcc ); + } + } + else + delete pVDev; + } + } +#else + if ( mbNewFont ) + ImplNewFont(); + if ( mbInitFont ) + ImplInitFont(); + + bRet = mpGraphics->GetGlyphBoundRect( cChar, rRect, bOptimize ); + + if ( bRet ) + { + rRect = Rectangle( Point( ImplDevicePixelToLogicWidth( rRect.Left() ), + ImplDevicePixelToLogicHeight( rRect.Top() ) ), + Size( ImplDevicePixelToLogicWidth( rRect.GetWidth() ), + ImplDevicePixelToLogicHeight( rRect.GetHeight() ) ) ); + } + +#endif + + if ( !bRet ) + rRect.SetEmpty(); + + return bRet; +} + +// ----------------------------------------------------------------------- + +BOOL OutputDevice::GetGlyphOutline( xub_Unicode cChar, PolyPolygon& rPolyPoly, BOOL bOptimize ) +{ + DBG_TRACE( "OutputDevice::GetGlyphOutline()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + BOOL bRet = FALSE; + +#ifndef REMOTE_APPSERVER + if ( mpGraphics || ImplGetGraphics() ) + { + Font* pOldFont; + USHORT* pPolySizes = NULL; + SalPoint* pPoints = NULL; + BYTE* pFlags = NULL; + long nFontWidth, nFontHeight; + long nOrgWidth, nOrgHeight; + ULONG nPolyCount; + + if ( bOptimize ) + { + pOldFont = new Font( GetFont() ); + + Font aFont( *pOldFont ); + Size aFontSize( LogicToPixel( aFont.GetSize() ) ); + + if ( aFontSize.Width() && aFontSize.Height() ) + { + const double fFactor = (double) aFontSize.Width() / aFontSize.Height(); + + if ( fFactor < 1.0 ) + { + aFontSize.Width() = FRound( fFactor * 500. ); + aFontSize.Height() = 500; + } + else + { + aFontSize.Width() = 500; + aFontSize.Height() = FRound( 500. / fFactor ); + } + + aFont.SetSize( PixelToLogic( aFontSize ) ); + ((OutputDevice*)this)->SetFont( aFont ); + nFontWidth = aFont.GetSize().Width(); + nFontHeight = aFont.GetSize().Height(); + nOrgWidth = pOldFont->GetSize().Width(); + nOrgHeight = pOldFont->GetSize().Height(); + } + else + { + aFont.SetSize( PixelToLogic( Size( 0, 500 ) ) ); + ((OutputDevice*)this)->SetFont( aFont ); + nFontWidth = nFontHeight = aFont.GetSize().Height(); + nOrgWidth = nOrgHeight = pOldFont->GetSize().Height(); + } + } + + if ( mbNewFont ) + ImplNewFont(); + if ( mbInitFont ) + ImplInitFont(); + + nPolyCount = mpGraphics->GetGlyphOutline( cChar, &pPolySizes, &pPoints, &pFlags ); + if ( nPolyCount && pPolySizes && pPoints && pFlags ) + { + ULONG nTotalPos = 0UL; + + rPolyPoly.Clear(); + + for( ULONG i = 0UL; i < nPolyCount; i++ ) + { + const USHORT nSize = pPolySizes[ i ]; + + if( nSize ) + { + Polygon aPoly( nSize ); + Point* pPt = aPoly.ImplGetPointAry(); + BYTE* pFl = aPoly.ImplGetFlagAry(); + + memcpy( pFl, pFlags + nTotalPos, nSize ); + + for( USHORT n = 0; n < nSize; n++ ) + { + const SalPoint& rSalPt = pPoints[ nTotalPos++ ]; + Point& rPt = pPt[ n ]; + + if( bOptimize ) + { + rPt.X() = ImplDevicePixelToLogicWidth( rSalPt.mnX ) * + nOrgWidth / nFontWidth; + rPt.Y() = ImplDevicePixelToLogicHeight( rSalPt.mnY ) * + nOrgHeight / nFontHeight; + } + else + { + rPt.X() = ImplDevicePixelToLogicWidth( rSalPt.mnX ); + rPt.Y() = ImplDevicePixelToLogicHeight( rSalPt.mnY ); + } + } + + rPolyPoly.Insert( aPoly ); + } + } + + bRet = TRUE; + } + + delete[] pPolySizes; + delete[] pPoints; + delete[] pFlags; + + if ( bOptimize ) + { + ((OutputDevice*)this)->SetFont( *pOldFont ); + delete pOldFont; + } + + if ( !bRet && (OUTDEV_PRINTER != meOutDevType) ) + { + if ( bOptimize ) + { + if( mbNewFont ) + ImplNewFont(); + if( mbInitFont ) + ImplInitFont(); + } + + Font aFont( GetFont() ); + VirtualDevice* pVDev = new VirtualDevice( 1 ); + const Size aFontSize( pVDev->LogicToPixel( Size( 0, GLYPH_FONT_HEIGHT ), MAP_POINT ) ); + const long nOrgWidth = ImplGetTextWidth( &cChar, 1, NULL ); + const long nOrgHeight = mpFontEntry->mnLineHeight; + + aFont.SetShadow( FALSE ); + aFont.SetOutline( FALSE ); + aFont.SetOrientation( 0 ); + aFont.SetSize( aFontSize ); + pVDev->SetFont( aFont ); + pVDev->SetTextAlign( ALIGN_TOP ); + pVDev->SetTextColor( Color( COL_BLACK ) ); + pVDev->SetTextFillColor(); + pVDev->ImplNewFont(); + pVDev->ImplInitFont(); + pVDev->ImplInitTextColor(); + + const long nWidth = pVDev->ImplGetTextWidth( &cChar, 1, NULL ); + const long nHeight = pVDev->mpFontEntry->mnLineHeight; + const Point aOffset( nWidth >> 1, 8 ); + const Size aSize( nWidth + ( aOffset.X() << 1 ), nHeight + ( aOffset.Y() << 1 ) ); + const double fScaleX = ( nOrgWidth && nWidth ) ? ( (double) nOrgWidth / nWidth ) : 0.0; + const double fScaleY = ( nOrgHeight && nHeight ) ? ( (double) nOrgHeight / nHeight ) : 0.0; + + if ( pVDev->SetOutputSizePixel( aSize ) ) + { + Bitmap aBmp; + + pVDev->ImplDrawText( aOffset.X(), aOffset.Y(), &cChar, 1, NULL ); + aBmp = pVDev->GetBitmap( Point(), aSize ); + delete pVDev; + + if( aBmp.Vectorize( rPolyPoly, BMP_VECTORIZE_OUTER | BMP_VECTORIZE_REDUCE_EDGES ) ) + { + const long nOffX = aOffset.X(), nOffY = aOffset.Y(); + + for( USHORT i = 0UL, nCount = rPolyPoly.Count(); i < nCount; i++ ) + { + Polygon& rPoly = rPolyPoly[ i ]; + + for( USHORT n = 0, nSize = rPoly.GetSize(); n < nSize; n++ ) + { + Point& rPt = rPoly[ n ]; + rPt.X() = FRound( ImplDevicePixelToLogicWidth( rPt.X() - nOffX ) * fScaleX ); + rPt.Y() = FRound( ImplDevicePixelToLogicHeight( rPt.Y() - nOffY ) * fScaleY ); + } + } + + bRet = TRUE; + } + } + else + delete pVDev; + } + } +#else + if ( mbNewFont ) + ImplNewFont(); + if ( mbInitFont ) + ImplInitFont(); + + bRet = mpGraphics->GetGlyphOutline( cChar, rPolyPoly, bOptimize ); + + if( bRet ) + { + for( USHORT i = 0UL, nCount = rPolyPoly.Count(); i < nCount; i++ ) + { + Polygon& rPoly = rPolyPoly[ i ]; + + for( USHORT n = 0, nSize = rPoly.GetSize(); n < nSize; n++ ) + { + Point& rPt = rPoly[ n ]; + rPt.X() = ImplDevicePixelToLogicWidth( rPt.X() ); + rPt.Y() = ImplDevicePixelToLogicHeight( rPt.Y() ); + } + } + } + +#endif + + if( !bRet ) + rPolyPoly = PolyPolygon(); + + return bRet; +} diff --git a/vcl/source/gdi/outdev4.cxx b/vcl/source/gdi/outdev4.cxx new file mode 100644 index 000000000000..fc8e313b825d --- /dev/null +++ b/vcl/source/gdi/outdev4.cxx @@ -0,0 +1,1634 @@ +/************************************************************************* + * + * $RCSfile: outdev4.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_OUTDEV_CXX + +#include <math.h> + +#ifndef REMOTE_APPSERVER +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#endif +#ifndef REMOTE_APPSERVER +#ifndef _SV_SALGDI_HXX +#include <salgdi.hxx> +#endif +#else +#ifndef _SV_RMOUTDEV_HXX +#include <rmoutdev.hxx> +#endif +#endif +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _SV_SVDATA_HXX +#include <svdata.hxx> +#endif +#ifndef _SV_GRADIENT_HXX +#include <gradient.hxx> +#endif +#ifndef _SV_METAACT_HXX +#include <metaact.hxx> +#endif +#ifndef _SV_GDIMTF_HXX +#include <gdimtf.hxx> +#endif +#ifndef _SV_OUTDATA_HXX +#include <outdata.hxx> +#endif +#ifndef _SV_POLY_H +#include <poly.h> +#endif +#ifndef _SV_POLY_HXX +#include <poly.hxx> +#endif +#ifndef _SV_SALBTYPE_HXX +#include <salbtype.hxx> +#endif +#ifndef _SV_LINE_HXX +#include <line.hxx> +#endif +#ifndef _SV_HATCH_HXX +#include <hatch.hxx> +#endif +#ifndef _SV_WINDOW_HXX +#include <window.hxx> +#endif +#ifndef _SV_VIRDEV_HXX +#include <virdev.hxx> +#endif +#ifndef _SV_OUTDEV_HXX +#include <outdev.hxx> +#endif + +// ----------- +// - Defines - +// ----------- + +#define HATCH_MAXPOINTS 1024 +#define GRADIENT_DEFAULT_STEPCOUNT 0 + +// ---------------- +// - Cmp-Function - +// ---------------- + +extern "C" int __LOADONCALLAPI ImplHatchCmpFnc( const void* p1, const void* p2 ) +{ + const long nX1 = ( (Point*) p1 )->X(); + const long nX2 = ( (Point*) p2 )->X(); + const long nY1 = ( (Point*) p1 )->Y(); + const long nY2 = ( (Point*) p2 )->Y(); + + return ( nX1 > nX2 ? 1 : nX1 == nX2 ? nY1 > nY2 ? 1: nY1 == nY2 ? 0 : -1 : -1 ); +} + +// ======================================================================= + +DBG_NAMEEX( OutputDevice ); +DBG_NAMEEX( Gradient ); + +// ======================================================================= + +#ifndef REMOTE_APPSERVER + +void OutputDevice::ImplDrawPolygon( const Polygon& rPoly ) +{ + USHORT nPoints = rPoly.GetSize(); + + if ( nPoints < 2 ) + return; + + const SalPoint* pPtAry = (const SalPoint*)rPoly.ImplGetConstPointAry(); + mpGraphics->DrawPolygon( nPoints, pPtAry ); +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplDrawPolyPolygon( const PolyPolygon& rPolyPoly ) +{ + USHORT nPoly = rPolyPoly.Count(); + + if ( !nPoly ) + return; + + if ( nPoly == 1 ) + { + const Polygon rPoly = rPolyPoly.GetObject( 0 ); + USHORT nSize = rPoly.GetSize(); + if ( nSize >= 2 ) + { + const SalPoint* pPtAry = (const SalPoint*)rPoly.ImplGetConstPointAry(); + mpGraphics->DrawPolygon( nSize, pPtAry ); + } + } + else + { + ULONG* pPointAry = new ULONG[nPoly]; + PCONSTSALPOINT* pPointAryAry = new PCONSTSALPOINT[nPoly]; + USHORT i = 0; + do + { + const Polygon& rPoly = rPolyPoly.GetObject( i ); + USHORT nSize = rPoly.GetSize(); + if ( nSize ) + { + pPointAry[i] = nSize; + pPointAryAry[i] = (PCONSTSALPOINT)rPoly.ImplGetConstPointAry(); + i++; + } + else + nPoly--; + } + while ( i < nPoly ); + + if ( nPoly == 1 ) + mpGraphics->DrawPolygon( *pPointAry, *pPointAryAry ); + else + mpGraphics->DrawPolyPolygon( nPoly, pPointAry, pPointAryAry ); + + delete pPointAry; + delete pPointAryAry; + } +} + +#endif + +// ----------------------------------------------------------------------- + +inline UINT8 ImplGetGradientColorValue( long nValue ) +{ + if ( nValue < 0 ) + return 0; + else if ( nValue > 0xFF ) + return 0xFF; + else + return (UINT8)nValue; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplDrawLinearGradient( const Rectangle& rRect, + const Gradient& rGradient, + BOOL bMtf ) +{ + // rotiertes BoundRect ausrechnen + Rectangle aRect = rRect; + aRect.Left()--; + aRect.Top()--; + aRect.Right()++; + aRect.Bottom()++; + USHORT nAngle = rGradient.GetAngle(); + double fAngle = (nAngle % 3600) * F_PI1800; + double fWidth = aRect.GetWidth(); + double fHeight = aRect.GetHeight(); + double fDX = fWidth * fabs( cos( fAngle ) ) + + fHeight * fabs( sin( fAngle ) ); + double fDY = fHeight * fabs( cos( fAngle ) ) + + fWidth * fabs( sin( fAngle ) ); + fDX = (fDX - fWidth) * 0.5 + 0.5; + fDY = (fDY - fHeight) * 0.5 + 0.5; + aRect.Left() -= (long)fDX; + aRect.Right() += (long)fDX; + aRect.Top() -= (long)fDY; + aRect.Bottom() += (long)fDY; + + // Rand berechnen und Rechteck neu setzen + Point aCenter = rRect.Center(); + Rectangle aFullRect = aRect; + long nBorder = (long)rGradient.GetBorder() * aRect.GetHeight() / 100; + BOOL bLinear; + + // Rand berechnen und Rechteck neu setzen fuer linearen Farbverlauf + if ( rGradient.GetStyle() == GRADIENT_LINEAR ) + { + bLinear = TRUE; + aRect.Top() += nBorder; + } + // Rand berechnen und Rechteck neu setzen fuer axiale Farbverlauf + else + { + bLinear = FALSE; + nBorder >>= 1; + + aRect.Top() += nBorder; + aRect.Bottom() -= nBorder; + } + + // Top darf nicht groesser als Bottom sein + aRect.Top() = Min( aRect.Top(), (long)(aRect.Bottom() - 1) ); + + long nMinRect = aRect.GetHeight(); + + // Intensitaeten von Start- und Endfarbe ggf. aendern und + // Farbschrittweiten berechnen + long nFactor; + Color aStartCol = rGradient.GetStartColor(); + Color aEndCol = rGradient.GetEndColor(); + long nStartRed = aStartCol.GetRed(); + long nStartGreen = aStartCol.GetGreen(); + long nStartBlue = aStartCol.GetBlue(); + long nEndRed = aEndCol.GetRed(); + long nEndGreen = aEndCol.GetGreen(); + long nEndBlue = aEndCol.GetBlue(); + nFactor = rGradient.GetStartIntensity(); + nStartRed = (nStartRed * nFactor) / 100; + nStartGreen = (nStartGreen * nFactor) / 100; + nStartBlue = (nStartBlue * nFactor) / 100; + nFactor = rGradient.GetEndIntensity(); + nEndRed = (nEndRed * nFactor) / 100; + nEndGreen = (nEndGreen * nFactor) / 100; + nEndBlue = (nEndBlue * nFactor) / 100; + long nRedSteps = nEndRed - nStartRed; + long nGreenSteps = nEndGreen - nStartGreen; + long nBlueSteps = nEndBlue - nStartBlue; + + // Bei nicht linearen Farbverlaeufen haben wir nur die halben Steps + // pro Farbe + if ( !bLinear ) + { + nRedSteps <<= 1; + nGreenSteps <<= 1; + nBlueSteps <<= 1; + } + + // Anzahl der Schritte berechnen, falls nichts uebergeben wurde + USHORT nStepCount = rGradient.GetSteps(); + if ( !nStepCount ) + { + long nInc; + + if ( meOutDevType != OUTDEV_PRINTER && !bMtf ) + nInc = (nMinRect < 50) ? 2 : 4; + else + nInc = ((nMinRect >> 9) + 1) << 3; + + if ( !nInc ) + nInc = 1; + + nStepCount = (USHORT)(nMinRect / nInc); + } + // minimal drei Schritte und maximal die Anzahl der Farbunterschiede + long nSteps = Max( nStepCount, (USHORT)3 ); + long nCalcSteps = Abs( nRedSteps ); + long nTempSteps = Abs( nGreenSteps ); + if ( nTempSteps > nCalcSteps ) + nCalcSteps = nTempSteps; + nTempSteps = Abs( nBlueSteps ); + if ( nTempSteps > nCalcSteps ) + nCalcSteps = nTempSteps; + if ( nCalcSteps < nSteps ) + nSteps = nCalcSteps; + if ( !nSteps ) + nSteps = 1; + + // Falls axialer Farbverlauf, muss die Schrittanzahl ungerade sein + if ( !bLinear && !(nSteps & 1) ) + nSteps++; + + // Berechnung ueber Double-Addition wegen Genauigkeit + double fScanLine = aRect.Top(); + double fScanInc = (double)aRect.GetHeight() / (double)nSteps; + + // Startfarbe berechnen und setzen + UINT8 nRed; + UINT8 nGreen; + UINT8 nBlue; + long nSteps2; + long nStepsHalf; + if ( bLinear ) + { + // Um 1 erhoeht, um die Border innerhalb der Schleife + // zeichnen zu koennen + nSteps2 = nSteps + 1; + nRed = (UINT8)nStartRed; + nGreen = (UINT8)nStartGreen; + nBlue = (UINT8)nStartBlue; + } + else + { + // Um 2 erhoeht, um die Border innerhalb der Schleife + // zeichnen zu koennen + nSteps2 = nSteps + 2; + nRed = (UINT8)nEndRed; + nGreen = (UINT8)nEndGreen; + nBlue = (UINT8)nEndBlue; + nStepsHalf = nSteps >> 1; + } + + if ( bMtf ) + mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), TRUE ) ); +#ifndef REMOTE_APPSERVER + else + mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) ); +#endif + + // Startpolygon erzeugen (== Borderpolygon) + Polygon aPoly( 4 ); + Polygon aTempPoly( 2 ); + aPoly[0] = aFullRect.TopLeft(); + aPoly[1] = aFullRect.TopRight(); + aPoly[2] = aRect.TopRight(); + aPoly[3] = aRect.TopLeft(); + aPoly.Rotate( aCenter, nAngle ); + + // Schleife, um rotierten Verlauf zu fuellen + for ( long i = 0; i < nSteps2; i++ ) + { + // berechnetesPolygon ausgeben + if ( bMtf ) + mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) ); +#ifndef REMOTE_APPSERVER + else + ImplDrawPolygon( aPoly ); +#endif + + // neues Polygon berechnen + aRect.Top() = (long)(fScanLine += fScanInc); + + // unteren Rand komplett fuellen + if ( i == nSteps ) + { + aTempPoly[0] = aFullRect.BottomLeft(); + aTempPoly[1] = aFullRect.BottomRight(); + } + else + { + aTempPoly[0] = aRect.TopLeft(); + aTempPoly[1] = aRect.TopRight(); + } + aTempPoly.Rotate( aCenter, nAngle ); + + aPoly[0] = aPoly[3]; + aPoly[1] = aPoly[2]; + aPoly[2] = aTempPoly[1]; + aPoly[3] = aTempPoly[0]; + + // Farbintensitaeten aendern... + // fuer lineare FV + if ( bLinear ) + { + nRed = ImplGetGradientColorValue( nStartRed+((nRedSteps*i)/nSteps2) ); + nGreen = ImplGetGradientColorValue( nStartGreen+((nGreenSteps*i)/nSteps2) ); + nBlue = ImplGetGradientColorValue( nStartBlue+((nBlueSteps*i)/nSteps2) ); + } + // fuer radiale FV + else + { + // fuer axiale FV muss die letzte Farbe der ersten + // Farbe entsprechen + if ( i > nSteps ) + { + nRed = (UINT8)nEndRed; + nGreen = (UINT8)nEndGreen; + nBlue = (UINT8)nEndBlue; + } + else + { + if ( i <= nStepsHalf ) + { + nRed = ImplGetGradientColorValue( nEndRed-((nRedSteps*i)/nSteps2) ); + nGreen = ImplGetGradientColorValue( nEndGreen-((nGreenSteps*i)/nSteps2) ); + nBlue = ImplGetGradientColorValue( nEndBlue-((nBlueSteps*i)/nSteps2) ); + } + // genau die Mitte und hoeher + else + { + long i2 = i - nStepsHalf; + nRed = ImplGetGradientColorValue( nStartRed+((nRedSteps*i2)/nSteps2) ); + nGreen = ImplGetGradientColorValue( nStartGreen+((nGreenSteps*i2)/nSteps2) ); + nBlue = ImplGetGradientColorValue( nStartBlue+((nBlueSteps*i2)/nSteps2) ); + } + } + } + + if ( bMtf ) + mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), TRUE ) ); +#ifndef REMOTE_APPSERVER + else + mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) ); +#endif + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplDrawRadialGradient( const Rectangle& rRect, + const Gradient& rGradient, + BOOL bMtf ) +{ + // Feststellen ob Ausgabe ueber Polygon oder PolyPolygon + // Bei Rasteroperationen ungleich Overpaint immer PolyPolygone, + // da es zu falschen Ergebnissen kommt, wenn man mehrfach uebereinander + // ausgibt + // Bei Druckern auch immer PolyPolygone, da nicht alle Drucker + // das Uebereinanderdrucken von Polygonen koennen + // Virtuelle Device werden auch ausgeklammert, da einige Treiber + // ansonsten zu langsam sind + PolyPolygon* pPolyPoly; + if ( (meRasterOp != ROP_OVERPAINT) || (meOutDevType != OUTDEV_WINDOW) || bMtf ) + pPolyPoly = new PolyPolygon( 2 ); + else + pPolyPoly = NULL; + + // Radien-Berechnung fuer Kreisausgabe (Kreis schliesst Rechteck ein) + USHORT nAngle = rGradient.GetAngle(); + Rectangle aFullRect = rRect; + Rectangle aRect = rRect; + long nZWidth = aRect.GetWidth() * (long)rGradient.GetOfsX() / 100; + long nZHeight= aRect.GetHeight() * (long)rGradient.GetOfsY() / 100; + Size aSize = aRect.GetSize(); + Point aCenter( aRect.Left() + nZWidth, aRect.Top() + nZHeight ); + if ( rGradient.GetStyle() == GRADIENT_RADIAL ) + { + aSize.Width() = (long)(0.5 + sqrt((double)aSize.Width()*(double)aSize.Width() + + (double)aSize.Height()*(double)aSize.Height())); + aSize.Height() = aSize.Width(); + } + // Radien-Berechnung fuer Ellipse + else + { + aSize.Width() = (long)(0.5 + (double)aSize.Width() * 1.4142); + aSize.Height() = (long)(0.5 + (double)aSize.Height() * 1.4142); + } + + // Border berechnen + long nBorderX = (long)rGradient.GetBorder() * aSize.Width() / 100; + long nBorderY = (long)rGradient.GetBorder() * aSize.Height() / 100; + aSize.Width() -= nBorderX; + aSize.Height() -= nBorderY; + aRect.Left() = aCenter.X() - (aSize.Width() >> 1); + aRect.Top() = aCenter.Y() - (aSize.Height() >> 1); + aRect.SetSize( aSize ); + + long nMinRect = Min( aRect.GetWidth(), aRect.GetHeight() ); + + // Intensitaeten von Start- und Endfarbe ggf. aendern und + // Farbschrittweiten berechnen + long nFactor; + Color aStartCol = rGradient.GetStartColor(); + Color aEndCol = rGradient.GetEndColor(); + long nStartRed = aStartCol.GetRed(); + long nStartGreen = aStartCol.GetGreen(); + long nStartBlue = aStartCol.GetBlue(); + long nEndRed = aEndCol.GetRed(); + long nEndGreen = aEndCol.GetGreen(); + long nEndBlue = aEndCol.GetBlue(); + nFactor = rGradient.GetStartIntensity(); + nStartRed = (nStartRed * nFactor) / 100; + nStartGreen = (nStartGreen * nFactor) / 100; + nStartBlue = (nStartBlue * nFactor) / 100; + nFactor = rGradient.GetEndIntensity(); + nEndRed = (nEndRed * nFactor) / 100; + nEndGreen = (nEndGreen * nFactor) / 100; + nEndBlue = (nEndBlue * nFactor) / 100; + long nRedSteps = nEndRed - nStartRed; + long nGreenSteps = nEndGreen - nStartGreen; + long nBlueSteps = nEndBlue - nStartBlue; + + // Anzahl der Schritte berechnen, falls nichts uebergeben wurde + USHORT nStepCount = rGradient.GetSteps(); + if ( !nStepCount ) + { + long nInc; + + if ( meOutDevType != OUTDEV_PRINTER && !bMtf ) + nInc = (nMinRect < 50) ? 2 : 4; + else + nInc = ((nMinRect >> 9) + 1) << 3; + + if ( !nInc ) + nInc = 1; + + nStepCount = (USHORT)(nMinRect / nInc); + } + // minimal drei Schritte und maximal die Anzahl der Farbunterschiede + long nSteps = Max( nStepCount, (USHORT)3 ); + long nCalcSteps = Abs( nRedSteps ); + long nTempSteps = Abs( nGreenSteps ); + if ( nTempSteps > nCalcSteps ) + nCalcSteps = nTempSteps; + nTempSteps = Abs( nBlueSteps ); + if ( nTempSteps > nCalcSteps ) + nCalcSteps = nTempSteps; + if ( nCalcSteps < nSteps ) + nSteps = nCalcSteps; + if ( !nSteps ) + nSteps = 1; + + // Ausgabebegrenzungen und Schrittweite fuer jede Richtung festlegen + double fScanLeft = aRect.Left(); + double fScanTop = aRect.Top(); + double fScanRight = aRect.Right(); + double fScanBottom = aRect.Bottom(); + double fScanInc = (double)nMinRect / (double)nSteps * 0.5; + + // Startfarbe berechnen und setzen + UINT8 nRed = (UINT8)nStartRed; + UINT8 nGreen = (UINT8)nStartGreen; + UINT8 nBlue = (UINT8)nStartBlue; + + if ( bMtf ) + mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), TRUE ) ); +#ifndef REMOTE_APPSERVER + else + mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) ); +#endif + + // Recteck erstmal ausgeben + aFullRect.Bottom()++; + aFullRect.Right()++; + Polygon aPoly( aFullRect ); +#ifndef REMOTE_APPSERVER + if ( pPolyPoly ) + { + pPolyPoly->Insert( aPoly ); + aPoly = Polygon( aRect ); + aPoly.Rotate( aCenter, nAngle ); + pPolyPoly->Insert( aPoly ); + + // erstes Polygon zeichnen (entspricht Rechteck) + if ( bMtf ) + mpMetaFile->AddAction( new MetaPolyPolygonAction( *pPolyPoly ) ); + else + ImplDrawPolyPolygon( *pPolyPoly ); + } + else + ImplDrawPolygon( aPoly ); +#else + pPolyPoly->Insert( aPoly ); + aPoly = Polygon( aRect ); + aPoly.Rotate( aCenter, nAngle ); + pPolyPoly->Insert( aPoly ); + + // erstes Polygon zeichnen (entspricht Rechteck) + mpMetaFile->AddAction( new MetaPolyPolygonAction( *pPolyPoly ) ); +#endif + + // Schleife, um nacheinander die Polygone/PolyPolygone auszugeben + for ( long i = 0; i < nSteps; i++ ) + { + // neues Polygon berechnen + aRect.Left() = (long)(fScanLeft += fScanInc); + aRect.Top() = (long)(fScanTop += fScanInc); + aRect.Right() = (long)(fScanRight -= fScanInc); + aRect.Bottom() = (long)(fScanBottom -= fScanInc); + + if ( (aRect.GetWidth() < 2) || (aRect.GetHeight() < 2) ) + break; + + // ... Evt. eine maximale Anzahl von Stuetztstellen fuer W16 + aPoly = Polygon( aRect.Center(), + aRect.GetWidth() >> 1, + aRect.GetHeight() >> 1 ); + aPoly.Rotate( aCenter, nAngle ); + + // entweder langsame PolyPolygon-Ausgaben oder + // schnelles Polygon-Painting +#ifndef REMOTE_APPSERVER + if ( pPolyPoly ) + { + pPolyPoly->Replace( pPolyPoly->GetObject( 1 ), 0 ); + pPolyPoly->Replace( aPoly, 1 ); + + if ( bMtf ) + mpMetaFile->AddAction( new MetaPolyPolygonAction( *pPolyPoly ) ); + else + ImplDrawPolyPolygon( *pPolyPoly ); + } + else + ImplDrawPolygon( aPoly ); +#else + pPolyPoly->Replace( pPolyPoly->GetObject( 1 ), 0 ); + pPolyPoly->Replace( aPoly, 1 ); + mpMetaFile->AddAction( new MetaPolyPolygonAction( *pPolyPoly ) ); +#endif + + // Farbe entsprechend anpassen + nRed = ImplGetGradientColorValue( nStartRed+((nRedSteps*i)/nSteps) ); + nGreen = ImplGetGradientColorValue( nStartGreen+((nGreenSteps*i)/nSteps) ); + nBlue = ImplGetGradientColorValue( nStartBlue+((nBlueSteps*i)/nSteps) ); + + if ( bMtf ) + mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), TRUE ) ); +#ifndef REMOTE_APPSERVER + else + mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) ); +#endif + } + + // Falls PolyPolygon-Ausgabe, muessen wir noch ein letztes + // inneres Polygon zeichnen + if ( pPolyPoly ) + { + const Polygon rPoly = pPolyPoly->GetObject( 1 ); + if ( !rPoly.GetBoundRect().IsEmpty() ) + { + if ( bMtf ) + mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) ); +#ifndef REMOTE_APPSERVER + else + ImplDrawPolygon( rPoly ); +#endif + } + delete pPolyPoly; + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplDrawRectGradient( const Rectangle& rRect, + const Gradient& rGradient, + BOOL bMtf ) +{ + // Feststellen ob Ausgabe ueber Polygon oder PolyPolygon + // Bei Rasteroperationen ungleich Overpaint immer PolyPolygone, + // da es zu falschen Ergebnissen kommt, wenn man mehrfach uebereinander + // ausgibt + // Bei Druckern auch immer PolyPolygone, da nicht alle Drucker + // das Uebereinanderdrucken von Polygonen koennen + // Virtuelle Device werden auch ausgeklammert, da einige Treiber + // ansonsten zu langsam sind + PolyPolygon* pPolyPoly; + if ( (meRasterOp != ROP_OVERPAINT) || (meOutDevType != OUTDEV_WINDOW) || bMtf ) + pPolyPoly = new PolyPolygon( 2 ); + else + pPolyPoly = NULL; + + // rotiertes BoundRect ausrechnen + Rectangle aRect( rRect ); + aRect.Left()--; + aRect.Top()--; + aRect.Right()++; + aRect.Bottom()++; + + Rectangle aFullRect( aRect ); + USHORT nAngle = rGradient.GetAngle(); + double fAngle = (nAngle % 3600) * F_PI1800; + double fWidth = aRect.GetWidth(); + double fHeight = aRect.GetHeight(); + double fDX = fWidth * fabs( cos( fAngle ) ) + + fHeight * fabs( sin( fAngle ) ); + double fDY = fHeight * fabs( cos( fAngle ) ) + + fWidth * fabs( sin( fAngle ) ); + fDX = (fDX - fWidth) * 0.5 + 0.5; + fDY = (fDY - fHeight) * 0.5 + 0.5; + aRect.Left() -= (long)fDX; + aRect.Right() += (long)fDX; + aRect.Top() -= (long)fDY; + aRect.Bottom() += (long)fDY; + + // Quadratisch machen, wenn angefordert; + Size aSize = aRect.GetSize(); + if ( rGradient.GetStyle() == GRADIENT_SQUARE ) + { + if ( aSize.Width() > aSize.Height() ) + aSize.Height() = aSize.Width(); + else + aSize.Width() = aSize.Height(); + } + + // neue Mittelpunkte berechnen + long nZWidth = aRect.GetWidth() * (long)rGradient.GetOfsX() / 100; + long nZHeight = aRect.GetHeight() * (long)rGradient.GetOfsY() / 100; + long nBorderX = (long)rGradient.GetBorder() * aSize.Width() / 100; + long nBorderY = (long)rGradient.GetBorder() * aSize.Height() / 100; + Point aCenter( aRect.Left() + nZWidth, aRect.Top() + nZHeight ); + + // Rand beruecksichtigen + aSize.Width() -= nBorderX; + aSize.Height() -= nBorderY; + + // Ausgaberechteck neu setzen + aRect.Left() = aCenter.X() - (aSize.Width() >> 1); + aRect.Top() = aCenter.Y() - (aSize.Height() >> 1); + aRect.SetSize( aSize ); + + long nMinRect = Min( aRect.GetWidth(), aRect.GetHeight() ); + + // Intensitaeten von Start- und Endfarbe ggf. aendern und + // Farbschrittweiten berechnen + long nFactor; + Color aStartCol = rGradient.GetStartColor(); + Color aEndCol = rGradient.GetEndColor(); + long nStartRed = aStartCol.GetRed(); + long nStartGreen = aStartCol.GetGreen(); + long nStartBlue = aStartCol.GetBlue(); + long nEndRed = aEndCol.GetRed(); + long nEndGreen = aEndCol.GetGreen(); + long nEndBlue = aEndCol.GetBlue(); + nFactor = rGradient.GetStartIntensity(); + nStartRed = (nStartRed * nFactor) / 100; + nStartGreen = (nStartGreen * nFactor) / 100; + nStartBlue = (nStartBlue * nFactor) / 100; + nFactor = rGradient.GetEndIntensity(); + nEndRed = (nEndRed * nFactor) / 100; + nEndGreen = (nEndGreen * nFactor) / 100; + nEndBlue = (nEndBlue * nFactor) / 100; + long nRedSteps = nEndRed - nStartRed; + long nGreenSteps = nEndGreen - nStartGreen; + long nBlueSteps = nEndBlue - nStartBlue; + + // Anzahl der Schritte berechnen, falls nichts uebergeben wurde + USHORT nStepCount = rGradient.GetSteps(); + if ( !nStepCount ) + { + long nInc; + + if ( meOutDevType != OUTDEV_PRINTER && !bMtf ) + nInc = (nMinRect < 50) ? 2 : 4; + else + nInc = ((nMinRect >> 9) + 1) << 3; + + if ( !nInc ) + nInc = 1; + + nStepCount = (USHORT)(nMinRect / nInc); + } + // minimal drei Schritte und maximal die Anzahl der Farbunterschiede + long nSteps = Max( nStepCount, (USHORT)3 ); + long nCalcSteps = Abs( nRedSteps ); + long nTempSteps = Abs( nGreenSteps ); + if ( nTempSteps > nCalcSteps ) + nCalcSteps = nTempSteps; + nTempSteps = Abs( nBlueSteps ); + if ( nTempSteps > nCalcSteps ) + nCalcSteps = nTempSteps; + if ( nCalcSteps < nSteps ) + nSteps = nCalcSteps; + if ( !nSteps ) + nSteps = 1; + + // Ausgabebegrenzungen und Schrittweite fuer jede Richtung festlegen + double fScanLeft = aRect.Left(); + double fScanTop = aRect.Top(); + double fScanRight = aRect.Right(); + double fScanBottom = aRect.Bottom(); + double fScanInc = (double)nMinRect / (double)nSteps * 0.5; + + // Startfarbe berechnen und setzen + UINT8 nRed = (UINT8)nStartRed; + UINT8 nGreen = (UINT8)nStartGreen; + UINT8 nBlue = (UINT8)nStartBlue; + + if ( bMtf ) + mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), TRUE ) ); +#ifndef REMOTE_APPSERVER + else + mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) ); +#endif + + // Recteck erstmal ausgeben + Polygon aPoly( aFullRect ); +#ifndef REMOTE_APPSERVER + if ( pPolyPoly ) + { + pPolyPoly->Insert( aPoly ); + aPoly = Polygon( aRect ); + aPoly.Rotate( aCenter, nAngle ); + pPolyPoly->Insert( aPoly ); + + // erstes Polygon zeichnen (entspricht Rechteck) + if ( bMtf ) + mpMetaFile->AddAction( new MetaPolyPolygonAction( *pPolyPoly ) ); + else + ImplDrawPolyPolygon( *pPolyPoly ); + } + else + ImplDrawPolygon( aPoly ); +#else + pPolyPoly->Insert( aPoly ); + aPoly = Polygon( aRect ); + aPoly.Rotate( aCenter, nAngle ); + pPolyPoly->Insert( aPoly ); + + // erstes Polygon zeichnen (entspricht Rechteck) + mpMetaFile->AddAction( new MetaPolyPolygonAction( *pPolyPoly ) ); +#endif + + // Schleife, um nacheinander die Polygone/PolyPolygone auszugeben + for ( long i = 0; i < nSteps; i++ ) + { + // neues Polygon berechnen + aRect.Left() = (long)(fScanLeft += fScanInc); + aRect.Top() = (long)(fScanTop += fScanInc); + aRect.Right() = (long)(fScanRight -= fScanInc); + aRect.Bottom() = (long)(fScanBottom-= fScanInc); + + if ( (aRect.GetWidth() < 2) || (aRect.GetHeight() < 2) ) + break; + + aPoly = Polygon( aRect ); + aPoly.Rotate( aCenter, nAngle ); + +#ifndef REMOTE_APPSERVER + // entweder langsame PolyPolygon-Ausgaben oder + // schnelles Polygon-Painting + if ( pPolyPoly ) + { + pPolyPoly->Replace( pPolyPoly->GetObject( 1 ), 0 ); + pPolyPoly->Replace( aPoly, 1 ); + + if ( bMtf ) + mpMetaFile->AddAction( new MetaPolyPolygonAction( *pPolyPoly ) ); + else + ImplDrawPolyPolygon( *pPolyPoly ); + } + else + ImplDrawPolygon( aPoly ); +#else + pPolyPoly->Replace( pPolyPoly->GetObject( 1 ), 0 ); + pPolyPoly->Replace( aPoly, 1 ); + mpMetaFile->AddAction( new MetaPolyPolygonAction( *pPolyPoly ) ); +#endif + + // Farbe entsprechend anpassen + nRed = ImplGetGradientColorValue( nStartRed+((nRedSteps*i)/nSteps) ); + nGreen = ImplGetGradientColorValue( nStartGreen+((nGreenSteps*i)/nSteps) ); + nBlue = ImplGetGradientColorValue( nStartBlue+((nBlueSteps*i)/nSteps) ); + + if ( bMtf ) + mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), TRUE ) ); +#ifndef REMOTE_APPSERVER + else + mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) ); +#endif + } + + // Falls PolyPolygon-Ausgabe, muessen wir noch ein letztes + // inneres Polygon zeichnen + if ( pPolyPoly ) + { + const Polygon rPoly = pPolyPoly->GetObject( 1 ); + if ( !rPoly.GetBoundRect().IsEmpty() ) + { + if ( bMtf ) + mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) ); +#ifndef REMOTE_APPSERVER + else + ImplDrawPolygon( rPoly ); +#endif + } + delete pPolyPoly; + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawGradient( const Rectangle& rRect, + const Gradient& rGradient ) +{ + DBG_TRACE( "OutputDevice::DrawGradient()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rGradient, Gradient, NULL ); + + if ( mnDrawMode & DRAWMODE_NOGRADIENT ) + return; + else if ( mnDrawMode & ( DRAWMODE_BLACKGRADIENT | DRAWMODE_WHITEGRADIENT ) ) + { + BYTE cCmpVal; + + if ( mnDrawMode & DRAWMODE_BLACKGRADIENT ) + cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT ) ? 0x80 : 0; + else + cCmpVal = 255; + + Color aCol( cCmpVal, cCmpVal, cCmpVal ); + Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); + SetLineColor( aCol ); + SetFillColor( aCol ); + DrawRect( rRect ); + Pop(); + return; + } + + Gradient aGradient( rGradient ); + + if ( mnDrawMode & ( DRAWMODE_GRAYGRADIENT | DRAWMODE_GHOSTEDGRADIENT ) ) + { + Color aStartCol( aGradient.GetStartColor() ); + Color aEndCol( aGradient.GetEndColor() ); + + if ( mnDrawMode & DRAWMODE_GRAYGRADIENT ) + { + BYTE cStartLum = aStartCol.GetLuminance(), cEndLum = aEndCol.GetLuminance(); + aStartCol = Color( cStartLum, cStartLum, cStartLum ); + aEndCol = Color( cEndLum, cEndLum, cEndLum ); + } + + if ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT ) + { + aStartCol = Color( ( aStartCol.GetRed() >> 1 ) | 0x80, + ( aStartCol.GetGreen() >> 1 ) | 0x80, + ( aStartCol.GetBlue() >> 1 ) | 0x80 ); + + aEndCol = Color( ( aEndCol.GetRed() >> 1 ) | 0x80, + ( aEndCol.GetGreen() >> 1 ) | 0x80, + ( aEndCol.GetBlue() >> 1 ) | 0x80 ); + } + + aGradient.SetStartColor( aStartCol ); + aGradient.SetEndColor( aEndCol ); + } + + if( mpMetaFile ) + mpMetaFile->AddAction( new MetaGradientAction( rRect, aGradient ) ); + + if( !IsDeviceOutputNecessary() ) + return; + + // Rechteck in Pixel umrechnen + Rectangle aRect( ImplLogicToDevicePixel( rRect ) ); + aRect.Justify(); + + // Wenn Rechteck leer ist, brauchen wir nichts machen + if ( !aRect.IsEmpty() ) + { +#ifndef REMOTE_APPSERVER + // Clip Region sichern + Push( PUSH_CLIPREGION ); + IntersectClipRegion( rRect ); + + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + + if ( !mbOutputClipped ) + { + // Gradienten werden ohne Umrandung gezeichnet + if ( mbLineColor || mbInitLineColor ) + { + mpGraphics->SetLineColor(); + mbInitLineColor = TRUE; + } + + mbInitFillColor = TRUE; + + // calculate step count if neccessary + if ( !aGradient.GetSteps() ) + aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT ); + + // Farbverlauf ausgeben + switch( aGradient.GetStyle() ) + { + case GRADIENT_LINEAR: + case GRADIENT_AXIAL: + ImplDrawLinearGradient( aRect, aGradient, FALSE ); + break; + + case GRADIENT_RADIAL: + case GRADIENT_ELLIPTICAL: + ImplDrawRadialGradient( aRect, aGradient, FALSE ); + break; + + case GRADIENT_SQUARE: + case GRADIENT_RECT: + ImplDrawRectGradient( aRect, aGradient, FALSE ); + break; + } + } + + Pop(); +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + pGraphics->DrawGradient( aRect, aGradient ); +#endif + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawGradient( const PolyPolygon& rPolyPoly, + const Gradient& rGradient ) +{ + DBG_TRACE( "OutputDevice::DrawGradient()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rGradient, Gradient, NULL ); + + if( rPolyPoly.Count() && rPolyPoly[ 0 ].GetSize() && !( mnDrawMode & DRAWMODE_NOGRADIENT ) ) + { + if( mnDrawMode & ( DRAWMODE_BLACKGRADIENT | DRAWMODE_WHITEGRADIENT ) ) + { + BYTE cCmpVal; + + if ( mnDrawMode & DRAWMODE_BLACKGRADIENT ) + cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT ) ? 0x80 : 0; + else + cCmpVal = 255; + + Color aCol( cCmpVal, cCmpVal, cCmpVal ); + Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); + SetLineColor( aCol ); + SetFillColor( aCol ); + DrawPolyPolygon( rPolyPoly ); + Pop(); + return; + } + + if( mpMetaFile ) + { + const Rectangle aRect( rPolyPoly.GetBoundRect() ); + + if( OUTDEV_PRINTER == meOutDevType ) + { + Push( PUSH_CLIPREGION ); + IntersectClipRegion( rPolyPoly ); + DrawGradient( aRect, rGradient ); + Pop(); + } + else + { + const BOOL bOldOutput = IsOutputEnabled(); + + EnableOutput( FALSE ); + Push( PUSH_RASTEROP ); + SetRasterOp( ROP_XOR ); + DrawGradient( aRect, rGradient ); + SetFillColor( COL_BLACK ); + SetRasterOp( ROP_0 ); + DrawPolyPolygon( rPolyPoly ); + SetRasterOp( ROP_XOR ); + DrawGradient( aRect, rGradient ); + Pop(); + EnableOutput( bOldOutput ); + } + } + + if( !IsDeviceOutputNecessary() ) + return; + + Gradient aGradient( rGradient ); + + if ( mnDrawMode & ( DRAWMODE_GRAYGRADIENT | DRAWMODE_GHOSTEDGRADIENT ) ) + { + Color aStartCol( aGradient.GetStartColor() ); + Color aEndCol( aGradient.GetEndColor() ); + + if ( mnDrawMode & DRAWMODE_GRAYGRADIENT ) + { + BYTE cStartLum = aStartCol.GetLuminance(), cEndLum = aEndCol.GetLuminance(); + aStartCol = Color( cStartLum, cStartLum, cStartLum ); + aEndCol = Color( cEndLum, cEndLum, cEndLum ); + } + + if ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT ) + { + aStartCol = Color( ( aStartCol.GetRed() >> 1 ) | 0x80, + ( aStartCol.GetGreen() >> 1 ) | 0x80, + ( aStartCol.GetBlue() >> 1 ) | 0x80 ); + + aEndCol = Color( ( aEndCol.GetRed() >> 1 ) | 0x80, + ( aEndCol.GetGreen() >> 1 ) | 0x80, + ( aEndCol.GetBlue() >> 1 ) | 0x80 ); + } + + aGradient.SetStartColor( aStartCol ); + aGradient.SetEndColor( aEndCol ); + } + +#ifndef REMOTE_APPSERVER + if( OUTDEV_PRINTER == meOutDevType ) + { + Push( PUSH_CLIPREGION ); + IntersectClipRegion( rPolyPoly ); + DrawGradient( rPolyPoly.GetBoundRect(), aGradient ); + Pop(); + } + else + { + const PolyPolygon aPolyPoly( LogicToPixel( rPolyPoly ) ); + const Rectangle aBoundRect( aPolyPoly.GetBoundRect() ); + Point aPoint; + Rectangle aDstRect( aPoint, GetOutputSizePixel() ); + + aDstRect.Intersection( aBoundRect ); + + if( OUTDEV_WINDOW == meOutDevType ) + { + const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() ); + + if( !aPaintRgn.IsNull() ) + aDstRect.Intersection( LogicToPixel( aPaintRgn ).GetBoundRect() ); + } + + if( !aDstRect.IsEmpty() ) + { + VirtualDevice aVDev; + const Size aDstSize( aDstRect.GetSize() ); + + if( aVDev.SetOutputSizePixel( aDstSize) ) + { + MapMode aVDevMap; + const RasterOp eOldROP = GetRasterOp(); + const BOOL bOldMap = mbMap; + + mbMap = FALSE; + + aVDev.DrawOutDev( Point(), aDstSize, aDstRect.TopLeft(), aDstSize, *this ); + DrawGradient( aBoundRect, aGradient ); + aVDev.SetRasterOp( ROP_XOR ); + aVDev.DrawOutDev( Point(), aDstSize, aDstRect.TopLeft(), aDstSize, *this ); + aVDev.SetFillColor( COL_BLACK ); + aVDev.SetRasterOp( ROP_0 ); + aVDevMap.SetOrigin( Point( -aDstRect.Left(), -aDstRect.Top() ) ); + aVDev.SetMapMode( aVDevMap ); + aVDev.DrawPolyPolygon( aPolyPoly ); + aVDevMap.SetOrigin( Point() ); + aVDev.SetMapMode( aVDevMap ); + SetRasterOp( ROP_XOR ); + DrawOutDev( aDstRect.TopLeft(), aDstSize, Point(), aDstSize, aVDev ); + SetRasterOp( eOldROP ); + + mbMap = bOldMap; + } + } + } +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + pGraphics->DrawGradient( ImplLogicToDevicePixel( rPolyPoly ), aGradient ); +#endif + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::AddGradientActions( const Rectangle& rRect, const Gradient& rGradient, + GDIMetaFile& rMtf ) +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rGradient, Gradient, NULL ); + + Rectangle aRect( rRect ); + + aRect.Justify(); + + // Wenn Rechteck leer ist, brauchen wir nichts machen + if ( !aRect.IsEmpty() ) + { + Gradient aGradient( rGradient ); + GDIMetaFile* pOldMtf = mpMetaFile; + + mpMetaFile = &rMtf; + mpMetaFile->AddAction( new MetaPushAction( PUSH_ALL ) ); + mpMetaFile->AddAction( new MetaISectRectClipRegionAction( aRect ) ); + mpMetaFile->AddAction( new MetaLineColorAction( Color(), FALSE ) ); + + // calculate step count if neccessary + if ( !aGradient.GetSteps() ) + aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT ); + + // Farbverlaufactions aufzeichnen + switch( rGradient.GetStyle() ) + { + case GRADIENT_LINEAR: + case GRADIENT_AXIAL: + ImplDrawLinearGradient( aRect, aGradient, TRUE ); + break; + + case GRADIENT_RADIAL: + case GRADIENT_ELLIPTICAL: + ImplDrawRadialGradient( aRect, aGradient, TRUE ); + break; + + case GRADIENT_SQUARE: + case GRADIENT_RECT: + ImplDrawRectGradient( aRect, aGradient, TRUE ); + break; + } + + mpMetaFile->AddAction( new MetaPopAction() ); + mpMetaFile = pOldMtf; + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch ) +{ + DBG_TRACE( "OutputDevice::DrawHatch()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + Hatch aHatch( rHatch ); + + if ( mnDrawMode & ( DRAWMODE_BLACKLINE | DRAWMODE_WHITELINE | + DRAWMODE_GRAYLINE | DRAWMODE_GHOSTEDLINE ) ) + { + Color aColor( rHatch.GetColor() ); + + if ( mnDrawMode & DRAWMODE_BLACKLINE ) + aColor = Color( COL_BLACK ); + else if ( mnDrawMode & DRAWMODE_WHITELINE ) + aColor = Color( COL_WHITE ); + else if ( mnDrawMode & DRAWMODE_GRAYLINE ) + { + const UINT8 cLum = aColor.GetLuminance(); + aColor = Color( cLum, cLum, cLum ); + } + + if ( mnDrawMode & DRAWMODE_GHOSTEDLINE ) + { + aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80, + ( aColor.GetGreen() >> 1 ) | 0x80, + ( aColor.GetBlue() >> 1 ) | 0x80); + } + + aHatch.SetColor( aColor ); + } + + if( mpMetaFile ) + mpMetaFile->AddAction( new MetaHatchAction( rPolyPoly, aHatch ) ); + + if( !IsDeviceOutputNecessary() ) + return; + +#ifndef REMOTE_APPSERVER + if( !mpGraphics && !ImplGetGraphics() ) + return; + + if( mbInitClipRegion ) + ImplInitClipRegion(); + + if( mbOutputClipped ) + return; +#endif + + PolyPolygon aPolyPoly( rPolyPoly ); + aPolyPoly.Optimize( POLY_OPTIMIZE_NO_SAME | POLY_OPTIMIZE_CLOSE ); + + if( aPolyPoly.Count() ) + { +#ifndef REMOTE_APPSERVER + GDIMetaFile* pOldMetaFile = mpMetaFile; + + mpMetaFile = NULL; + Push( PUSH_LINECOLOR ); + SetLineColor( aHatch.GetColor() ); + ImplInitLineColor(); + ImplDrawHatch( aPolyPoly, aHatch, FALSE ); + Pop(); + mpMetaFile = pOldMetaFile; +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + aHatch.SetDistance( ImplLogicWidthToDevicePixel( aHatch.GetDistance() ) ); + pGraphics->DrawHatch( ImplLogicToDevicePixel( aPolyPoly ), aHatch ); + } +#endif + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::AddHatchActions( const PolyPolygon& rPolyPoly, const Hatch& rHatch, + GDIMetaFile& rMtf ) +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + PolyPolygon aPolyPoly( rPolyPoly ); + aPolyPoly.Optimize( POLY_OPTIMIZE_NO_SAME | POLY_OPTIMIZE_CLOSE ); + + if( aPolyPoly.Count() ) + { + GDIMetaFile* pOldMtf = mpMetaFile; + + mpMetaFile = &rMtf; + mpMetaFile->AddAction( new MetaPushAction( PUSH_ALL ) ); + mpMetaFile->AddAction( new MetaLineColorAction( rHatch.GetColor(), TRUE ) ); + ImplDrawHatch( aPolyPoly, rHatch, TRUE ); + mpMetaFile->AddAction( new MetaPopAction() ); + mpMetaFile = pOldMtf; + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplDrawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch, BOOL bMtf ) +{ + Rectangle aRect( rPolyPoly.GetBoundRect() ); + const long nLogPixelWidth = ImplDevicePixelToLogicWidth( 1 ); + const long nWidth = ImplDevicePixelToLogicWidth( Max( ImplLogicWidthToDevicePixel( rHatch.GetDistance() ), 5L ) ); + Point* pPtBuffer = new Point[ HATCH_MAXPOINTS ]; + Point aPt1, aPt2, aEndPt1; + Size aInc; + + // Single hatch + aRect.Left() -= nLogPixelWidth; aRect.Top() -= nLogPixelWidth; aRect.Right() += nLogPixelWidth; aRect.Bottom() += nLogPixelWidth; + ImplCalcHatchValues( aRect, nWidth, rHatch.GetAngle(), aPt1, aPt2, aInc, aEndPt1 ); + do + { + ImplDrawHatchLine( Line( aPt1, aPt2 ), rPolyPoly, pPtBuffer, bMtf ); + aPt1.X() += aInc.Width(); aPt1.Y() += aInc.Height(); + aPt2.X() += aInc.Width(); aPt2.Y() += aInc.Height(); + } + while( ( aPt1.X() <= aEndPt1.X() ) && ( aPt1.Y() <= aEndPt1.Y() ) ); + + if( ( rHatch.GetStyle() == HATCH_DOUBLE ) || ( rHatch.GetStyle() == HATCH_TRIPLE ) ) + { + // Double hatch + ImplCalcHatchValues( aRect, nWidth, rHatch.GetAngle() + 900, aPt1, aPt2, aInc, aEndPt1 ); + do + { + ImplDrawHatchLine( Line( aPt1, aPt2 ), rPolyPoly, pPtBuffer, bMtf ); + aPt1.X() += aInc.Width(); aPt1.Y() += aInc.Height(); + aPt2.X() += aInc.Width(); aPt2.Y() += aInc.Height(); + } + while( ( aPt1.X() <= aEndPt1.X() ) && ( aPt1.Y() <= aEndPt1.Y() ) ); + + if( rHatch.GetStyle() == HATCH_TRIPLE ) + { + // Triple hatch + ImplCalcHatchValues( aRect, nWidth, rHatch.GetAngle() + 450, aPt1, aPt2, aInc, aEndPt1 ); + do + { + ImplDrawHatchLine( Line( aPt1, aPt2 ), rPolyPoly, pPtBuffer, bMtf ); + aPt1.X() += aInc.Width(); aPt1.Y() += aInc.Height(); + aPt2.X() += aInc.Width(); aPt2.Y() += aInc.Height(); + } + while( ( aPt1.X() <= aEndPt1.X() ) && ( aPt1.Y() <= aEndPt1.Y() ) ); + } + } + + delete[] pPtBuffer; +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplCalcHatchValues( const Rectangle& rRect, long nDist, USHORT nAngle10, + Point& rPt1, Point& rPt2, Size& rInc, Point& rEndPt1 ) +{ + Point aRef; + long nAngle = nAngle10 % 1800; + long nOffset = 0; + + if( nAngle > 900 ) + nAngle -= 1800; + + aRef = ( !IsRefPoint() ? rRect.TopLeft() : GetRefPoint() ); + + if( 0 == nAngle ) + { + rInc = Size( 0, nDist ); + rPt1 = rRect.TopLeft(); + rPt2 = rRect.TopRight(); + rEndPt1 = rRect.BottomLeft(); + + if( aRef.Y() <= rRect.Top() ) + nOffset = ( ( rRect.Top() - aRef.Y() ) % nDist ); + else + nOffset = ( nDist - ( ( aRef.Y() - rRect.Top() ) % nDist ) ); + + rPt1.Y() -= nOffset; + rPt2.Y() -= nOffset; + } + else if( 900 == nAngle ) + { + rInc = Size( nDist, 0 ); + rPt1 = rRect.TopLeft(); + rPt2 = rRect.BottomLeft(); + rEndPt1 = rRect.TopRight(); + + if( aRef.X() <= rRect.Left() ) + nOffset = ( rRect.Left() - aRef.X() ) % nDist; + else + nOffset = nDist - ( ( aRef.X() - rRect.Left() ) % nDist ); + + rPt1.X() -= nOffset; + rPt2.X() -= nOffset; + } + else if( nAngle >= -450 && nAngle <= 450 ) + { + const double fAngle = F_PI1800 * labs( nAngle ); + const double fTan = tan( fAngle ); + const long nYOff = FRound( ( rRect.Right() - rRect.Left() ) * fTan ); + long nPY; + + rInc = Size( 0, nDist = FRound( nDist / cos( fAngle ) ) ); + + if( nAngle > 0 ) + { + rPt1 = rRect.TopLeft(); + rPt2 = Point( rRect.Right(), rRect.Top() - nYOff ); + rEndPt1 = Point( rRect.Left(), rRect.Bottom() + nYOff ); + nPY = FRound( aRef.Y() - ( ( rPt1.X() - aRef.X() ) * fTan ) ); + } + else + { + rPt1 = rRect.TopRight(); + rPt2 = Point( rRect.Left(), rRect.Top() - nYOff ); + rEndPt1 = Point( rRect.Right(), rRect.Bottom() + nYOff ); + nPY = FRound( aRef.Y() + ( ( rPt1.X() - aRef.X() ) * fTan ) ); + } + + if( nPY <= rPt1.Y() ) + nOffset = ( rPt1.Y() - nPY ) % nDist; + else + nOffset = nDist - ( ( nPY - rPt1.Y() ) % nDist ); + + rPt1.Y() -= nOffset; + rPt2.Y() -= nOffset; + } + else + { + const double fAngle = F_PI1800 * labs( nAngle ); + const double fTan = tan( fAngle ); + const long nXOff = FRound( ( rRect.Bottom() - rRect.Top() ) / fTan ); + long nPX; + + rInc = Size( nDist = FRound( nDist / sin( fAngle ) ), 0 ); + + if( nAngle > 0 ) + { + rPt1 = rRect.TopLeft(); + rPt2 = Point( rRect.Left() - nXOff, rRect.Bottom() ); + rEndPt1 = Point( rRect.Right() + nXOff, rRect.Top() ); + nPX = FRound( aRef.X() - ( ( rPt1.Y() - aRef.Y() ) / fTan ) ); + } + else + { + rPt1 = rRect.BottomLeft(); + rPt2 = Point( rRect.Left() - nXOff, rRect.Top() ); + rEndPt1 = Point( rRect.Right() + nXOff, rRect.Bottom() ); + nPX = FRound( aRef.X() + ( ( rPt1.Y() - aRef.Y() ) / fTan ) ); + } + + if( nPX <= rPt1.X() ) + nOffset = ( rPt1.X() - nPX ) % nDist; + else + nOffset = nDist - ( ( nPX - rPt1.X() ) % nDist ); + + rPt1.X() -= nOffset; + rPt2.X() -= nOffset; + } +} + +// ------------------------------------------------------------------------ + +void OutputDevice::ImplDrawHatchLine( const Line& rLine, const PolyPolygon& rPolyPoly, + Point* pPtBuffer, BOOL bMtf ) +{ +#ifdef REMOTE_APPSERVER + ImplServerGraphics* pGraphics; + if( !bMtf && !( pGraphics = ImplGetServerGraphics() ) ) + return; +#endif + + double fSaveDist = 0.0; + long nPCounter = 0; + + for( long nPoly = 0, nPolyCount = rPolyPoly.Count(); nPoly < nPolyCount; nPoly++ ) + { + const Polygon& rPoly = rPolyPoly[ (USHORT) nPoly ]; + + if( rPoly.GetSize() > 1 ) + { + Point aIntersection; + Point aPt1( rPoly[0] ); + + for( long i = 1, nCount = rPoly.GetSize(); i < nCount; i++ ) + { + const Point& rPt2 = rPoly[ (USHORT) i ]; + + if( rLine.Intersection( Line( aPt1, rPt2 ), aIntersection ) ) + { + const BOOL bDifferent = !nPCounter || aIntersection != pPtBuffer[ nPCounter - 1 ]; + + if( aIntersection == aPt1 ) + { + double fDist1 = rLine.GetDistance( rPoly[ ( i > 1 ) ? i - 2 : nCount - 2 ] ); + double fDist2 = rLine.GetDistance( rPt2 ); + + if( 1 == i ) + nCount--; + + if( bDifferent ) + { + pPtBuffer[ nPCounter++ ] = aIntersection; + + if( ( ( fDist1 < 0.0 && fDist2 < 0.0 ) || ( fDist1 > 0.0 && fDist2 > 0.0 ) ) ) + pPtBuffer[ nPCounter++ ] = aIntersection; + else if( fDist1 == 0.0 ) + { + if( ( fSaveDist > 0.0 && fDist2 < 0.0 ) || ( fSaveDist < 0.0 && fDist2 > 0.0 ) ) + pPtBuffer[ nPCounter++ ] = aIntersection; + } + } + } + else if( aIntersection == rPt2 ) + { + double fDist1 = rLine.GetDistance( aPt1 ); + double fDist2 = rLine.GetDistance( rPoly[ ( i < nCount - 1 ) ? i + 1 : 1 ] ); + + if( bDifferent ) + { + pPtBuffer[ nPCounter++ ] = aIntersection; + + if( ( ( fDist1 < 0.0 && fDist2 < 0.0 ) || ( fDist1 > 0.0 && fDist2 > 0.0 ) ) ) + pPtBuffer[ nPCounter++ ] = aIntersection; + else if( fDist2 == 0.0 ) + fSaveDist = fDist1; + } + } + else + pPtBuffer[ nPCounter++ ] = aIntersection; + } + + aPt1 = rPt2; + } + } + } + + if( nPCounter > 1 ) + { + qsort( pPtBuffer, nPCounter, sizeof( Point ), ImplHatchCmpFnc ); + + if( nPCounter & 1 ) + nPCounter--; + + if( bMtf ) + { + for( long i = 0; i < nPCounter; i += 2 ) + mpMetaFile->AddAction( new MetaLineAction( pPtBuffer[ i ], pPtBuffer[ i + 1 ] ) ); + } + else + { + for( long i = 0; i < nPCounter; i += 2 ) + { + const Point aPt1( ImplLogicToDevicePixel( pPtBuffer[ i ] ) ); + const Point aPt2( ImplLogicToDevicePixel( pPtBuffer[ i + 1 ] ) ); + +#ifndef REMOTE_APPSERVER + mpGraphics->DrawLine( aPt1.X(), aPt1.Y(), aPt2.X(), aPt2.Y() ); +#else + pGraphics->DrawLine( aPt1, aPt2 ); +#endif + } + } + } +} diff --git a/vcl/source/gdi/outdev5.cxx b/vcl/source/gdi/outdev5.cxx new file mode 100644 index 000000000000..f162b1196fd1 --- /dev/null +++ b/vcl/source/gdi/outdev5.cxx @@ -0,0 +1,430 @@ +/************************************************************************* + * + * $RCSfile: outdev5.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_OUTDEV_CXX +#include <tools/ref.hxx> +#ifndef REMOTE_APPSERVER +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#endif + +#ifndef REMOTE_APPSERVER +#ifndef _SV_SALGDI_HXX +#include <salgdi.hxx> +#endif +#else +#ifndef _SV_RMOUTDEV_HXX +#include <rmoutdev.hxx> +#endif +#endif + +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif + +#ifndef _SV_SVDATA_HXX +#include <svdata.hxx> +#endif +#ifndef _SV_POLY_H +#include <poly.h> +#endif +#ifndef _SV_POLY_HXX +#include <poly.hxx> +#endif +#ifndef _SV_METAACT_HXX +#include <metaact.hxx> +#endif +#ifndef _SV_GDIMTF_HXX +#include <gdimtf.hxx> +#endif +#ifndef _SV_OUTDATA_HXX +#include <outdata.hxx> +#endif +#ifndef _SV_OUTDEV_H +#include <outdev.h> +#endif +#ifndef _SV_OUTDEV_HXX +#include <outdev.hxx> +#endif + +// ======================================================================= + +DBG_NAMEEX( OutputDevice ); + +// ======================================================================= + +void OutputDevice::DrawRect( const Rectangle& rRect, + ULONG nHorzRound, ULONG nVertRound ) +{ + DBG_TRACE( "OutputDevice::DrawRoundRect()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaRoundRectAction( rRect, nHorzRound, nVertRound ) ); + + if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) ) + return; + + const Rectangle aRect( ImplLogicToDevicePixel( rRect ) ); + + if ( aRect.IsEmpty() ) + return; + + nHorzRound = ImplLogicWidthToDevicePixel( nHorzRound ); + nVertRound = ImplLogicHeightToDevicePixel( nVertRound ); + +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; + + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); + + if ( !nHorzRound && !nVertRound ) + mpGraphics->DrawRect( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight() ); + else + { + const Polygon aRoundRectPoly( aRect, nHorzRound, nVertRound ); + + if ( aRoundRectPoly.GetSize() >= 2 ) + { + const SalPoint* pPtAry = (const SalPoint*) aRoundRectPoly.ImplGetConstPointAry(); + + if ( !mbFillColor ) + mpGraphics->DrawPolyLine( aRoundRectPoly.GetSize(), pPtAry ); + else + mpGraphics->DrawPolygon( aRoundRectPoly.GetSize(), pPtAry ); + } + } +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); + if ( !nHorzRound || !nVertRound ) + pGraphics->DrawRect( aRect ); + else + pGraphics->DrawRect( aRect, nHorzRound, nVertRound ); + } +#endif +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawEllipse( const Rectangle& rRect ) +{ + DBG_TRACE( "OutputDevice::DrawEllipse()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaEllipseAction( rRect ) ); + + if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) ) + return; + + Rectangle aRect( ImplLogicToDevicePixel( rRect ) ); + if ( aRect.IsEmpty() ) + return; + +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; + + if ( mbInitLineColor ) + ImplInitLineColor(); + + Polygon aRectPoly( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 ); + if ( aRectPoly.GetSize() >= 2 ) + { + const SalPoint* pPtAry = (const SalPoint*)aRectPoly.ImplGetConstPointAry(); + if ( !mbFillColor ) + mpGraphics->DrawPolyLine( aRectPoly.GetSize(), pPtAry ); + else + { + if ( mbInitFillColor ) + ImplInitFillColor(); + mpGraphics->DrawPolygon( aRectPoly.GetSize(), pPtAry ); + } + } +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); + pGraphics->DrawEllipse( aRect ); + } +#endif +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawArc( const Rectangle& rRect, + const Point& rStartPt, const Point& rEndPt ) +{ + DBG_TRACE( "OutputDevice::DrawArc()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaArcAction( rRect, rStartPt, rEndPt ) ); + + if ( !IsDeviceOutputNecessary() || !mbLineColor ) + return; + + Rectangle aRect( ImplLogicToDevicePixel( rRect ) ); + if ( aRect.IsEmpty() ) + return; + +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; + + if ( mbInitLineColor ) + ImplInitLineColor(); + + const Point aStart( ImplLogicToDevicePixel( rStartPt ) ); + const Point aEnd( ImplLogicToDevicePixel( rEndPt ) ); + Polygon aArcPoly( aRect, aStart, aEnd, POLY_ARC ); + + if ( aArcPoly.GetSize() >= 2 ) + { + const SalPoint* pPtAry = (const SalPoint*)aArcPoly.ImplGetConstPointAry(); + mpGraphics->DrawPolyLine( aArcPoly.GetSize(), pPtAry ); + } +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); + pGraphics->DrawArc( aRect, + ImplLogicToDevicePixel( rStartPt ), + ImplLogicToDevicePixel( rEndPt ) ); + } +#endif +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawPie( const Rectangle& rRect, + const Point& rStartPt, const Point& rEndPt ) +{ + DBG_TRACE( "OutputDevice::DrawPie()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaPieAction( rRect, rStartPt, rEndPt ) ); + + if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) ) + return; + + Rectangle aRect( ImplLogicToDevicePixel( rRect ) ); + if ( aRect.IsEmpty() ) + return; + +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; + + if ( mbInitLineColor ) + ImplInitLineColor(); + + const Point aStart( ImplLogicToDevicePixel( rStartPt ) ); + const Point aEnd( ImplLogicToDevicePixel( rEndPt ) ); + Polygon aPiePoly( aRect, aStart, aEnd, POLY_PIE ); + + if ( aPiePoly.GetSize() >= 2 ) + { + const SalPoint* pPtAry = (const SalPoint*)aPiePoly.ImplGetConstPointAry(); + if ( !mbFillColor ) + mpGraphics->DrawPolyLine( aPiePoly.GetSize(), pPtAry ); + else + { + if ( mbInitFillColor ) + ImplInitFillColor(); + mpGraphics->DrawPolygon( aPiePoly.GetSize(), pPtAry ); + } + } +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); + pGraphics->DrawPie( aRect, + ImplLogicToDevicePixel( rStartPt ), + ImplLogicToDevicePixel( rEndPt ) ); + } +#endif +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawChord( const Rectangle& rRect, + const Point& rStartPt, const Point& rEndPt ) +{ + DBG_TRACE( "OutputDevice::DrawChord()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaChordAction( rRect, rStartPt, rEndPt ) ); + + if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) ) + return; + + Rectangle aRect( ImplLogicToDevicePixel( rRect ) ); + if ( aRect.IsEmpty() ) + return; + +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; + + if ( mbInitLineColor ) + ImplInitLineColor(); + + const Point aStart( ImplLogicToDevicePixel( rStartPt ) ); + const Point aEnd( ImplLogicToDevicePixel( rEndPt ) ); + Polygon aChordPoly( aRect, aStart, aEnd, POLY_CHORD ); + + if ( aChordPoly.GetSize() >= 2 ) + { + const SalPoint* pPtAry = (const SalPoint*)aChordPoly.ImplGetConstPointAry(); + if ( !mbFillColor ) + mpGraphics->DrawPolyLine( aChordPoly.GetSize(), pPtAry ); + else + { + if ( mbInitFillColor ) + ImplInitFillColor(); + mpGraphics->DrawPolygon( aChordPoly.GetSize(), pPtAry ); + } + } +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); + pGraphics->DrawChord( aRect, + ImplLogicToDevicePixel( rStartPt ), + ImplLogicToDevicePixel( rEndPt ) ); + } +#endif +} diff --git a/vcl/source/gdi/outdev6.cxx b/vcl/source/gdi/outdev6.cxx new file mode 100644 index 000000000000..371334530488 --- /dev/null +++ b/vcl/source/gdi/outdev6.cxx @@ -0,0 +1,1043 @@ +/************************************************************************* + * + * $RCSfile: outdev6.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_WALL_CXX + +#include <math.h> +#ifndef REMOTE_APPSERVER +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#ifndef _SV_SALGDI_HXX +#include <salgdi.hxx> +#endif +#else // REMOTE_APPSERVER +#include <tools/stream.hxx> +#endif // REMOTE_APPSERVER +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _SV_OUTDEV_H +#include <outdev.h> +#endif +#ifndef _SV_OUTDEV_HXX +#include <outdev.hxx> +#endif +#ifndef _SV_VIRDEV_HXX +#include <virdev.hxx> +#endif +#ifndef _SV_BMPACC_HXX +#include <bmpacc.hxx> +#endif +#ifndef _SV_METAACT_HXX +#include <metaact.hxx> +#endif +#ifndef _SV_GDIMTF_HXX +#include <gdimtf.hxx> +#endif +#ifndef _SV_SVAPP_HXX +#include <svapp.hxx> +#endif +#ifndef _SV_WRKWIN_HXX +#include <wrkwin.hxx> +#endif +#ifndef _SV_GRAPH_HXX +#include <graph.hxx> +#endif +#ifdef REMOTE_APPSERVER +#include <rmoutdev.hxx> +#endif +#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_ +#include <com/sun/star/uno/Sequence.hxx> +#endif + +// ======================================================================== + +DBG_NAMEEX( OutputDevice ); + +// ------------------------------------------------------------------------ + +void OutputDevice::DrawGrid( const Rectangle& rRect, const Size& rDist, ULONG nFlags ) +{ + DBG_TRACE( "OutputDevice::DrawGrid()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + Rectangle aDstRect( PixelToLogic( Point() ), GetOutputSize() ); + aDstRect.Intersection( rRect ); + + if( aDstRect.IsEmpty() ) + return; + +#ifndef REMOTE_APPSERVER + if( !mpGraphics && !ImplGetGraphics() ) + return; + + if( mbInitClipRegion ) + ImplInitClipRegion(); + + if( mbOutputClipped ) + return; +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + + if( !pGraphics ) + return; +#endif + + const long nDistX = Max( rDist.Width(), 1L ); + const long nDistY = 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(); + +#ifndef REMOTE_APPSERVER + const BOOL bOldMap = mbMap; + mbMap = FALSE; + + if( nFlags & GRID_DOTS ) + { + for( long i = 0L; i < nVertCount; i++ ) + for( long j = 0L, nY = aVertBuf[ i ]; j < nHorzCount; j++ ) + mpGraphics->DrawPixel( aHorzBuf[ j ], nY ); + } + else + { + if( nFlags & GRID_HORZLINES ) + { + for( long i = 0L; i < nVertCount; i++ ) + { + nY = aVertBuf[ i ]; + mpGraphics->DrawLine( nStartX, nY, nEndX, nY ); + } + } + + if( nFlags & GRID_VERTLINES ) + { + for( long i = 0L; i < nHorzCount; i++ ) + { + nX = aHorzBuf[ i ]; + mpGraphics->DrawLine( nX, nStartY, nX, nEndY ); + } + } + } + + mbMap = bOldMap; +#else // REMOTE_APPSERVER + aHorzBuf.realloc( nHorzCount ); + aVertBuf.realloc( nVertCount ); + pGraphics->DrawGrid( nStartX, nEndX, aHorzBuf, nStartY, nEndY, aVertBuf, nFlags ); +#endif // REMOTE_APPSERVER +} + +// ------------------------------------------------------------------------ + +void OutputDevice::DrawTransparent( const PolyPolygon& rPolyPoly, + USHORT nTransparencePercent ) +{ + DBG_TRACE( "OutputDevice::DrawTransparent()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if( !mbFillColor || ( 0 == nTransparencePercent ) ) + DrawPolyPolygon( rPolyPoly ); + else if( 100 == nTransparencePercent ) + { + Push( PUSH_FILLCOLOR ); + SetFillColor(); + DrawPolyPolygon( rPolyPoly ); + Pop(); + } + else + { + if( mpMetaFile ) + mpMetaFile->AddAction( new MetaTransparentAction( rPolyPoly, nTransparencePercent ) ); + + if( !IsDeviceOutputNecessary() || ( !mbLineColor && !mbFillColor ) ) + return; + + GDIMetaFile* pOldMetaFile = mpMetaFile; + mpMetaFile = NULL; + + if( OUTDEV_PRINTER == meOutDevType ) + { + Rectangle aPolyRect( LogicToPixel( rPolyPoly ).GetBoundRect() ); + const Size aDPISize( LogicToPixel( Size( 1, 1 ), MAP_INCH ) ); + const long nBaseExtent = Max( FRound( aDPISize.Width() / 300. ), 1L ); + long nMove; + const USHORT nTrans = ( nTransparencePercent < 13 ) ? 0 : + ( nTransparencePercent < 38 ) ? 25 : + ( nTransparencePercent < 63 ) ? 50 : + ( nTransparencePercent < 88 ) ? 75 : 100; + + switch( nTrans ) + { + case( 25 ): nMove = nBaseExtent * 3; break; + case( 50 ): nMove = nBaseExtent * 4; break; + case( 75 ): nMove = nBaseExtent * 6; break; + } + + Push( PUSH_CLIPREGION | PUSH_LINECOLOR ); + IntersectClipRegion( rPolyPoly ); + SetLineColor( GetFillColor() ); + + Rectangle aRect( aPolyRect.TopLeft(), Size( aPolyRect.GetWidth(), nBaseExtent ) ); + + const BOOL bOldMap = mbMap; + mbMap = FALSE; + + while( aRect.Top() <= aPolyRect.Bottom() ) + { + DrawRect( aRect ); + aRect.Move( 0, nMove ); + } + + aRect = Rectangle( aPolyRect.TopLeft(), Size( nBaseExtent, aPolyRect.GetHeight() ) ); + while( aRect.Left() <= aPolyRect.Right() ) + { + DrawRect( aRect ); + aRect.Move( nMove, 0 ); + } + + mbMap = bOldMap; + Pop(); + } + else + { +#ifndef REMOTE_APPSERVER + PolyPolygon aPolyPoly( LogicToPixel( rPolyPoly ) ); + Rectangle aPolyRect( aPolyPoly.GetBoundRect() ); + Point aPoint; + Rectangle aDstRect( aPoint, GetOutputSizePixel() ); + + aDstRect.Intersection( aPolyRect ); + + if( OUTDEV_WINDOW == meOutDevType ) + { + const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() ); + + if( !aPaintRgn.IsNull() ) + aDstRect.Intersection( LogicToPixel( aPaintRgn ).GetBoundRect() ); + } + + if( !aDstRect.IsEmpty() ) + { + VirtualDevice aVDev( *this, 1 ); + const Size aDstSz( aDstRect.GetSize() ); + const BYTE cTrans = (BYTE) 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; + + mbMap = FALSE; + + aVDev.SetLineColor( COL_BLACK ); + aVDev.SetFillColor( COL_BLACK ); + aVDev.DrawPolyPolygon( aPolyPoly ); + + Bitmap aPaint( GetBitmap( aDstRect.TopLeft(), aDstSz ) ); + Bitmap aPolyMask( aVDev.GetBitmap( Point(), aDstSz ) ); + 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 USHORT nCount = rPal.GetEntryCount(); + BitmapColor* pMap = (BitmapColor*) new BYTE[ nCount * sizeof( BitmapColor ) ]; + + for( USHORT i = 0; i < nCount; i++ ) + { + BitmapColor aCol( rPal[ i ] ); + pMap[ i ] = BitmapColor( (BYTE) rPal.GetBestIndex( aCol.Merge( aFillCol, cTrans ) ) ); + } + + if( pR->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL && + pW->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) + { + const BYTE cBlack = aBlack.GetIndex(); + + for( nY = 0; nY < nHeight; nY++ ) + { + Scanline pWScan = pW->GetScanline( nY ); + Scanline pRScan = pR->GetScanline( nY ); + BYTE cBit = 128; + + for( nX = 0; nX < nWidth; nX++, cBit >>= 1, pWScan++ ) + { + if( !cBit ) + cBit = 128, pRScan++; + + if( ( *pRScan & cBit ) == cBlack ) + *pWScan = (BYTE) 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[] (BYTE*) pMap; + } + else + { + if( pR->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL && + pW->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR ) + { + const BYTE cBlack = aBlack.GetIndex(); + + for( nY = 0; nY < nHeight; nY++ ) + { + Scanline pWScan = pW->GetScanline( nY ); + Scanline pRScan = pR->GetScanline( nY ); + BYTE 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 ); + + mbMap = bOldMap; + + if( mbLineColor ) + { + Push( PUSH_FILLCOLOR ); + SetFillColor(); + DrawPolyPolygon( rPolyPoly ); + Pop(); + } + } + else + DrawPolyPolygon( rPolyPoly ); + } +#else // REMOTE_APPSERVER + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); + pGraphics->DrawTransparent( ImplLogicToDevicePixel( rPolyPoly ), nTransparencePercent ); + } +#endif // REMOTE_APPSERVER + } + + mpMetaFile = pOldMetaFile; + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos, + const Size& rSize, const Gradient& rTransparenceGradient ) +{ + DBG_TRACE( "OutputDevice::DrawTransparent()" ); + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + const Color aBlack( COL_BLACK ); + + if( mpMetaFile ) + mpMetaFile->AddAction( new MetaFloatTransparentAction( rMtf, rPos, rSize, rTransparenceGradient ) ); + + if( rTransparenceGradient.GetStartColor() == aBlack && rTransparenceGradient.GetEndColor() == aBlack ) + { + ( (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 ); + + if( OUTDEV_WINDOW == meOutDevType ) + { + const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() ); + + if( !aPaintRgn.IsNull() ) + aDstRect.Intersection( LogicToPixel( aPaintRgn.GetBoundRect() ) ); + } + + if( !aDstRect.IsEmpty() ) + { + VirtualDevice* pVDev = new VirtualDevice; + + pVDev->mnDPIX = mnDPIX; + pVDev->mnDPIY = mnDPIY; + + if( pVDev->SetOutputSizePixel( aDstRect.GetSize() ) ) + { + 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 ); + + // create paint bitmap + ( (GDIMetaFile&) rMtf ).WindStart(); + ( (GDIMetaFile&) rMtf ).Play( pVDev, rPos, rSize ); + ( (GDIMetaFile&) rMtf ).WindStart(); + pVDev->EnableMapMode( FALSE ); + aPaint = pVDev->GetBitmap( Point(), pVDev->GetOutputSizePixel() ); + pVDev->EnableMapMode( TRUE ); + + // 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, rPos, rSize ); + ( (GDIMetaFile&) rMtf ).WindStart(); + pVDev->EnableMapMode( FALSE ); + aMask = pVDev->GetBitmap( Point(), pVDev->GetOutputSizePixel() ); + pVDev->EnableMapMode( TRUE ); + + // 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 ) ); + +#ifndef REMOTE_APPSERVER + aAlpha = pVDev->GetBitmap( Point(), pVDev->GetOutputSizePixel() ); +#else + aAlpha.ImplSetBitmap( pVDev->GetBitmap( Point(), pVDev->GetOutputSizePixel() ) ); +#endif + + delete pVDev; + + mbMap = FALSE; + DrawBitmapEx( aDstRect.TopLeft(), BitmapEx( aPaint, aAlpha ) ); + mbMap = bOldMap; + } + else + delete pVDev; + } + + mpMetaFile = pOldMetaFile; + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplDrawColorWallpaper( long nX, long nY, + long nWidth, long nHeight, + const Wallpaper& rWallpaper ) +{ +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + if ( mbOutputClipped ) + return; + + // Wallpaper ohne Umrandung zeichnen + Color aOldLineColor = GetLineColor(); + Color aOldFillColor = GetFillColor(); + SetLineColor(); + SetFillColor( rWallpaper.GetColor() ); + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); + mpGraphics->DrawRect( nX+mnOutOffX, nY+mnOutOffY, nWidth, nHeight ); + SetLineColor( aOldLineColor ); + SetFillColor( aOldFillColor ); +#else + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + Color aOldLineColor = GetLineColor(); + Color aOldFillColor = GetFillColor(); + SetLineColor(); + SetFillColor( rWallpaper.GetColor() ); + if ( mbInitLineColor ) + ImplInitLineColor(); + if ( mbInitFillColor ) + ImplInitFillColor(); + pGraphics->DrawRect( Rectangle( Point( nX+mnOutOffX, nY+mnOutOffY ), Size( nWidth, nHeight ) ) ); + SetLineColor( aOldLineColor ); + SetFillColor( aOldFillColor ); + } +#endif +} + +// ----------------------------------------------------------------------- + +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( nX, nY ); + aSize = Size( nWidth, nHeight ); + } + + mpMetaFile = NULL; + mbMap = 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(); + mbMap = 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; + +/* + if ( rWallpaper.IsRect() ) + aBound = LogicToPixel( rWallpaper.GetRect() ); + else +*/ + aBound = Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ); + + mpMetaFile = NULL; + mbMap = FALSE; + Push( PUSH_CLIPREGION ); + IntersectClipRegion( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ) ); + + DrawGradient( aBound, rWallpaper.GetGradient() ); + + Pop(); + mbMap = 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() ) + 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 ); + } + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::Erase() +{ + if ( !IsDeviceOutputNecessary() ) + return; + + if ( mbBackground ) + { + RasterOp eRasterOp = GetRasterOp(); + if ( eRasterOp != ROP_OVERPAINT ) + SetRasterOp( ROP_OVERPAINT ); + ImplDrawWallpaper( 0, 0, mnOutWidth, mnOutHeight, maBackground ); + if ( eRasterOp != ROP_OVERPAINT ) + SetRasterOp( eRasterOp ); + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::ImplDraw2ColorFrame( const Rectangle& rRect, + const Color& rLeftTopColor, + const Color& rRightBottomColor ) +{ +#ifndef REMOTE_APPSERVER + SetFillColor( rLeftTopColor ); + DrawRect( Rectangle( rRect.TopLeft(), Point( rRect.Left(), rRect.Bottom()-1 ) ) ); + DrawRect( Rectangle( rRect.TopLeft(), Point( rRect.Right()-1, rRect.Top() ) ) ); + SetFillColor( rRightBottomColor ); + DrawRect( Rectangle( rRect.BottomLeft(), rRect.BottomRight() ) ); + DrawRect( Rectangle( rRect.TopRight(), rRect.BottomRight() ) ); +#else + if ( mpMetaFile ) + { + BOOL bOutputEnabled = IsOutputEnabled(); + EnableOutput( FALSE ); + SetFillColor( rLeftTopColor ); + DrawRect( Rectangle( rRect.TopLeft(), Point( rRect.Left(), rRect.Bottom()-1 ) ) ); + DrawRect( Rectangle( rRect.TopLeft(), Point( rRect.Right()-1, rRect.Top() ) ) ); + SetFillColor( rRightBottomColor ); + DrawRect( Rectangle( rRect.BottomLeft(), rRect.BottomRight() ) ); + DrawRect( Rectangle( rRect.TopRight(), rRect.BottomRight() ) ); + EnableOutput( bOutputEnabled ); + } + + if ( IsDeviceOutputNecessary() && !rRect.IsEmpty() ) + { + ImplServerGraphics* pGraphics = ImplGetServerGraphics(); + if ( pGraphics ) + { + if ( mbInitLineColor ) + ImplInitLineColor(); + Rectangle aRect( ImplLogicToDevicePixel( rRect ) ); + pGraphics->Draw2ColorFrame( aRect, rLeftTopColor, rRightBottomColor ); + } + } + SetFillColor( rRightBottomColor ); +#endif +} + +// ----------------------------------------------------------------------- + +void OutputDevice::DrawEPS( const Point& rPoint, const Size& rSize, + const GfxLink& rGfxLink, GDIMetaFile* pSubst ) +{ + if ( mpMetaFile ) + { + GDIMetaFile aSubst; + + if( pSubst ) + aSubst = *pSubst; + + mpMetaFile->AddAction( new MetaEPSAction( rPoint, rSize, rGfxLink, aSubst ) ); + } + + if ( !IsDeviceOutputNecessary() ) + return; + + Rectangle aRect( ImplLogicToDevicePixel( Rectangle( rPoint, rSize ) ) ); + BOOL bDrawn = FALSE; + + if( !aRect.IsEmpty() ) + { + aRect.Justify(); + + if( GetOutDevType() == OUTDEV_PRINTER ) + { +#ifndef REMOTE_APPSERVER + if( !mpGraphics && !ImplGetGraphics() ) + return; + + if( mbInitClipRegion ) + ImplInitClipRegion(); + + if( !mbOutputClipped ) + { + bDrawn = mpGraphics->DrawEPS( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), + (BYTE*) rGfxLink.GetData(), rGfxLink.GetDataSize() ); + } +#else + DBG_ERROR( "No direct EPS-support for remote appserver!" ); +#endif + } + + if( !bDrawn && pSubst ) + { + GDIMetaFile* pOldMetaFile = mpMetaFile; + + mpMetaFile = NULL; + Graphic( *pSubst ).Draw( this, rPoint, rSize ); + mpMetaFile = pOldMetaFile; + } + } +} diff --git a/vcl/source/gdi/outmap.cxx b/vcl/source/gdi/outmap.cxx new file mode 100644 index 000000000000..c086efb92bbc --- /dev/null +++ b/vcl/source/gdi/outmap.cxx @@ -0,0 +1,2106 @@ +/************************************************************************* + * + * $RCSfile: outmap.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <limits.h> + +#define _SV_OUTMAP_CXX + +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif + +#ifndef _BIGINT_HXX +#include <tools/bigint.hxx> +#endif +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif + +#ifndef _SV_SVDATA_HXX +#include <svdata.hxx> +#endif +#ifndef _SV_POLY_H +#include <poly.h> +#endif +#ifndef _SV_POLY_HXX +#include <poly.hxx> +#endif +#ifndef _SV_REGION_HXX +#include <region.hxx> +#endif +#ifndef _SV_REGION_H +#include <region.h> +#endif +#ifndef _SV_WINDOW_H +#include <window.h> +#endif +#ifndef _SV_WRKWIN_HXX +#include <wrkwin.hxx> +#endif +#ifndef _SV_CURSOR_HXX +#include <cursor.hxx> +#endif +#ifndef _SV_METAACT_HXX +#include <metaact.hxx> +#endif +#ifndef _SV_GDIMTF_HXX +#include <gdimtf.hxx> +#endif +#ifndef _SV_LINEINFO_HXX +#include <lineinfo.hxx> +#endif +#ifndef _SV_OUTDEV_HXX +#include <outdev.hxx> +#endif + +// ======================================================================= + +DBG_NAMEEX( OutputDevice ); +DBG_NAMEEX( Polygon ); +DBG_NAMEEX( PolyPolygon ); +DBG_NAMEEX( Region ); + +// ======================================================================= + +static long aImplNumeratorAry[MAP_PIXEL+1] = + { 1, 1, 5, 50, 1, 1, 1, 1, 1, 1, 1 }; +static long aImplDenominatorAry[MAP_PIXEL+1] = + { 2540, 254, 127, 127, 1000, 100, 10, 1, 72, 1440, 1 }; + +// ----------------------------------------------------------------------- + +/* +Reduziert die Genauigkeit bis eine Fraction draus wird (sollte mal +ein Fraction ctor werden) koennte man dann auch mit BigInts machen +*/ + +static Fraction ImplMakeFraction( long nN1, long nN2, long nD1, long nD2 ) +{ + long i = 1; + + if ( nN1 < 0 ) { i = -i; nN1 = -nN1; } + if ( nN2 < 0 ) { i = -i; nN2 = -nN2; } + if ( nD1 < 0 ) { i = -i; nD1 = -nD1; } + if ( nD2 < 0 ) { i = -i; nD2 = -nD2; } + // alle positiv; i Vorzeichen + + Fraction aF( i*nN1, nD1 ); + aF *= Fraction( nN2, nD2 ); + + while ( aF.GetDenominator() == -1 ) + { + if ( nN1 > nN2 ) + nN1 = (nN1 + 1) / 2; + else + nN2 = (nN2 + 1) / 2; + if ( nD1 > nD2 ) + nD1 = (nD1 + 1) / 2; + else + nD2 = (nD2 + 1) / 2; + + aF = Fraction( i*nN1, nD1 ); + aF *= Fraction( nN2, nD2 ); + } + + return aF; +} + +// ----------------------------------------------------------------------- + +// Fraction.GetNumerator() +// Fraction.GetDenominator() > 0 +// rOutRes.nPixPerInch? > 0 +// rMapRes.nMapScNum? +// rMapRes.nMapScDenom? > 0 + +static void ImplCalcBigIntThreshold( long nDPIX, long nDPIY, + const ImplMapRes& rMapRes, + ImplThresholdRes& rThresRes ) +{ + if ( LONG_MAX / nDPIX < Abs( rMapRes.mnMapScNumX ) ) + { + rThresRes.mnThresLogToPixX = 0; + rThresRes.mnThresPixToLogX = 0; + } + else + { + // Schwellenwerte fuer BigInt Arithmetik berechnen + long nDenomHalfX = rMapRes.mnMapScDenomX / 2; + ULONG nDenomX = rMapRes.mnMapScDenomX; + long nProductX = nDPIX * rMapRes.mnMapScNumX; + + if ( !nProductX ) + rThresRes.mnThresLogToPixX = LONG_MAX; + else + rThresRes.mnThresLogToPixX = Abs( (LONG_MAX - nDenomHalfX) / nProductX ); + + if ( !nDenomX ) + rThresRes.mnThresPixToLogX = LONG_MAX; + else if ( nProductX >= 0 ) + rThresRes.mnThresPixToLogX = (long)(((ULONG)LONG_MAX - (ULONG)( nProductX/2)) / nDenomX); + else + rThresRes.mnThresPixToLogX = (long)(((ULONG)LONG_MAX + (ULONG)(-nProductX/2)) / nDenomX); + } + + if ( LONG_MAX / nDPIY < Abs( rMapRes.mnMapScNumY ) ) + { + rThresRes.mnThresLogToPixY = 0; + rThresRes.mnThresPixToLogY = 0; + } + else + { + // Schwellenwerte fuer BigInt Arithmetik berechnen + long nDenomHalfY = rMapRes.mnMapScDenomY / 2; + ULONG nDenomY = rMapRes.mnMapScDenomY; + long nProductY = nDPIY * rMapRes.mnMapScNumY; + + if ( !nProductY ) + rThresRes.mnThresLogToPixY = LONG_MAX; + else + rThresRes.mnThresLogToPixY = Abs( (LONG_MAX - nDenomHalfY) / nProductY ); + + if ( !nDenomY ) + rThresRes.mnThresPixToLogY = LONG_MAX; + else if ( nProductY >= 0 ) + rThresRes.mnThresPixToLogY = (long)(((ULONG)LONG_MAX - (ULONG)( nProductY/2)) / nDenomY); + else + rThresRes.mnThresPixToLogY = (long)(((ULONG)LONG_MAX + (ULONG)(-nProductY/2)) / nDenomY); + } +} + +// ----------------------------------------------------------------------- + +static void ImplCalcMapResolution( const MapMode& rMapMode, + long nDPIX, long nDPIY, ImplMapRes& rMapRes ) +{ + switch ( rMapMode.GetMapUnit() ) + { + case MAP_RELATIVE: + break; + case MAP_100TH_MM: + rMapRes.mnMapScNumX = 1; + rMapRes.mnMapScDenomX = 2540; + rMapRes.mnMapScNumY = 1; + rMapRes.mnMapScDenomY = 2540; + break; + case MAP_10TH_MM: + rMapRes.mnMapScNumX = 1; + rMapRes.mnMapScDenomX = 254; + rMapRes.mnMapScNumY = 1; + rMapRes.mnMapScDenomY = 254; + break; + case MAP_MM: + rMapRes.mnMapScNumX = 5; // 10 + rMapRes.mnMapScDenomX = 127; // 254 + rMapRes.mnMapScNumY = 5; // 10 + rMapRes.mnMapScDenomY = 127; // 254 + break; + case MAP_CM: + rMapRes.mnMapScNumX = 50; // 100 + rMapRes.mnMapScDenomX = 127; // 254 + rMapRes.mnMapScNumY = 50; // 100 + rMapRes.mnMapScDenomY = 127; // 254 + break; + case MAP_1000TH_INCH: + rMapRes.mnMapScNumX = 1; + rMapRes.mnMapScDenomX = 1000; + rMapRes.mnMapScNumY = 1; + rMapRes.mnMapScDenomY = 1000; + break; + case MAP_100TH_INCH: + rMapRes.mnMapScNumX = 1; + rMapRes.mnMapScDenomX = 100; + rMapRes.mnMapScNumY = 1; + rMapRes.mnMapScDenomY = 100; + break; + case MAP_10TH_INCH: + rMapRes.mnMapScNumX = 1; + rMapRes.mnMapScDenomX = 10; + rMapRes.mnMapScNumY = 1; + rMapRes.mnMapScDenomY = 10; + break; + case MAP_INCH: + rMapRes.mnMapScNumX = 1; + rMapRes.mnMapScDenomX = 1; + rMapRes.mnMapScNumY = 1; + rMapRes.mnMapScDenomY = 1; + break; + case MAP_POINT: + rMapRes.mnMapScNumX = 1; + rMapRes.mnMapScDenomX = 72; + rMapRes.mnMapScNumY = 1; + rMapRes.mnMapScDenomY = 72; + break; + case MAP_TWIP: + rMapRes.mnMapScNumX = 1; + rMapRes.mnMapScDenomX = 1440; + rMapRes.mnMapScNumY = 1; + rMapRes.mnMapScDenomY = 1440; + break; + case MAP_PIXEL: + rMapRes.mnMapScNumX = 1; + rMapRes.mnMapScDenomX = nDPIX; + rMapRes.mnMapScNumY = 1; + rMapRes.mnMapScDenomY = nDPIY; + break; + case MAP_SYSFONT: + case MAP_APPFONT: + case MAP_REALAPPFONT: + { + ImplSVData* pSVData = ImplGetSVData(); + if ( !pSVData->maGDIData.mnAppFontX ) + { + WorkWindow* pWin = new WorkWindow( NULL, 0 ); + delete pWin; + } + if ( rMapMode.GetMapUnit() == MAP_REALAPPFONT ) + rMapRes.mnMapScNumX = pSVData->maGDIData.mnRealAppFontX; + else + rMapRes.mnMapScNumX = pSVData->maGDIData.mnAppFontX; + rMapRes.mnMapScDenomX = nDPIX * 40; + rMapRes.mnMapScNumY = pSVData->maGDIData.mnAppFontY;; + rMapRes.mnMapScDenomY = nDPIY * 80; + } + break; + } + + Fraction aScaleX = rMapMode.GetScaleX(); + Fraction aScaleY = rMapMode.GetScaleY(); + + // Offset laut MapMode setzen + Point aOrigin = rMapMode.GetOrigin(); + if ( rMapMode.GetMapUnit() != MAP_RELATIVE ) + { + rMapRes.mnMapOfsX = aOrigin.X(); + rMapRes.mnMapOfsY = aOrigin.Y(); + } + else + { + BigInt aX( rMapRes.mnMapOfsX ); + aX *= BigInt( aScaleX.GetDenominator() ); + if ( rMapRes.mnMapOfsX >= 0 ) + { + if ( aScaleX.GetNumerator() >= 0 ) + aX += BigInt( aScaleX.GetNumerator()/2 ); + else + aX -= BigInt( (aScaleX.GetNumerator()+1)/2 ); + } + else + { + if ( aScaleX.GetNumerator() >= 0 ) + aX -= BigInt( (aScaleX.GetNumerator()-1)/2 ); + else + aX += BigInt( aScaleX.GetNumerator()/2 ); + } + aX /= BigInt( aScaleX.GetNumerator() ); + rMapRes.mnMapOfsX = (long)aX + aOrigin.X(); + BigInt aY( rMapRes.mnMapOfsY ); + aY *= BigInt( aScaleY.GetDenominator() ); + if( rMapRes.mnMapOfsY >= 0 ) + { + if ( aScaleY.GetNumerator() >= 0 ) + aY += BigInt( aScaleY.GetNumerator()/2 ); + else + aY -= BigInt( (aScaleY.GetNumerator()+1)/2 ); + } + else + { + if ( aScaleY.GetNumerator() >= 0 ) + aY -= BigInt( (aScaleY.GetNumerator()-1)/2 ); + else + aY += BigInt( aScaleY.GetNumerator()/2 ); + } + aY /= BigInt( aScaleY.GetNumerator() ); + rMapRes.mnMapOfsY = (long)aY + aOrigin.Y(); + } + + // Scaling Faktor laut MapMode einberechnen + // aTemp? = rMapRes.mnMapSc? * aScale? + Fraction aTempX = ImplMakeFraction( rMapRes.mnMapScNumX, + aScaleX.GetNumerator(), + rMapRes.mnMapScDenomX, + aScaleX.GetDenominator() ); + Fraction aTempY = ImplMakeFraction( rMapRes.mnMapScNumY, + aScaleY.GetNumerator(), + rMapRes.mnMapScDenomY, + aScaleY.GetDenominator() ); + rMapRes.mnMapScNumX = aTempX.GetNumerator(); + rMapRes.mnMapScDenomX = aTempX.GetDenominator(); + rMapRes.mnMapScNumY = aTempY.GetNumerator(); + rMapRes.mnMapScDenomY = aTempY.GetDenominator(); + + // hack: 0/n ungef"ahr 1/max + if ( !rMapRes.mnMapScNumX ) + { + rMapRes.mnMapScNumX = 1; + rMapRes.mnMapScDenomX = LONG_MAX; + } + if ( !rMapRes.mnMapScNumY ) + { + rMapRes.mnMapScNumY = 1; + rMapRes.mnMapScDenomY = LONG_MAX; + } +} + +// ----------------------------------------------------------------------- + +inline void ImplCalcMapResolution( const MapMode& rMapMode, + long nDPIX, long nDPIY, + ImplMapRes& rMapRes, + ImplThresholdRes& rThresRes ) +{ + ImplCalcMapResolution( rMapMode, nDPIX, nDPIY, rMapRes ); + ImplCalcBigIntThreshold( nDPIX, nDPIY, rMapRes, rThresRes ); +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetMapMode() +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( mpMetaFile ) + mpMetaFile->AddAction( new MetaMapModeAction( MapMode() ) ); + + if ( mbMap || !maMapMode.IsDefault() ) + { + mbMap = FALSE; + maMapMode = MapMode(); + + // create new objects (clip region werden nicht neu skaliert) + mbNewFont = TRUE; + mbInitFont = TRUE; + if ( GetOutDevType() == OUTDEV_WINDOW ) + { + if ( ((Window*)this)->mpCursor ) + ((Window*)this)->mpCursor->ImplNew(); + } + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetMapMode( const MapMode& rNewMapMode ) +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + BOOL bRelMap = (rNewMapMode.GetMapUnit() == MAP_RELATIVE); + + if ( mpMetaFile ) + { + mpMetaFile->AddAction( new MetaMapModeAction( rNewMapMode ) ); +#ifdef DBG_UTIL + if ( GetOutDevType() != OUTDEV_PRINTER ) + DBG_ASSERTWARNING( bRelMap, "Please record only relative MapModes!" ); +#endif + } + + // Ist der MapMode der gleiche wie vorher, dann mache nichts + if ( maMapMode == rNewMapMode ) + return; + + // Ist Default-MapMode, dann bereche nichts + BOOL bOldMap = mbMap; + mbMap = !rNewMapMode.IsDefault(); + if ( mbMap ) + { + // Falls nur der Orign umgesetzt wird, dann scaliere nichts neu + if ( (rNewMapMode.GetMapUnit() == maMapMode.GetMapUnit()) && + (rNewMapMode.GetScaleX() == maMapMode.GetScaleX()) && + (rNewMapMode.GetScaleY() == maMapMode.GetScaleY()) && + (bOldMap == mbMap) ) + { + // Offset setzen + Point aOrigin = rNewMapMode.GetOrigin(); + maMapRes.mnMapOfsX = aOrigin.X(); + maMapRes.mnMapOfsY = aOrigin.Y(); + maMapMode = rNewMapMode; + return; + } + if ( !bOldMap && bRelMap ) + { + maMapRes.mnMapScNumX = 1; + maMapRes.mnMapScNumY = 1; + maMapRes.mnMapScDenomX = mnDPIX; + maMapRes.mnMapScDenomY = mnDPIY; + maMapRes.mnMapOfsX = 0; + maMapRes.mnMapOfsY = 0; + } + + // Neue MapMode-Aufloesung berechnen + ImplCalcMapResolution( rNewMapMode, mnDPIX, mnDPIY, maMapRes, maThresRes ); + } + + // Neuen MapMode setzen + if ( bRelMap ) + { + Point aOrigin( maMapRes.mnMapOfsX, maMapRes.mnMapOfsY ); + // aScale? = maMapMode.GetScale?() * rNewMapMode.GetScale?() + Fraction aScaleX = ImplMakeFraction( maMapMode.GetScaleX().GetNumerator(), + rNewMapMode.GetScaleX().GetNumerator(), + maMapMode.GetScaleX().GetDenominator(), + rNewMapMode.GetScaleX().GetDenominator() ); + Fraction aScaleY = ImplMakeFraction( maMapMode.GetScaleY().GetNumerator(), + rNewMapMode.GetScaleY().GetNumerator(), + maMapMode.GetScaleY().GetDenominator(), + rNewMapMode.GetScaleY().GetDenominator() ); + maMapMode.SetOrigin( aOrigin ); + maMapMode.SetScaleX( aScaleX ); + maMapMode.SetScaleY( aScaleY ); + } + else + maMapMode = rNewMapMode; + + // create new objects (clip region werden nicht neu skaliert) + mbNewFont = TRUE; + mbInitFont = TRUE; + if ( GetOutDevType() == OUTDEV_WINDOW ) + { + if ( ((Window*)this)->mpCursor ) + ((Window*)this)->mpCursor->ImplNew(); + } +} + +// ----------------------------------------------------------------------- + +void OutputDevice::SetRelativeMapMode( const MapMode& rNewMapMode ) +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + // Ist der MapMode der gleiche wie vorher, dann mache nichts + if ( maMapMode == rNewMapMode ) + return; + + MapUnit eOld = maMapMode.GetMapUnit(); + MapUnit eNew = rNewMapMode.GetMapUnit(); + + // a?F = rNewMapMode.GetScale?() / maMapMode.GetScale?() + Fraction aXF = ImplMakeFraction( rNewMapMode.GetScaleX().GetNumerator(), + maMapMode.GetScaleX().GetDenominator(), + rNewMapMode.GetScaleX().GetDenominator(), + maMapMode.GetScaleX().GetNumerator() ); + Fraction aYF = ImplMakeFraction( rNewMapMode.GetScaleY().GetNumerator(), + maMapMode.GetScaleY().GetDenominator(), + rNewMapMode.GetScaleY().GetDenominator(), + maMapMode.GetScaleY().GetNumerator() ); + + Point aPt( LogicToLogic( Point(), NULL, &rNewMapMode ) ); + if ( eNew != eOld ) + { + if ( eOld > MAP_PIXEL ) + { + DBG_ERRORFILE( "Not implemented MapUnit" ) + } + else if ( eNew > MAP_PIXEL ) + { + DBG_ERRORFILE( "Not implemented MapUnit" ) + } + else + { + Fraction aF( aImplNumeratorAry[eNew] * aImplDenominatorAry[eOld], + aImplNumeratorAry[eOld] * aImplDenominatorAry[eNew] ); + + // a?F = a?F * aF + aXF = ImplMakeFraction( aXF.GetNumerator(), aF.GetNumerator(), + aXF.GetDenominator(), aF.GetDenominator() ); + aYF = ImplMakeFraction( aYF.GetNumerator(), aF.GetNumerator(), + aYF.GetDenominator(), aF.GetDenominator() ); + if ( eOld == MAP_PIXEL ) + { + aXF *= Fraction( mnDPIX, 1 ); + aYF *= Fraction( mnDPIY, 1 ); + } + else if ( eNew == MAP_PIXEL ) + { + aXF *= Fraction( 1, mnDPIX ); + aYF *= Fraction( 1, mnDPIY ); + } + } + } + + MapMode aNewMapMode( MAP_RELATIVE, Point( -aPt.X(), -aPt.Y() ), aXF, aYF ); + SetMapMode( aNewMapMode ); + + if ( eNew != eOld ) + maMapMode = rNewMapMode; +} + +// ----------------------------------------------------------------------- + +static long ImplLogicToPixel( long n, long nDPI, long nMapNum, long nMapDenom, + long nThres ) +{ + if ( Abs( n ) < nThres ) + { + n *= nDPI * nMapNum; + n += n >= 0 ? nMapDenom/2 : -((nMapDenom-1)/2); + return (n / nMapDenom); + } + else + { + BigInt aTemp( n ); + aTemp *= BigInt( nDPI ); + aTemp *= BigInt( nMapNum ); + + if ( aTemp.IsNeg() ) + { + BigInt aMapScDenom2( (nMapDenom-1)/2 ); + aTemp -= aMapScDenom2; + } + else + { + BigInt aMapScDenom2( nMapDenom/2 ); + aTemp += aMapScDenom2; + } + + aTemp /= BigInt( nMapDenom ); + return (long)aTemp; + } +} + +// ----------------------------------------------------------------------- + +static long ImplPixelToLogic( long n, long nDPI, long nMapNum, long nMapDenom, + long nThres ) +{ + if ( Abs( n ) < nThres ) + { + long nDenom = nDPI * nMapNum; + long nNum = n * nMapDenom; + if ( nNum >= 0 ) + { + if ( nDenom >= 0 ) + nNum += nDenom/2; + else + nNum -= (nDenom+1)/2; + } + else + { + if ( nDenom >= 0 ) + nNum -= (nDenom-1)/2; + else + nNum += nDenom/2; + } + return (nNum / nDenom); + } + else + { + BigInt aDenom( nDPI ); + aDenom *= BigInt( nMapNum ); + + BigInt aNum( n ); + aNum *= BigInt( nMapDenom ); + + BigInt aDenom2( aDenom ); + if ( aNum.IsNeg() ) + { + if ( aDenom.IsNeg() ) + { + aDenom2 /= BigInt(2); + aNum += aDenom2; + } + else + { + aDenom2 -= 1; + aDenom2 /= BigInt(2); + aNum -= aDenom2; + } + } + else + { + if ( aDenom.IsNeg() ) + { + aDenom2 += 1; + aDenom2 /= BigInt(2); + aNum -= aDenom2; + } + else + { + aDenom2 /= BigInt(2); + aNum += aDenom2; + } + } + + aNum /= aDenom; + return (long)aNum; + } +} + +// ----------------------------------------------------------------------- + +long OutputDevice::ImplLogicXToDevicePixel( long nX ) const +{ + if ( !mbMap ) + return nX+mnOutOffX; + + return ImplLogicToPixel( nX + maMapRes.mnMapOfsX, mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresLogToPixX )+mnOutOffX; +} + +// ----------------------------------------------------------------------- + +long OutputDevice::ImplLogicYToDevicePixel( long nY ) const +{ + if ( !mbMap ) + return nY+mnOutOffY; + + return ImplLogicToPixel( nY + maMapRes.mnMapOfsY, mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresLogToPixY )+mnOutOffY; +} + +// ----------------------------------------------------------------------- + +long OutputDevice::ImplLogicWidthToDevicePixel( long nWidth ) const +{ + if ( !mbMap ) + return nWidth; + + return ImplLogicToPixel( nWidth, mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresLogToPixX ); +} + +// ----------------------------------------------------------------------- + +long OutputDevice::ImplLogicHeightToDevicePixel( long nHeight ) const +{ + if ( !mbMap ) + return nHeight; + + return ImplLogicToPixel( nHeight, mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresLogToPixY ); +} + +// ----------------------------------------------------------------------- + +long OutputDevice::ImplDevicePixelToLogicWidth( long nWidth ) const +{ + if ( !mbMap ) + return nWidth; + + return ImplPixelToLogic( nWidth, mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresPixToLogX ); +} + +// ----------------------------------------------------------------------- + +long OutputDevice::ImplDevicePixelToLogicHeight( long nHeight ) const +{ + if ( !mbMap ) + return nHeight; + + return ImplPixelToLogic( nHeight, mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresPixToLogY ); +} + +// ----------------------------------------------------------------------- + +Point OutputDevice::ImplLogicToDevicePixel( const Point& rLogicPt ) const +{ + if ( !mbMap ) + return Point( rLogicPt.X()+mnOutOffX, rLogicPt.Y()+mnOutOffY ); + + return Point( ImplLogicToPixel( rLogicPt.X() + maMapRes.mnMapOfsX, mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresLogToPixX )+mnOutOffX, + ImplLogicToPixel( rLogicPt.Y() + maMapRes.mnMapOfsY, mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresLogToPixY )+mnOutOffY ); +} + +// ----------------------------------------------------------------------- + +Size OutputDevice::ImplLogicToDevicePixel( const Size& rLogicSize ) const +{ + if ( !mbMap ) + return rLogicSize; + + return Size( ImplLogicToPixel( rLogicSize.Width(), mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresLogToPixX ), + ImplLogicToPixel( rLogicSize.Height(), mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresLogToPixY ) ); +} + +// ----------------------------------------------------------------------- + +Rectangle OutputDevice::ImplLogicToDevicePixel( const Rectangle& rLogicRect ) const +{ + if ( rLogicRect.IsEmpty() ) + return rLogicRect; + + if ( !mbMap ) + { + return Rectangle( rLogicRect.Left()+mnOutOffX, rLogicRect.Top()+mnOutOffY, + rLogicRect.Right()+mnOutOffX, rLogicRect.Bottom()+mnOutOffY ); + } + + return Rectangle( ImplLogicToPixel( rLogicRect.Left()+maMapRes.mnMapOfsX, mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresLogToPixX )+mnOutOffX, + ImplLogicToPixel( rLogicRect.Top()+maMapRes.mnMapOfsY, mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresLogToPixY )+mnOutOffY, + ImplLogicToPixel( rLogicRect.Right()+maMapRes.mnMapOfsX, mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresLogToPixX )+mnOutOffX, + ImplLogicToPixel( rLogicRect.Bottom()+maMapRes.mnMapOfsY, mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresLogToPixY )+mnOutOffY ); +} + +// ----------------------------------------------------------------------- + +Polygon OutputDevice::ImplLogicToDevicePixel( const Polygon& rLogicPoly ) const +{ + if ( !mbMap && !mnOutOffX && !mnOutOffY ) + return rLogicPoly; + + USHORT i; + USHORT nPoints = rLogicPoly.GetSize(); + Polygon aPoly( rLogicPoly ); + + // Pointer auf das Point-Array holen (Daten werden kopiert) +#ifdef WIN + Point huge* pPointAry = (Point huge*)aPoly.ImplGetPointAry(); +#else + Point* pPointAry = aPoly.ImplGetPointAry(); +#endif + + if ( mbMap ) + { + for ( i = 0; i < nPoints; i++ ) + { + Point* pPt = &(pPointAry[i]); + pPt->X() = ImplLogicToPixel( pPt->X()+maMapRes.mnMapOfsX, mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresLogToPixX )+mnOutOffX; + pPt->Y() = ImplLogicToPixel( pPt->Y()+maMapRes.mnMapOfsY, mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresLogToPixY )+mnOutOffY; + } + } + else + { + for ( i = 0; i < nPoints; i++ ) + { + Point* pPt = &(pPointAry[i]); + pPt->X() += mnOutOffX; + pPt->Y() += mnOutOffY; + } + } + + return aPoly; +} + +// ----------------------------------------------------------------------- + +PolyPolygon OutputDevice::ImplLogicToDevicePixel( const PolyPolygon& rLogicPolyPoly ) const +{ + if ( !mbMap && !mnOutOffX && !mnOutOffY ) + return rLogicPolyPoly; + + PolyPolygon aPolyPoly( rLogicPolyPoly ); + USHORT nPoly = aPolyPoly.Count(); + for( USHORT i = 0; i < nPoly; i++ ) + { + Polygon& rPoly = aPolyPoly[i]; + rPoly = ImplLogicToDevicePixel( rPoly ); + } + return aPolyPoly; +} + +// ----------------------------------------------------------------------- + +LineInfo OutputDevice::ImplLogicToDevicePixel( const LineInfo& rLineInfo ) const +{ + LineInfo aInfo( rLineInfo ); + + if( aInfo.GetStyle() == LINE_DASH ) + { + if( aInfo.GetDotCount() && aInfo.GetDotLen() ) + aInfo.SetDotLen( Max( ImplLogicWidthToDevicePixel( aInfo.GetDotLen() ), 1L ) ); + else + aInfo.SetDotCount( 0 ); + + if( aInfo.GetDashCount() && aInfo.GetDashLen() ) + aInfo.SetDashLen( Max( ImplLogicWidthToDevicePixel( aInfo.GetDashLen() ), 1L ) ); + else + aInfo.SetDashCount( 0 ); + + aInfo.SetDistance( ImplLogicWidthToDevicePixel( aInfo.GetDistance() ) ); + + if( ( !aInfo.GetDashCount() && !aInfo.GetDotCount() ) || !aInfo.GetDistance() ) + aInfo.SetStyle( LINE_SOLID ); + } + + aInfo.SetWidth( ImplLogicWidthToDevicePixel( aInfo.GetWidth() ) ); + + return aInfo; +} + +// ----------------------------------------------------------------------- + +Rectangle OutputDevice::ImplDevicePixelToLogic( const Rectangle& rPixelRect ) const +{ + if ( rPixelRect.IsEmpty() ) + return rPixelRect; + + if ( !mbMap ) + { + return Rectangle( rPixelRect.Left()-mnOutOffX, rPixelRect.Top()-mnOutOffY, + rPixelRect.Right()-mnOutOffX, rPixelRect.Bottom()-mnOutOffY ); + } + + return Rectangle( ImplPixelToLogic( rPixelRect.Left()-mnOutOffX, mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresPixToLogX )-maMapRes.mnMapOfsX, + ImplPixelToLogic( rPixelRect.Top()-mnOutOffY, mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresPixToLogY )-maMapRes.mnMapOfsY, + ImplPixelToLogic( rPixelRect.Right()-mnOutOffX, mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresPixToLogX )-maMapRes.mnMapOfsX, + ImplPixelToLogic( rPixelRect.Bottom()-mnOutOffY, mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresPixToLogY )-maMapRes.mnMapOfsY ); +} + +// ----------------------------------------------------------------------- + +Region OutputDevice::ImplPixelToDevicePixel( const Region& rRegion ) const +{ + DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); + + if ( !mnOutOffX && !mnOutOffY ) + return rRegion; + + Region aRegion( rRegion ); + aRegion.Move( mnOutOffX, mnOutOffY ); + return aRegion; +} + +// ----------------------------------------------------------------------- + +Point OutputDevice::LogicToPixel( const Point& rLogicPt ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( !mbMap ) + return rLogicPt; + + return Point( ImplLogicToPixel( rLogicPt.X() + maMapRes.mnMapOfsX, mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresLogToPixX ), + ImplLogicToPixel( rLogicPt.Y() + maMapRes.mnMapOfsY, mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresLogToPixY ) ); +} + +// ----------------------------------------------------------------------- + +Size OutputDevice::LogicToPixel( const Size& rLogicSize ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( !mbMap ) + return rLogicSize; + + return Size( ImplLogicToPixel( rLogicSize.Width(), mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresLogToPixX ), + ImplLogicToPixel( rLogicSize.Height(), mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresLogToPixY ) ); +} + +// ----------------------------------------------------------------------- + +Rectangle OutputDevice::LogicToPixel( const Rectangle& rLogicRect ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( !mbMap || rLogicRect.IsEmpty() ) + return rLogicRect; + + return Rectangle( ImplLogicToPixel( rLogicRect.Left() + maMapRes.mnMapOfsX, mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresLogToPixX ), + ImplLogicToPixel( rLogicRect.Top() + maMapRes.mnMapOfsY, mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresLogToPixY ), + ImplLogicToPixel( rLogicRect.Right() + maMapRes.mnMapOfsX, mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresLogToPixX ), + ImplLogicToPixel( rLogicRect.Bottom() + maMapRes.mnMapOfsY, mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresLogToPixY ) ); +} + +// ----------------------------------------------------------------------- + +Polygon OutputDevice::LogicToPixel( const Polygon& rLogicPoly ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rLogicPoly, Polygon, NULL ); + + if ( !mbMap ) + return rLogicPoly; + + USHORT i; + USHORT nPoints = rLogicPoly.GetSize(); + Polygon aPoly( rLogicPoly ); + + // Pointer auf das Point-Array holen (Daten werden kopiert) +#ifdef WIN + Point huge* pPointAry = (Point huge*)aPoly.ImplGetPointAry(); +#else + Point* pPointAry = aPoly.ImplGetPointAry(); +#endif + + for ( i = 0; i < nPoints; i++ ) + { + Point* pPt = &(pPointAry[i]); + pPt->X() = ImplLogicToPixel( pPt->X() + maMapRes.mnMapOfsX, mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresLogToPixX ); + pPt->Y() = ImplLogicToPixel( pPt->Y() + maMapRes.mnMapOfsY, mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresLogToPixY ); + } + + return aPoly; +} + +// ----------------------------------------------------------------------- + +PolyPolygon OutputDevice::LogicToPixel( const PolyPolygon& rLogicPolyPoly ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rLogicPolyPoly, PolyPolygon, NULL ); + + if ( !mbMap ) + return rLogicPolyPoly; + + PolyPolygon aPolyPoly( rLogicPolyPoly ); + USHORT nPoly = aPolyPoly.Count(); + for( USHORT i = 0; i < nPoly; i++ ) + { + Polygon& rPoly = aPolyPoly[i]; + rPoly = LogicToPixel( rPoly ); + } + return aPolyPoly; +} + +// ----------------------------------------------------------------------- + +Region OutputDevice::LogicToPixel( const Region& rLogicRegion ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rLogicRegion, Region, ImplDbgTestRegion ); + + RegionType eType = rLogicRegion.GetType(); + + if ( !mbMap || (eType == REGION_EMPTY) || (eType == REGION_NULL) ) + return rLogicRegion; + + Region aRegion; + PolyPolygon* pPolyPoly = rLogicRegion.ImplGetImplRegion()->mpPolyPoly; + + if ( pPolyPoly ) + aRegion = Region( LogicToPixel( *pPolyPoly ) ); + else + { + long nX; + long nY; + long nWidth; + long nHeight; + ImplRegionInfo aInfo; + BOOL bRegionRect; + + aRegion.ImplBeginAddRect(); + bRegionRect = rLogicRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); + while ( bRegionRect ) + { + Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) ); + aRegion.ImplAddRect( LogicToPixel( aRect ) ); + bRegionRect = rLogicRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + } + aRegion.ImplEndAddRect(); + } + + return aRegion; +} + +// ----------------------------------------------------------------------- + +Point OutputDevice::LogicToPixel( const Point& rLogicPt, + const MapMode& rMapMode ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( rMapMode.IsDefault() ) + return rLogicPt; + + // MapMode-Aufloesung berechnen und Umrechnen + ImplMapRes aMapRes; + ImplThresholdRes aThresRes; + ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes ); + + return Point( ImplLogicToPixel( rLogicPt.X() + aMapRes.mnMapOfsX, mnDPIX, + aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX, + aThresRes.mnThresLogToPixX ), + ImplLogicToPixel( rLogicPt.Y() + aMapRes.mnMapOfsY, mnDPIY, + aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY, + aThresRes.mnThresLogToPixY ) ); +} + +// ----------------------------------------------------------------------- + +Size OutputDevice::LogicToPixel( const Size& rLogicSize, + const MapMode& rMapMode ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( rMapMode.IsDefault() ) + return rLogicSize; + + // MapMode-Aufloesung berechnen und Umrechnen + ImplMapRes aMapRes; + ImplThresholdRes aThresRes; + ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes ); + + return Size( ImplLogicToPixel( rLogicSize.Width(), mnDPIX, + aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX, + aThresRes.mnThresLogToPixX ), + ImplLogicToPixel( rLogicSize.Height(), mnDPIY, + aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY, + aThresRes.mnThresLogToPixY ) ); +} + +// ----------------------------------------------------------------------- + +Rectangle OutputDevice::LogicToPixel( const Rectangle& rLogicRect, + const MapMode& rMapMode ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( rMapMode.IsDefault() || rLogicRect.IsEmpty() ) + return rLogicRect; + + // MapMode-Aufloesung berechnen und Umrechnen + ImplMapRes aMapRes; + ImplThresholdRes aThresRes; + ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes ); + + return Rectangle( ImplLogicToPixel( rLogicRect.Left() + aMapRes.mnMapOfsX, mnDPIX, + aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX, + aThresRes.mnThresLogToPixX ), + ImplLogicToPixel( rLogicRect.Top() + aMapRes.mnMapOfsY, mnDPIY, + aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY, + aThresRes.mnThresLogToPixY ), + ImplLogicToPixel( rLogicRect.Right() + aMapRes.mnMapOfsX, mnDPIX, + aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX, + aThresRes.mnThresLogToPixX ), + ImplLogicToPixel( rLogicRect.Bottom() + aMapRes.mnMapOfsY, mnDPIY, + aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY, + aThresRes.mnThresLogToPixY ) ); +} + +// ----------------------------------------------------------------------- + +Polygon OutputDevice::LogicToPixel( const Polygon& rLogicPoly, + const MapMode& rMapMode ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rLogicPoly, Polygon, NULL ); + + if ( rMapMode.IsDefault() ) + return rLogicPoly; + + // MapMode-Aufloesung berechnen und Umrechnen + ImplMapRes aMapRes; + ImplThresholdRes aThresRes; + ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes ); + + USHORT i; + USHORT nPoints = rLogicPoly.GetSize(); + Polygon aPoly( rLogicPoly ); + + // Pointer auf das Point-Array holen (Daten werden kopiert) +#ifdef WIN + Point huge* pPointAry = (Point huge*)aPoly.ImplGetPointAry(); +#else + Point* pPointAry = aPoly.ImplGetPointAry(); +#endif + + for ( i = 0; i < nPoints; i++ ) + { + Point* pPt = &(pPointAry[i]); + pPt->X() = ImplLogicToPixel( pPt->X() + aMapRes.mnMapOfsX, mnDPIX, + aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX, + aThresRes.mnThresLogToPixX ); + pPt->Y() = ImplLogicToPixel( pPt->Y() + aMapRes.mnMapOfsY, mnDPIY, + aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY, + aThresRes.mnThresLogToPixY ); + } + + return aPoly; +} + +// ----------------------------------------------------------------------- + +PolyPolygon OutputDevice::LogicToPixel( const PolyPolygon& rLogicPolyPoly, + const MapMode& rMapMode ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rLogicPolyPoly, PolyPolygon, NULL ); + + if ( rMapMode.IsDefault() ) + return rLogicPolyPoly; + + PolyPolygon aPolyPoly( rLogicPolyPoly ); + USHORT nPoly = aPolyPoly.Count(); + for( USHORT i = 0; i < nPoly; i++ ) + { + Polygon& rPoly = aPolyPoly[i]; + rPoly = LogicToPixel( rPoly, rMapMode ); + } + return aPolyPoly; +} + +// ----------------------------------------------------------------------- + +Region OutputDevice::LogicToPixel( const Region& rLogicRegion, + const MapMode& rMapMode ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rLogicRegion, Region, ImplDbgTestRegion ); + + RegionType eType = rLogicRegion.GetType(); + + if ( rMapMode.IsDefault() || (eType == REGION_EMPTY) || (eType == REGION_NULL) ) + return rLogicRegion; + + Region aRegion; + PolyPolygon* pPolyPoly = rLogicRegion.ImplGetImplRegion()->mpPolyPoly; + + if( pPolyPoly ) + aRegion = Region( LogicToPixel( *pPolyPoly, rMapMode ) ); + else + { + long nX; + long nY; + long nWidth; + long nHeight; + ImplRegionInfo aInfo; + BOOL bRegionRect; + + aRegion.ImplBeginAddRect(); + bRegionRect = rLogicRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); + while ( bRegionRect ) + { + Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) ); + aRegion.ImplAddRect( LogicToPixel( aRect, rMapMode ) ); + bRegionRect = rLogicRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + } + aRegion.ImplEndAddRect(); + } + + return aRegion; +} + +// ----------------------------------------------------------------------- + +Point OutputDevice::PixelToLogic( const Point& rDevicePt ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( !mbMap ) + return rDevicePt; + + return Point( ImplPixelToLogic( rDevicePt.X(), mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresPixToLogX ) - maMapRes.mnMapOfsX, + ImplPixelToLogic( rDevicePt.Y(), mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresPixToLogY ) - maMapRes.mnMapOfsY ); +} + +// ----------------------------------------------------------------------- + +Size OutputDevice::PixelToLogic( const Size& rDeviceSize ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( !mbMap ) + return rDeviceSize; + + return Size( ImplPixelToLogic( rDeviceSize.Width(), mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresPixToLogX ), + ImplPixelToLogic( rDeviceSize.Height(), mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresPixToLogY ) ); +} + +// ----------------------------------------------------------------------- + +Rectangle OutputDevice::PixelToLogic( const Rectangle& rDeviceRect ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + if ( !mbMap || rDeviceRect.IsEmpty() ) + return rDeviceRect; + + return Rectangle( ImplPixelToLogic( rDeviceRect.Left(), mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresPixToLogX ) - maMapRes.mnMapOfsX, + ImplPixelToLogic( rDeviceRect.Top(), mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresPixToLogY ) - maMapRes.mnMapOfsY, + ImplPixelToLogic( rDeviceRect.Right(), mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresPixToLogX ) - maMapRes.mnMapOfsX, + ImplPixelToLogic( rDeviceRect.Bottom(), mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresPixToLogY ) - maMapRes.mnMapOfsY ); +} + +// ----------------------------------------------------------------------- + +Polygon OutputDevice::PixelToLogic( const Polygon& rDevicePoly ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rDevicePoly, Polygon, NULL ); + + if ( !mbMap ) + return rDevicePoly; + + USHORT i; + USHORT nPoints = rDevicePoly.GetSize(); + Polygon aPoly( rDevicePoly ); + + // Pointer auf das Point-Array holen (Daten werden kopiert) +#ifdef WIN + Point huge* pPointAry = (Point huge*)aPoly.ImplGetPointAry(); +#else + Point* pPointAry = aPoly.ImplGetPointAry(); +#endif + + for ( i = 0; i < nPoints; i++ ) + { + Point* pPt = &(pPointAry[i]); + pPt->X() = ImplPixelToLogic( pPt->X(), mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, + maThresRes.mnThresPixToLogX ) - maMapRes.mnMapOfsX; + pPt->Y() = ImplPixelToLogic( pPt->Y(), mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, + maThresRes.mnThresPixToLogY ) - maMapRes.mnMapOfsY; + } + + return aPoly; +} + +// ----------------------------------------------------------------------- + +PolyPolygon OutputDevice::PixelToLogic( const PolyPolygon& rDevicePolyPoly ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rDevicePolyPoly, PolyPolygon, NULL ); + + if ( !mbMap ) + return rDevicePolyPoly; + + PolyPolygon aPolyPoly( rDevicePolyPoly ); + USHORT nPoly = aPolyPoly.Count(); + for( USHORT i = 0; i < nPoly; i++ ) + { + Polygon& rPoly = aPolyPoly[i]; + rPoly = PixelToLogic( rPoly ); + } + return aPolyPoly; +} + +// ----------------------------------------------------------------------- + +Region OutputDevice::PixelToLogic( const Region& rDeviceRegion ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rDeviceRegion, Region, ImplDbgTestRegion ); + + RegionType eType = rDeviceRegion.GetType(); + + if ( !mbMap || (eType == REGION_EMPTY) || (eType == REGION_NULL) ) + return rDeviceRegion; + + Region aRegion; + PolyPolygon* pPolyPoly = rDeviceRegion.ImplGetImplRegion()->mpPolyPoly; + + if ( pPolyPoly ) + aRegion = Region( PixelToLogic( *pPolyPoly ) ); + else + { + long nX; + long nY; + long nWidth; + long nHeight; + ImplRegionInfo aInfo; + BOOL bRegionRect; + + aRegion.ImplBeginAddRect(); + bRegionRect = rDeviceRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); + while ( bRegionRect ) + { + Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) ); + aRegion.ImplAddRect( PixelToLogic( aRect ) ); + bRegionRect = rDeviceRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + } + aRegion.ImplEndAddRect(); + } + + return aRegion; +} + +// ----------------------------------------------------------------------- + +Point OutputDevice::PixelToLogic( const Point& rDevicePt, + const MapMode& rMapMode ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + // Ist Default-MapMode, dann bereche nichts + if ( rMapMode.IsDefault() ) + return rDevicePt; + + // MapMode-Aufloesung berechnen und Umrechnen + ImplMapRes aMapRes; + ImplThresholdRes aThresRes; + ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes ); + + return Point( ImplPixelToLogic( rDevicePt.X(), mnDPIX, + aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX, + aThresRes.mnThresPixToLogX ) - aMapRes.mnMapOfsX, + ImplPixelToLogic( rDevicePt.Y(), mnDPIY, + aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY, + aThresRes.mnThresPixToLogY ) - aMapRes.mnMapOfsY ); +} + +// ----------------------------------------------------------------------- + +Size OutputDevice::PixelToLogic( const Size& rDeviceSize, + const MapMode& rMapMode ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + // Ist Default-MapMode, dann bereche nichts + if ( rMapMode.IsDefault() ) + return rDeviceSize; + + // MapMode-Aufloesung berechnen und Umrechnen + ImplMapRes aMapRes; + ImplThresholdRes aThresRes; + ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes ); + + return Size( ImplPixelToLogic( rDeviceSize.Width(), mnDPIX, + aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX, + aThresRes.mnThresPixToLogX ), + ImplPixelToLogic( rDeviceSize.Height(), mnDPIY, + aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY, + aThresRes.mnThresPixToLogY ) ); +} + +// ----------------------------------------------------------------------- + +Rectangle OutputDevice::PixelToLogic( const Rectangle& rDeviceRect, + const MapMode& rMapMode ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + + // Ist Default-MapMode, dann bereche nichts + if ( rMapMode.IsDefault() || rDeviceRect.IsEmpty() ) + return rDeviceRect; + + // MapMode-Aufloesung berechnen und Umrechnen + ImplMapRes aMapRes; + ImplThresholdRes aThresRes; + ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes ); + + return Rectangle( ImplPixelToLogic( rDeviceRect.Left(), mnDPIX, + aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX, + aThresRes.mnThresPixToLogX ) - aMapRes.mnMapOfsX, + ImplPixelToLogic( rDeviceRect.Top(), mnDPIY, + aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY, + aThresRes.mnThresPixToLogY ) - aMapRes.mnMapOfsY, + ImplPixelToLogic( rDeviceRect.Right(), mnDPIX, + aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX, + aThresRes.mnThresPixToLogX ) - aMapRes.mnMapOfsX, + ImplPixelToLogic( rDeviceRect.Bottom(), mnDPIY, + aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY, + aThresRes.mnThresPixToLogY ) - aMapRes.mnMapOfsY ); +} + +// ----------------------------------------------------------------------- + +Polygon OutputDevice::PixelToLogic( const Polygon& rDevicePoly, + const MapMode& rMapMode ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rDevicePoly, Polygon, NULL ); + + // Ist Default-MapMode, dann bereche nichts + if ( rMapMode.IsDefault() ) + return rDevicePoly; + + // MapMode-Aufloesung berechnen und Umrechnen + ImplMapRes aMapRes; + ImplThresholdRes aThresRes; + ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes ); + + USHORT i; + USHORT nPoints = rDevicePoly.GetSize(); + Polygon aPoly( rDevicePoly ); + + // Pointer auf das Point-Array holen (Daten werden kopiert) +#ifdef WIN + Point huge* pPointAry = (Point huge*)aPoly.ImplGetPointAry(); +#else + Point* pPointAry = aPoly.ImplGetPointAry(); +#endif + + for ( i = 0; i < nPoints; i++ ) + { + Point* pPt = &(pPointAry[i]); + pPt->X() = ImplPixelToLogic( pPt->X(), mnDPIX, + aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX, + aThresRes.mnThresPixToLogX ) - aMapRes.mnMapOfsX; + pPt->Y() = ImplPixelToLogic( pPt->Y(), mnDPIY, + aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY, + aThresRes.mnThresPixToLogY ) - aMapRes.mnMapOfsY; + } + + return aPoly; +} + +// ----------------------------------------------------------------------- + +PolyPolygon OutputDevice::PixelToLogic( const PolyPolygon& rDevicePolyPoly, + const MapMode& rMapMode ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rDevicePolyPoly, PolyPolygon, NULL ); + + if ( rMapMode.IsDefault() ) + return rDevicePolyPoly; + + PolyPolygon aPolyPoly( rDevicePolyPoly ); + USHORT nPoly = aPolyPoly.Count(); + for( USHORT i = 0; i < nPoly; i++ ) + { + Polygon& rPoly = aPolyPoly[i]; + rPoly = PixelToLogic( rPoly, rMapMode ); + } + return aPolyPoly; +} + +// ----------------------------------------------------------------------- + +Region OutputDevice::PixelToLogic( const Region& rDeviceRegion, + const MapMode& rMapMode ) const +{ + DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); + DBG_CHKOBJ( &rDeviceRegion, Region, ImplDbgTestRegion ); + + RegionType eType = rDeviceRegion.GetType(); + + if ( rMapMode.IsDefault() || (eType == REGION_EMPTY) || (eType == REGION_NULL) ) + return rDeviceRegion; + + Region aRegion; + PolyPolygon* pPolyPoly = rDeviceRegion.ImplGetImplRegion()->mpPolyPoly; + + if ( pPolyPoly ) + aRegion = Region( PixelToLogic( *pPolyPoly, rMapMode ) ); + else + { + long nX; + long nY; + long nWidth; + long nHeight; + ImplRegionInfo aInfo; + BOOL bRegionRect; + + aRegion.ImplBeginAddRect(); + bRegionRect = rDeviceRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); + while ( bRegionRect ) + { + Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) ); + aRegion.ImplAddRect( PixelToLogic( aRect, rMapMode ) ); + bRegionRect = rDeviceRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + } + aRegion.ImplEndAddRect(); + } + + return aRegion; +} + +// ----------------------------------------------------------------------- + +#define ENTER0( rSource, pMapModeSource, pMapModeDest ) \ + if ( !pMapModeSource ) \ + pMapModeSource = &maMapMode; \ + if ( !pMapModeDest ) \ + pMapModeDest = &maMapMode; \ + if ( *pMapModeSource == *pMapModeDest ) \ + return rSource + +// ----------------------------------------------------------------------- + +#define ENTER1( rSource, pMapModeSource, pMapModeDest ) \ + ENTER0( rSource, pMapModeSource, pMapModeDest ); \ + \ + ImplMapRes aMapResSource; \ + ImplMapRes aMapResDest; \ + \ + if ( !mbMap || pMapModeSource != &maMapMode ) \ + { \ + if ( pMapModeSource->GetMapUnit() == MAP_RELATIVE ) \ + aMapResSource = maMapRes; \ + ImplCalcMapResolution( *pMapModeSource, \ + mnDPIX, mnDPIY, aMapResSource ); \ + } \ + else \ + aMapResSource = maMapRes; \ + if ( !mbMap || pMapModeDest != &maMapMode ) \ + { \ + if ( pMapModeDest->GetMapUnit() == MAP_RELATIVE ) \ + aMapResDest = maMapRes; \ + ImplCalcMapResolution( *pMapModeDest, \ + mnDPIX, mnDPIY, aMapResDest ); \ + } \ + else \ + aMapResDest = maMapRes + +// ----------------------------------------------------------------------- + +#define ENTER2( eUnitSource, eUnitDest ) \ + DBG_ASSERT( eUnitSource != MAP_SYSFONT \ + && eUnitSource != MAP_APPFONT \ + && eUnitSource != MAP_RELATIVE, \ + "Source MapUnit nicht erlaubt" ); \ + DBG_ASSERT( eUnitDest != MAP_SYSFONT \ + && eUnitDest != MAP_APPFONT \ + && eUnitDest != MAP_RELATIVE, \ + "Destination MapUnit nicht erlaubt" ); \ + DBG_ASSERTWARNING( eUnitSource != MAP_PIXEL, \ + "MAP_PIXEL mit 72dpi angenaehert" ); \ + DBG_ASSERTWARNING( eUnitDest != MAP_PIXEL, \ + "MAP_PIXEL mit 72dpi angenaehert" ) + +// ----------------------------------------------------------------------- + +#define ENTER3( eUnitSource, eUnitDest ) \ + long nNumerator = aImplNumeratorAry[eUnitSource] * \ + aImplDenominatorAry[eUnitDest]; \ + long nDenominator = aImplNumeratorAry[eUnitDest] * \ + aImplDenominatorAry[eUnitSource]; \ + if ( eUnitSource == MAP_PIXEL ) \ + nDenominator *= 72; \ + else if( eUnitDest == MAP_PIXEL ) \ + nNumerator *= 72 + +// ----------------------------------------------------------------------- + +#define ENTER4( rMapModeSource, rMapModeDest ) \ + ImplMapRes aMapResSource; \ + ImplMapRes aMapResDest; \ + \ + ImplCalcMapResolution( rMapModeSource, 72, 72, aMapResSource ); \ + ImplCalcMapResolution( rMapModeDest, 72, 72, aMapResDest ) + +// ----------------------------------------------------------------------- + +// return (n1 * n2 * n3) / (n4 * n5) +static long fn5( const long n1, + const long n2, + const long n3, + const long n4, + const long n5 ) +{ + if ( n1 == 0 || n2 == 0 || n3 == 0 || n4 == 0 || n5 == 0 ) + return 0; + if ( LONG_MAX / Abs(n2) < Abs(n3) ) + { + // a6 wird "ubersprungen + BigInt a7 = n2; + a7 *= n3; + a7 *= n1; + + if ( LONG_MAX / Abs(n4) < Abs(n5) ) + { + BigInt a8 = n4; + a8 *= n5; + + BigInt a9 = a8; + a9 /= 2; + if ( a7.IsNeg() ) + a7 -= a9; + else + a7 += a9; + + a7 /= a8; + } // of if + else + { + long n8 = n4 * n5; + + if ( a7.IsNeg() ) + a7 -= n8 / 2; + else + a7 += n8 / 2; + + a7 /= n8; + } // of else + return (long)a7; + } // of if + else + { + long n6 = n2 * n3; + + if ( LONG_MAX / Abs(n1) < Abs(n6) ) + { + BigInt a7 = n1; + a7 *= n6; + + if ( LONG_MAX / Abs(n4) < Abs(n5) ) + { + BigInt a8 = n4; + a8 *= n5; + + BigInt a9 = a8; + a9 /= 2; + if ( a7.IsNeg() ) + a7 -= a9; + else + a7 += a9; + + a7 /= a8; + } // of if + else + { + long n8 = n4 * n5; + + if ( a7.IsNeg() ) + a7 -= n8 / 2; + else + a7 += n8 / 2; + + a7 /= n8; + } // of else + return (long)a7; + } // of if + else + { + long n7 = n1 * n6; + + if ( LONG_MAX / Abs(n4) < Abs(n5) ) + { + BigInt a7 = n7; + BigInt a8 = n4; + a8 *= n5; + + BigInt a9 = a8; + a9 /= 2; + if ( a7.IsNeg() ) + a7 -= a9; + else + a7 += a9; + + a7 /= a8; + return (long)a7; + } // of if + else + { + const long n8 = n4 * n5; + const long n8_2 = n8 / 2; + + if( n7 < 0 ) + { + if( ( n7 - LONG_MIN ) >= n8_2 ) + n7 -= n8_2; + } + else if( ( LONG_MAX - n7 ) >= n8_2 ) + n7 += n8_2; + + return n7 / n8; + } // of else + } // of else + } // of else + + return 0; +} + +// ----------------------------------------------------------------------- + +// return (n1 * n2) / n3 +static long fn3( const long n1, const long n2, const long n3 ) +{ + if ( n1 == 0 || n2 == 0 || n3 == 0 ) + return 0; + if ( LONG_MAX / Abs(n1) < Abs(n2) ) + { + BigInt a4 = n1; + a4 *= n2; + + if ( a4.IsNeg() ) + a4 -= n3 / 2; + else + a4 += n3 / 2; + + a4 /= n3; + return (long)a4; + } // of if + else + { + long n4 = n1 * n2; + const long n3_2 = n3 / 2; + + if( n4 < 0 ) + { + if( ( n4 - LONG_MIN ) >= n3_2 ) + n4 -= n3_2; + } + else if( ( LONG_MAX - n4 ) >= n3_2 ) + n4 += n3_2; + + return n4 / n3; + } // of else + + return 0; +} + +// ----------------------------------------------------------------------- + +Point OutputDevice::LogicToLogic( const Point& rPtSource, + const MapMode* pMapModeSource, + const MapMode* pMapModeDest ) const +{ + ENTER1( rPtSource, pMapModeSource, pMapModeDest ); + + return Point( fn5( rPtSource.X() + aMapResSource.mnMapOfsX, + aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX, + aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) - + aMapResDest.mnMapOfsX, + fn5( rPtSource.Y() + aMapResSource.mnMapOfsY, + aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY, + aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) - + aMapResDest.mnMapOfsY ); +} + +// ----------------------------------------------------------------------- + +Size OutputDevice::LogicToLogic( const Size& rSzSource, + const MapMode* pMapModeSource, + const MapMode* pMapModeDest ) const +{ + ENTER1( rSzSource, pMapModeSource, pMapModeDest ); + + return Size( fn5( rSzSource.Width(), + aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX, + aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ), + fn5( rSzSource.Height(), + aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY, + aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) ); +} + +// ----------------------------------------------------------------------- + +Rectangle OutputDevice::LogicToLogic( const Rectangle& rRectSource, + const MapMode* pMapModeSource, + const MapMode* pMapModeDest ) const +{ + ENTER1( rRectSource, pMapModeSource, pMapModeDest ); + + return Rectangle( fn5( rRectSource.Left() + aMapResSource.mnMapOfsX, + aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX, + aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) - + aMapResDest.mnMapOfsX, + fn5( rRectSource.Top() + aMapResSource.mnMapOfsY, + aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY, + aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) - + aMapResDest.mnMapOfsY, + fn5( rRectSource.Right() + aMapResSource.mnMapOfsX, + aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX, + aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) - + aMapResDest.mnMapOfsX, + fn5( rRectSource.Bottom() + aMapResSource.mnMapOfsY, + aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY, + aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) - + aMapResDest.mnMapOfsY ); +} + +// ----------------------------------------------------------------------- + +long* OutputDevice::LogicToLogic( long* pX, USHORT nCount, + const MapMode* pMapModeSource, + const MapMode* pMapModeDest ) const +{ + ENTER1( pX, pMapModeSource, pMapModeDest ); + + for( ; nCount; nCount--, pX++ ) + { + *pX = fn5( *pX, + aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX, + aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ); + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +Point OutputDevice::LogicToLogic( const Point& rPtSource, + const MapMode& rMapModeSource, + const MapMode& rMapModeDest ) +{ + if ( rMapModeSource == rMapModeDest ) + return rPtSource; + + MapUnit eUnitSource = rMapModeSource.GetMapUnit(); + MapUnit eUnitDest = rMapModeDest.GetMapUnit(); + ENTER2( eUnitSource, eUnitDest ); + + if ( rMapModeSource.mpImplMapMode->mbSimple && + rMapModeDest.mpImplMapMode->mbSimple ) + { + ENTER3( eUnitSource, eUnitDest ); + + return Point( fn3( rPtSource.X(), nNumerator, nDenominator ), + fn3( rPtSource.Y(), nNumerator, nDenominator ) ); + } + else + { + ENTER4( rMapModeSource, rMapModeDest ); + + return Point( fn5( rPtSource.X() + aMapResSource.mnMapOfsX, + aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX, + aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) - + aMapResDest.mnMapOfsX, + fn5( rPtSource.Y() + aMapResSource.mnMapOfsY, + aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY, + aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) - + aMapResDest.mnMapOfsY ); + } +} + +// ----------------------------------------------------------------------- + +Size OutputDevice::LogicToLogic( const Size& rSzSource, + const MapMode& rMapModeSource, + const MapMode& rMapModeDest ) +{ + if ( rMapModeSource == rMapModeDest ) + return rSzSource; + + MapUnit eUnitSource = rMapModeSource.GetMapUnit(); + MapUnit eUnitDest = rMapModeDest.GetMapUnit(); + ENTER2( eUnitSource, eUnitDest ); + + if ( rMapModeSource.mpImplMapMode->mbSimple && + rMapModeDest.mpImplMapMode->mbSimple ) + { + ENTER3( eUnitSource, eUnitDest ); + + return Size( fn3( rSzSource.Width(), nNumerator, nDenominator ), + fn3( rSzSource.Height(), nNumerator, nDenominator ) ); + } + else + { + ENTER4( rMapModeSource, rMapModeDest ); + + return Size( fn5( rSzSource.Width(), + aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX, + aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ), + fn5( rSzSource.Height(), + aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY, + aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) ); + } +} + +// ----------------------------------------------------------------------- + +Rectangle OutputDevice::LogicToLogic( const Rectangle& rRectSource, + const MapMode& rMapModeSource, + const MapMode& rMapModeDest ) +{ + if ( rMapModeSource == rMapModeDest ) + return rRectSource; + + MapUnit eUnitSource = rMapModeSource.GetMapUnit(); + MapUnit eUnitDest = rMapModeDest.GetMapUnit(); + ENTER2( eUnitSource, eUnitDest ); + + if ( rMapModeSource.mpImplMapMode->mbSimple && + rMapModeDest.mpImplMapMode->mbSimple ) + { + ENTER3( eUnitSource, eUnitDest ); + + return Rectangle( fn3( rRectSource.Left(), nNumerator, nDenominator ), + fn3( rRectSource.Top(), nNumerator, nDenominator ), + fn3( rRectSource.Right(), nNumerator, nDenominator ), + fn3( rRectSource.Bottom(), nNumerator, nDenominator ) ); + } + else + { + ENTER4( rMapModeSource, rMapModeDest ); + + return Rectangle( fn5( rRectSource.Left() + aMapResSource.mnMapOfsX, + aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX, + aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) - + aMapResDest.mnMapOfsX, + fn5( rRectSource.Top() + aMapResSource.mnMapOfsY, + aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY, + aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) - + aMapResDest.mnMapOfsY, + fn5( rRectSource.Right() + aMapResSource.mnMapOfsX, + aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX, + aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) - + aMapResDest.mnMapOfsX, + fn5( rRectSource.Bottom() + aMapResSource.mnMapOfsY, + aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY, + aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) - + aMapResDest.mnMapOfsY ); + } +} + +// ----------------------------------------------------------------------- + +long OutputDevice::LogicToLogic( long nLongSource, + MapUnit eUnitSource, MapUnit eUnitDest ) +{ + if ( eUnitSource == eUnitDest ) + return nLongSource; + + ENTER2( eUnitSource, eUnitDest ); + ENTER3( eUnitSource, eUnitDest ); + + return fn3( nLongSource, nNumerator, nDenominator ); +} + +// ----------------------------------------------------------------------- + +long Window::ImplLogicUnitToPixelX( long nX, MapUnit eUnit ) +{ + if ( eUnit != MAP_PIXEL ) + { + ImplFrameData* pFrameData = mpFrameData; + + // Map-Einheit verschieden, dann neu berechnen + if ( pFrameData->meMapUnit != eUnit ) + { + pFrameData->meMapUnit = eUnit; + ImplCalcMapResolution( MapMode( eUnit ), mnDPIX, mnDPIY, + pFrameData->maMapUnitRes ); + } + + // Es wird kein BigInt gebraucht, da diese Funktion nur zur Umrechnung + // von Fensterposition benutzt wird + nX = nX * mnDPIX * pFrameData->maMapUnitRes.mnMapScNumX; + nX += nX >= 0 ? (pFrameData->maMapUnitRes.mnMapScDenomX/2) : + -((pFrameData->maMapUnitRes.mnMapScDenomX-1)/2); + nX /= pFrameData->maMapUnitRes.mnMapScDenomX; + } + + return nX; +} + +// ----------------------------------------------------------------------- + +long Window::ImplLogicUnitToPixelY( long nY, MapUnit eUnit ) +{ + if ( eUnit != MAP_PIXEL ) + { + ImplFrameData* pFrameData = mpFrameData; + + // Map-Einheit verschieden, dann neu berechnen + if ( pFrameData->meMapUnit != eUnit ) + { + pFrameData->meMapUnit = eUnit; + ImplCalcMapResolution( MapMode( eUnit ), mnDPIX, mnDPIY, + pFrameData->maMapUnitRes ); + } + + // Es wird kein BigInt gebraucht, da diese Funktion nur zur Umrechnung + // von Fensterposition benutzt wird + nY = nY * mnDPIY * pFrameData->maMapUnitRes.mnMapScNumY; + nY += nY >= 0 ? (pFrameData->maMapUnitRes.mnMapScDenomY/2) : + -((pFrameData->maMapUnitRes.mnMapScDenomY-1)/2); + nY /= pFrameData->maMapUnitRes.mnMapScDenomY; + } + + return nY; +} diff --git a/vcl/source/gdi/polyscan.cxx b/vcl/source/gdi/polyscan.cxx new file mode 100644 index 000000000000..cb9714d51765 --- /dev/null +++ b/vcl/source/gdi/polyscan.cxx @@ -0,0 +1,389 @@ +/************************************************************************* + * + * $RCSfile: polyscan.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <string.h> +#include <tools/new.hxx> +#include "salbtype.hxx" +#include "poly.hxx" +#include "polyscan.hxx" + +// ---------------- +// - PolyScanline - +// ---------------- + +PolyScanline::PolyScanline() : + mpFirst ( NULL ), + mpLast ( NULL ), + mpAct ( NULL ), + mnLeft ( 0L ), + mnRight ( 0L ) +{ +} + +// ------------------------------------------------------------------------ + +PolyScanline::~PolyScanline() +{ + ImplDelete(); +} + +// ------------------------------------------------------------------------ + +void PolyScanline::ImplDelete() +{ + ScanlinePoint* pAct = mpFirst; + + while( pAct ) + { + ScanlinePoint* pNext = pAct->mpNext; + delete pAct; + pAct = pNext; + } + + mnLeft = mnRight = 0L; + mpFirst = mpAct = mpLast = NULL; +} + +// ------------------------------------------------------------------------ + +void PolyScanline::Insert( long nX ) +{ + // first point to insert? + if( !mpFirst ) + mpLast = mpFirst = new ScanlinePoint( mnLeft = mnRight = nX, NULL ); + else + { + // insert at the beginning of the scanline + if( nX <= mpFirst->mnX ) + mpFirst = new ScanlinePoint( mnLeft = nX, mpFirst ); + else if( nX >= mnRight ) + mpLast = mpLast->mpNext = new ScanlinePoint( mnRight = nX, NULL ); + else + { + ScanlinePoint* pLast = mpFirst; + ScanlinePoint* pAct = mpFirst->mpNext; + + while( pAct ) + { + // insert in the midlle of the scanline? + if( nX <= pAct->mnX ) + { + pLast->mpNext = new ScanlinePoint( nX, pAct ); + break; + } + + pLast = pAct; + pAct = pAct->mpNext; + } + } + } +} + +// ------------------------------------------------------------------------ + +void PolyScanline::Set( long nStart, long nEnd ) +{ + if( mpFirst ) + ImplDelete(); + + if( nStart <= nEnd ) + mpFirst = new ScanlinePoint( mnLeft = nStart, mpLast = new ScanlinePoint( mnRight = nEnd, NULL ) ); + else + mpFirst = new ScanlinePoint( mnLeft = nEnd, mpLast = new ScanlinePoint( mnRight = nStart, NULL ) ); +} + +// ------------------------------------------------------------------------ + +BOOL PolyScanline::GetFirstSegment( PolyScanSegment& rSegment ) +{ + BOOL bRet = GetFirstX( rSegment.mnStart ); + + if( bRet && !GetNextX( rSegment.mnEnd ) ) + rSegment.mnEnd = rSegment.mnStart; + + return bRet; +} + +// ------------------------------------------------------------------------ + +BOOL PolyScanline::GetNextSegment( PolyScanSegment& rSegment ) +{ + BOOL bRet = GetNextX( rSegment.mnStart ); + + if( bRet && !GetNextX( rSegment.mnEnd ) ) + rSegment.mnEnd = rSegment.mnStart; + + return bRet; +} + +// --------------- +// - PolyScanner - +// --------------- + +PolyScanner::PolyScanner( const Rectangle& rRect ) +{ + if( !rRect.IsEmpty() ) + { + Rectangle aRect( rRect ); + ULONG nHeight; + + aRect.Justify(); + mnLeft = aRect.Left(); + mnTop = aRect.Top(); + mnRight = aRect.Right(); + mnBottom = aRect.Bottom(); + mpArray = new PolyScanline[ nHeight = Height() ]; + + for( ULONG i = 0UL; i < nHeight; i++ ) + mpArray[ i ].Set( mnLeft, mnRight ); + } + else + { + mnLeft = mnTop = mnRight = mnBottom = 0L; + mpArray = NULL; + } +} + +// ------------------------------------------------------------------------ + +PolyScanner::PolyScanner( const Polygon& rPoly ) +{ + const long nCount = rPoly.GetSize(); + + if( nCount ) + { + long nLast = nCount - 1; + Point aFirst( rPoly[ 0 ] ); + Point aLast( rPoly[ (USHORT) nLast ] ); + + while( nLast && ( aLast == aFirst ) ) + aLast = rPoly[ (USHORT) --nLast ]; + + if( !nLast ) + { + aLast = rPoly[ 0 ]; + mnLeft = mnRight = aLast.X(); + mnTop = mnBottom = aLast.Y(); + mpArray = new PolyScanline[ 1UL ]; + mpArray[ 0 ].Set( mnLeft, mnRight ); + } + else + { + const Rectangle aRect( rPoly.GetBoundRect() ); + ULONG nHeight; + + mnLeft = aRect.Left(); + mnTop = aRect.Top(); + mnRight = aRect.Right(); + mnBottom = aRect.Bottom(); + aLast = aFirst; + mpArray = new PolyScanline[ nHeight = Height() ]; + + for( long i = 1L; i <= nLast; i++ ) + { + const Point& rPt = rPoly[ (USHORT) i ]; + + if( rPt != aLast ) + { + InsertLine( aLast, rPt ); + aLast = rPt; + } + } + + InsertLine( aLast, aFirst ); + } + } + else + mpArray = NULL; +} + +// ------------------------------------------------------------------------ + +PolyScanner::PolyScanner( const PolyPolygon& rPolyPoly ) +{ + mpArray = NULL; +} + +// ------------------------------------------------------------------------ + +PolyScanner::~PolyScanner() +{ + delete[] mpArray; +} + +// ------------------------------------------------------------------------ + +PolyScanline* PolyScanner::operator[]( ULONG nPos ) const +{ + DBG_ASSERT( nPos < Count(), "nPos out of range!" ); + return( mpArray ? ( mpArray + nPos ) : NULL ); +} + +// ------------------------------------------------------------------------ + +void PolyScanner::InsertLine( const Point& rStart, const Point& rEnd ) +{ + long nX, nY; + + if( rStart.Y() == rEnd.Y() ) + mpArray[ rStart.Y() - mnTop ].Insert( rStart.X() ); + else if( rStart.X() == rEnd.X() ) + { + // vertical line + const long nEndY = rEnd.Y(); + + nX = rStart.X(); + nY = rStart.Y(); + + if( nEndY > nY ) + while( nY < nEndY ) + mpArray[ nY++ - mnTop ].Insert( nX ); + else + while( nY > nEndY ) + mpArray[ nY-- - mnTop ].Insert( nX ); + } + else + { + const long nDX = labs( rEnd.X() - rStart.X() ); + const long nDY = labs( rEnd.Y() - rStart.Y() ); + const long nStartX = rStart.X(); + const long nStartY = rStart.Y(); + const long nEndX = rEnd.X(); + const long nEndY = rEnd.Y(); + const long nXInc = ( nStartX < nEndX ) ? 1L : -1L; + const long nYInc = ( nStartY < nEndY ) ? 1L : -1L; + long nLastX = nStartX; + long nLastY = nStartY; + BOOL bLast = FALSE; + + mpArray[ nStartY - mnTop ].Insert( nStartX ); + + if( nDX >= nDY ) + { + const long nDYX = ( nDY - nDX ) << 1; + const long nDY2 = nDY << 1; + long nD = nDY2 - nDX; + + for( nX = nStartX, nY = nLastY = nStartY; nX != nEndX; ) + { + if( nY != nLastY ) + { + if( bLast ) + mpArray[ nLastY - mnTop ].Insert( nLastX ); + + mpArray[ nY - mnTop ].Insert( nX ); + bLast = FALSE; + } + else + bLast = TRUE; + + nLastX = nX; + nLastY = nY; + + if( nD < 0L ) + nD += nDY2; + else + { + nD += nDYX; + nY += nYInc; + } + + nX += nXInc; + } + } + else + { + const long nDYX = ( nDX - nDY ) << 1; + const long nDY2 = nDX << 1; + long nD = nDY2 - nDY; + + for( nX = nStartX, nY = nStartY; nY != nEndY; ) + { + if( nY != nLastY ) + { + if( bLast ) + mpArray[ nLastY - mnTop ].Insert( nLastX ); + + mpArray[ nY - mnTop ].Insert( nX ); + bLast = FALSE; + } + else + bLast = TRUE; + + nLastX = nX; + nLastY = nY; + + if( nD < 0L ) + nD += nDY2; + else + { + nD += nDYX; + nX += nXInc; + } + + nY += nYInc; + } + } + + if( bLast ) + mpArray[ nLastY - mnTop ].Insert( nLastX ); + } +} diff --git a/vcl/source/gdi/print.cxx b/vcl/source/gdi/print.cxx new file mode 100644 index 000000000000..84c54f0cc5b2 --- /dev/null +++ b/vcl/source/gdi/print.cxx @@ -0,0 +1,1979 @@ +/************************************************************************* + * + * $RCSfile: print.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_PRINT_CXX +#define _SPOOLPRINTER_EXT +#define _RMPRINTER_EXT +#define ENABLE_BYTESTRING_STREAM_OPERATORS + +#ifndef REMOTE_APPSERVER + +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#ifndef _SV_SALINST_HXX +#include <salinst.hxx> +#endif +#ifndef _SV_SALGDI_HXX +#include <salgdi.hxx> +#endif +#ifndef _SV_SALPTYPE_HXX +#include <salptype.hxx> +#endif +#ifndef _SV_SALPRN_HXX +#include <salprn.hxx> +#endif + +#else + +#include "rmoutdev.hxx" +#include "rmprint.hxx" +#include "rmwindow.hxx" +#include "rvp.hxx" +#include <vos/mutex.hxx> + +using namespace ::com::sun::star::uno; + +struct SalPrinterQueueInfo +{ + XubString maPrinterName; + XubString maDriver; + XubString maLocation; + XubString maComment; + ULONG mnStatus; + ULONG mnJobs; + void* mpSysData; + + SalPrinterQueueInfo(); + ~SalPrinterQueueInfo(); +}; + +#endif + +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif +#ifndef _VCOMPAT_HXX +#include <tools/vcompat.hxx> +#endif +#ifndef _SV_SVDATA_HXX +#include <svdata.hxx> +#endif +#ifndef _SV_SVAPP_HXX +#include <svapp.hxx> +#endif +#ifndef _SV_WRKWIN_HXX +#include <wrkwin.hxx> +#endif +#ifndef _SV_JOBSET_H +#include <jobset.h> +#endif +#ifndef _SV_OUTDEV_H +#include <outdev.h> +#endif +#ifndef _SV_VIRDEV_HXX +#include <virdev.hxx> +#endif +#ifndef _SV_WINDOW_HXX +#include <window.hxx> +#endif +#ifndef _SV_PRINT_H +#include <print.h> +#endif +#ifndef _SV_GDIMTF_HXX +#include <gdimtf.hxx> +#endif +#ifndef _SV_METAACT_HXX +#include <metaact.hxx> +#endif +#ifndef _SV_IMPPRN_HXX +#include <impprn.hxx> +#endif +#ifndef _SV_PRINT_HXX +#include <print.hxx> +#endif + +int nImplSysDialog = 0; + +#define PRINTERSEQ_GET( _def_Seq, _def_Obj ) \ +{ \ + SvMemoryStream* _def_pStm = new SvMemoryStream( (char*)_def_Seq.getConstArray(), _def_Seq.getLength(), STREAM_READ ); \ + _def_pStm->SetCompressMode( COMPRESSMODE_FULL ); \ + *_def_pStm >> _def_Obj; \ + delete _def_pStm; \ +} + +#define PRINTERSEQ_SET( _def_Obj, _def_Seq, _def_Type ) \ +{ \ + SvMemoryStream* _def_pStm = new SvMemoryStream( 8192, 8192 ); \ + _def_pStm->SetCompressMode( COMPRESSMODE_FULL ); \ + *_def_pStm << _def_Obj; \ + _def_Seq = _def_Type( (sal_Int8*) (_def_pStm)->GetData(), (_def_pStm)->Tell() ); \ + delete _def_pStm; \ +} + +// ======================================================================= + +#define PAPER_SLOPPY 20 +#define PAPER_COUNT 9 + +static long ImplPaperFormats[PAPER_COUNT*2] = +{ + 29700, 42000, // A3 + 21000, 29700, // A4 + 14800, 21000, // A5 + 25000, 35300, // B4 + 17600, 25000, // B5 + 21600, 27900, // Letter + 21600, 35600, // Legal + 27900, 43100, // Tabloid + 0, 0 // USER +}; + +// ======================================================================= + +Paper ImplGetPaperFormat( long nWidth100thMM, long nHeight100thMM ) +{ + USHORT i; + + for( i = 0; i < PAPER_COUNT; i++ ) + { + if ( (ImplPaperFormats[i*2] == nWidth100thMM) && + (ImplPaperFormats[i*2+1] == nHeight100thMM) ) + return (Paper)i; + } + + for( i = 0; i < PAPER_COUNT; i++ ) + { + if ( (Abs( ImplPaperFormats[i*2]-nWidth100thMM ) < PAPER_SLOPPY) && + (Abs( ImplPaperFormats[i*2+1]-nHeight100thMM ) < PAPER_SLOPPY) ) + return (Paper)i; + } + + return PAPER_USER; +} + +// ======================================================================= + +void ImplUpdateJobSetupPaper( JobSetup& rJobSetup ) +{ + const ImplJobSetup* pConstData = rJobSetup.ImplGetConstData(); + + if ( !pConstData->mnPaperWidth || !pConstData->mnPaperHeight ) + { + if ( pConstData->mePaperFormat != PAPER_USER ) + { + ImplJobSetup* pData = rJobSetup.ImplGetData(); + pData->mnPaperWidth = ImplPaperFormats[((USHORT)pConstData->mePaperFormat)*2]; + pData->mnPaperHeight = ImplPaperFormats[((USHORT)pConstData->mePaperFormat)*2+1]; + } + } + else if ( pConstData->mePaperFormat == PAPER_USER ) + { + Paper ePaper = ImplGetPaperFormat( pConstData->mnPaperWidth, pConstData->mnPaperHeight ); + if ( ePaper != PAPER_USER ) + rJobSetup.ImplGetData()->mePaperFormat = ePaper; + } +} + +// ======================================================================= + +QueueInfo::QueueInfo() +{ + mnStatus = 0; + mnJobs = 0; +} + +// ----------------------------------------------------------------------- + +QueueInfo::QueueInfo( const QueueInfo& rInfo ) : + maPrinterName( rInfo.maPrinterName ), + maDriver( rInfo.maDriver ), + maLocation( rInfo.maLocation ), + maComment( rInfo.maComment ), + mnStatus( rInfo.mnStatus ), + mnJobs( rInfo.mnJobs ) +{ +} + +// ----------------------------------------------------------------------- + +QueueInfo::~QueueInfo() +{ +} + +// ----------------------------------------------------------------------- + +const QueueInfo& QueueInfo::operator==( const QueueInfo& rInfo ) +{ + maPrinterName = rInfo.maPrinterName; + maDriver = rInfo.maDriver; + maLocation = rInfo.maLocation; + maComment = rInfo.maComment; + mnStatus = rInfo.mnStatus; + mnJobs = rInfo.mnJobs; + return *this; +} + +// ----------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rOStream, const QueueInfo& rInfo ) +{ + VersionCompat aCompat( rOStream, STREAM_WRITE, 1 ); + + rOStream.WriteByteString( rInfo.maPrinterName, RTL_TEXTENCODING_UTF8 ); + rOStream.WriteByteString( rInfo.maDriver, RTL_TEXTENCODING_UTF8 ); + rOStream.WriteByteString( rInfo.maLocation, RTL_TEXTENCODING_UTF8 ); + rOStream.WriteByteString( rInfo.maComment, RTL_TEXTENCODING_UTF8 ); + rOStream << rInfo.mnStatus; + rOStream << rInfo.mnJobs; + + return rOStream; +} + +// ----------------------------------------------------------------------- + +SvStream& operator>>( SvStream& rIStream, QueueInfo& rInfo ) +{ + VersionCompat aCompat( rIStream, STREAM_READ ); + + rIStream.ReadByteString( rInfo.maPrinterName, RTL_TEXTENCODING_UTF8 ); + rIStream.ReadByteString( rInfo.maDriver, RTL_TEXTENCODING_UTF8 ); + rIStream.ReadByteString( rInfo.maLocation, RTL_TEXTENCODING_UTF8 ); + rIStream.ReadByteString( rInfo.maComment, RTL_TEXTENCODING_UTF8 ); + rIStream >> rInfo.mnStatus; + rIStream >> rInfo.mnJobs; + + return rIStream; +} + +// ======================================================================= + +SalPrinterQueueInfo::SalPrinterQueueInfo() +{ + mnStatus = 0; + mnJobs = QUEUE_JOBS_DONTKNOW; + mpSysData = NULL; +} + +// ----------------------------------------------------------------------- + +SalPrinterQueueInfo::~SalPrinterQueueInfo() +{ +} + +// ----------------------------------------------------------------------- + +void ImplPrnQueueList::Add( SalPrinterQueueInfo* pData ) +{ + ImplPrnQueueData* pInfo = new ImplPrnQueueData; + pInfo->mpQueueInfo = NULL; + pInfo->mpSalQueueInfo = pData; + List::Insert( (void*)pInfo, LIST_APPEND ); +} + +// ======================================================================= + +static void ImplInitPrnQueueList() +{ + ImplSVData* pSVData = ImplGetSVData(); + + pSVData->maGDIData.mpPrinterQueueList = new ImplPrnQueueList; + +#ifndef REMOTE_APPSERVER + pSVData->mpDefInst->GetPrinterQueueInfo( pSVData->maGDIData.mpPrinterQueueList ); +#else + if ( pSVData->mpRemotePrinterList && pSVData->mpRemotePrinterList->GetPrinterCount() ) + { + const ULONG nCount = pSVData->mpRemotePrinterList->GetPrinterCount(); + for( ULONG i = 0; i < nCount; i++ ) + { + NMSP_CLIENT::RmQueueInfo aRmQInfo; + QueueInfo aQInfo; + SalPrinterQueueInfo* pNewInfo = new SalPrinterQueueInfo; + + RemotePrinterInfo* pPrinterInfo = pSVData->mpRemotePrinterList->GetPrinter( i ); + REF( NMSP_CLIENT::XRmPrinterEnvironment ) xPrinterEnv( pSVData->mpRemotePrinterList->GetPrinterEnv( pPrinterInfo->aServerName ) ); + + if ( xPrinterEnv.is() && xPrinterEnv->GetPrinterInfo( + pPrinterInfo->aPrinterName.GetBuffer(), aRmQInfo ) ) + { + PRINTERSEQ_GET( aRmQInfo, aQInfo ); + pNewInfo->maPrinterName = pPrinterInfo->GetFullName(); + pNewInfo->maDriver = aQInfo.GetDriver(); + pNewInfo->maLocation = aQInfo.GetLocation(); + pNewInfo->maComment = aQInfo.GetComment(); + pNewInfo->mnStatus = aQInfo.GetStatus(); + pNewInfo->mnJobs = aQInfo.GetJobs(); + pNewInfo->mpSysData = NULL; + pSVData->maGDIData.mpPrinterQueueList->Add( pNewInfo ); + } + } + } + if ( !pSVData->maGDIData.mpPrinterQueueList->Count() ) + { + SalPrinterQueueInfo* pNewInfo = new SalPrinterQueueInfo; + pNewInfo->maPrinterName = String::CreateFromAscii("No Printer"); + pNewInfo->mpSysData = NULL; + pSVData->maGDIData.mpPrinterQueueList->Add( pNewInfo ); + } +#endif +} + +// ----------------------------------------------------------------------- + +void ImplDeletePrnQueueList() +{ + ImplSVData* pSVData = ImplGetSVData(); + ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList; + + if ( pPrnList ) + { + ImplPrnQueueData* pInfo = pPrnList->First(); + while ( pInfo ) + { + if ( pInfo->mpQueueInfo ) + delete pInfo->mpQueueInfo; + +#ifndef REMOTE_APPSERVER + pSVData->mpDefInst->DeletePrinterQueueInfo( pInfo->mpSalQueueInfo ); +#else + delete pInfo->mpSalQueueInfo; +#endif + + delete pInfo; + pInfo = pPrnList->Next(); + } + + delete pPrnList; + pSVData->maGDIData.mpPrinterQueueList = NULL; + } +} + +// ----------------------------------------------------------------------- + +USHORT Printer::GetQueueCount() +{ + ImplSVData* pSVData = ImplGetSVData(); + + if ( !pSVData->maGDIData.mpPrinterQueueList ) + ImplInitPrnQueueList(); + + return (USHORT)(pSVData->maGDIData.mpPrinterQueueList->Count()); +} + +// ----------------------------------------------------------------------- + +const QueueInfo& Printer::GetQueueInfo( USHORT nQueue ) +{ + return GetQueueInfo( nQueue, TRUE ); +} + +// ----------------------------------------------------------------------- + +const QueueInfo& Printer::GetQueueInfo( USHORT nQueue, BOOL bStatus ) +{ + ImplSVData* pSVData = ImplGetSVData(); + + if ( !pSVData->maGDIData.mpPrinterQueueList ) + ImplInitPrnQueueList(); + + DBG_ASSERT( nQueue < pSVData->maGDIData.mpPrinterQueueList->Count(), + "Printer::GetQueueInfo() - nQueue > QueueCount" ); + + ImplPrnQueueData* pInfo = pSVData->maGDIData.mpPrinterQueueList->Get( nQueue ); + +#ifndef REMOTE_APPSERVER + if ( bStatus ) + pSVData->mpDefInst->GetPrinterQueueState( pInfo->mpSalQueueInfo ); +#else + // ??? +#endif + + if ( !pInfo->mpQueueInfo ) + pInfo->mpQueueInfo = new QueueInfo; + + pInfo->mpQueueInfo->maPrinterName = pInfo->mpSalQueueInfo->maPrinterName; + pInfo->mpQueueInfo->maDriver = pInfo->mpSalQueueInfo->maDriver; + pInfo->mpQueueInfo->maLocation = pInfo->mpSalQueueInfo->maLocation; + pInfo->mpQueueInfo->maComment = pInfo->mpSalQueueInfo->maComment; + pInfo->mpQueueInfo->mnStatus = pInfo->mpSalQueueInfo->mnStatus; + pInfo->mpQueueInfo->mnJobs = pInfo->mpSalQueueInfo->mnJobs; + return *pInfo->mpQueueInfo; +} + +// ----------------------------------------------------------------------- + +XubString Printer::GetDefaultPrinterName() +{ + ImplSVData* pSVData = ImplGetSVData(); + +#ifndef REMOTE_APPSERVER + return pSVData->mpDefInst->GetDefaultPrinter(); +#else + XubString aDefPrinterName; + if ( pSVData->mpRemotePrinterList ) + { + RemotePrinterInfo* pDefPrinter = pSVData->mpRemotePrinterList->GetDefaultPrinter(); + if ( pDefPrinter ) + aDefPrinterName = pDefPrinter->GetFullName(); + + } + return aDefPrinterName; +#endif +} + +// ======================================================================= + +void Printer::ImplInitData() +{ + mbDevOutput = FALSE; + meOutDevType = OUTDEV_PRINTER; + + mbDefPrinter = FALSE; + mnError = 0; + mnCurPage = 0; + mnCurPrintPage = 0; + mnPageQueueSize = 0; + mnCopyCount = 1; + mbCollateCopy = FALSE; + mbPrinting = FALSE; + mbJobActive = FALSE; + mbPrintFile = FALSE; + mbInPrintPage = FALSE; + mbNewJobSetup = FALSE; + mpInfoPrinter = NULL; + mpPrinter = NULL; + mpDisplayDev = NULL; + mpQPrinter = NULL; + mpQMtf = NULL; + mbIsQueuePrinter = FALSE; + + // Printer in die Liste eintragen + ImplSVData* pSVData = ImplGetSVData(); + mpNext = pSVData->maGDIData.mpFirstPrinter; + mpPrev = NULL; + if ( mpNext ) + mpNext->mpPrev = this; + else + pSVData->maGDIData.mpLastPrinter = this; + pSVData->maGDIData.mpFirstPrinter = this; +} + +// ----------------------------------------------------------------------- + +void Printer::ImplInit( SalPrinterQueueInfo* pInfo ) +{ + // Testen, ob Treiber ueberhaupt mit dem JobSetup uebereinstimmt + ImplJobSetup* pJobSetup = maJobSetup.ImplGetData(); + + if ( pJobSetup->mpDriverData ) + { + if ( (pJobSetup->maPrinterName != pInfo->maPrinterName) || + (pJobSetup->maDriver != pInfo->maDriver) ) + { + delete pJobSetup->mpDriverData; + pJobSetup->mpDriverData = NULL; + pJobSetup->mnDriverDataLen = 0; + } + } + + ImplSVData* pSVData = ImplGetSVData(); + + // Printernamen merken + maPrinterName = pInfo->maPrinterName; + maDriver = pInfo->maDriver; + + // In JobSetup den Printernamen eintragen + pJobSetup->maPrinterName = maPrinterName; + pJobSetup->maDriver = maDriver; + +#ifndef REMOTE_APPSERVER + mpInfoPrinter = pSVData->mpDefInst->CreateInfoPrinter( pInfo, pJobSetup ); + mpPrinter = NULL; + mpJobPrinter = NULL; + mpJobGraphics = NULL; + ImplUpdateJobSetupPaper( maJobSetup ); + + if ( !mpInfoPrinter ) + { + ImplInitDisplay( NULL ); + return; + } + + // we need a graphics + if ( !ImplGetGraphics() ) + { + ImplInitDisplay( NULL ); + return; + } +#else + + String aPrinterName( maPrinterName.GetToken( 0, '@' ) ); + String aPrintServerName( maPrinterName.GetToken( 1, '@' ) ); + + + mpInfoPrinter = new RmPrinter; + + Reference< ::com::sun::star::lang::XMultiServiceFactory > xPrinterFactory; + Reference< NMSP_CLIENT::XRmPrinter > xPrinter; + + if (pSVData->mpRemotePrinterList) + { +// if ( !aPrintServerName.Len() ) +// aPrintServerName = pSVData->mpRemotePrinterList->FindLocalPrintServer( aPrinterName ); + + xPrinterFactory = pSVData->mpRemotePrinterList->GetServerFactory( aPrintServerName ); + if( xPrinterFactory.is() ) + { + xPrinter = Reference< NMSP_CLIENT::XRmPrinter >( xPrinterFactory->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OfficePrinter.stardiv.de" ) ) ), NMSP_UNO::UNO_QUERY ); + mpInfoPrinter->SetInterface( xPrinter ); + } + } + + if ( ! xPrinter.is() ) + { + delete mpInfoPrinter; + mpInfoPrinter = NULL; + ImplInitDisplay( NULL ); + return; + } + else + { + QueueInfo aQInfo; + NMSP_CLIENT::RmQueueInfo aRmQInfo; + NMSP_CLIENT::RmJobSetup aRmJobSetup; + const REF( NMSP_CLIENT::XRmPrinter )& rxPrinter = mpInfoPrinter->GetInterface(); + + aQInfo.maPrinterName = aPrinterName; + aQInfo.maDriver = pInfo->maDriver; + aQInfo.maLocation = pInfo->maLocation; + aQInfo.maComment = pInfo->maComment; + aQInfo.mnStatus = pInfo->mnStatus; + aQInfo.mnJobs = pInfo->mnJobs; + + PRINTERSEQ_SET( aQInfo, aRmQInfo, NMSP_CLIENT::RmQueueInfo ); + mpInfoPrinter->Create( aRmQInfo, aRmJobSetup ); + PRINTERSEQ_GET( aRmJobSetup, maJobSetup ); + + if( rxPrinter.is() ) + { + mpGraphics = new ImplServerGraphics( pSVData->mpRemotePrinterList->GetServerAtoms( aPrintServerName ) ); + mpGraphics->SetInterface( REF( NMSP_CLIENT::XRmOutputDevice )( rxPrinter, NMSP_UNO::UNO_QUERY ) ); + } + + if( !mpGraphics->GetInterface().is() ) + { + delete mpGraphics, mpGraphics = NULL; + delete mpInfoPrinter, mpInfoPrinter = NULL; + ImplInitDisplay( NULL ); + return; + } + } +#endif + + // Daten initialisieren + ImplUpdatePageData(); + mpFontList = new ImplDevFontList; + mpFontCache = new ImplFontCache( TRUE ); + mpGraphics->GetDevFontList( mpFontList ); + mpFontList->InitStdFonts(); +} + +// ----------------------------------------------------------------------- + +void Printer::ImplInitDisplay( const Window* pWindow ) +{ + ImplSVData* pSVData = ImplGetSVData(); + + mpInfoPrinter = NULL; + mpPrinter = NULL; + mpJobPrinter = NULL; + mpJobGraphics = NULL; + + if ( pWindow ) + mpDisplayDev = new VirtualDevice( *pWindow ); + else + mpDisplayDev = new VirtualDevice(); + mpFontList = pSVData->maGDIData.mpScreenFontList; + mpFontCache = pSVData->maGDIData.mpScreenFontCache; + mnDPIX = mpDisplayDev->mnDPIX; + mnDPIY = mpDisplayDev->mnDPIY; + +#ifdef REMOTE_APPSERVER + mpGraphics = mpDisplayDev->mpGraphics; +#endif +} + +// ----------------------------------------------------------------------- + +SalPrinterQueueInfo* Printer::ImplGetQueueInfo( const XubString& rPrinterName, + const XubString* pDriver ) +{ + ImplSVData* pSVData = ImplGetSVData(); + if ( !pSVData->maGDIData.mpPrinterQueueList ) + ImplInitPrnQueueList(); + + ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList; + if ( pPrnList && pPrnList->Count() ) + { + // Zuerst suchen wir nach dem Printer-Namen + ImplPrnQueueData* pBestInfo = NULL; + ImplPrnQueueData* pInfo = pPrnList->First(); + while ( pInfo ) + { + if ( pInfo->mpSalQueueInfo->maPrinterName == rPrinterName ) + { + pBestInfo = pInfo; + if ( !pDriver || (pInfo->mpSalQueueInfo->maDriver == *pDriver) ) + return pInfo->mpSalQueueInfo; + } + pInfo = pPrnList->Next(); + } + + // Wenn wir einen PrinterNamen gefunden haben und nur der Treiber + // nicht passt, nehmen wir diesen + if ( pBestInfo ) + return pBestInfo->mpSalQueueInfo; + + // Dann suchen wir caseinsensitiv + pInfo = pPrnList->First(); + while ( pInfo ) + { + if ( pInfo->mpSalQueueInfo->maPrinterName.EqualsIgnoreCaseAscii( rPrinterName ) ) + { + pBestInfo = pInfo; + if ( !pDriver || pInfo->mpSalQueueInfo->maDriver.EqualsIgnoreCaseAscii( *pDriver ) ) + return pInfo->mpSalQueueInfo; + } + pInfo = pPrnList->Next(); + } + + // Wenn wir einen PrinterNamen gefunden haben und nur der Treiber + // nicht passt, nehmen wir diesen + if ( pBestInfo ) + return pBestInfo->mpSalQueueInfo; + + // Und wenn wir immer noch keinen gefunden haben, suchen wir + // noch nach einem passenden Treiber + if ( pDriver ) + { + pInfo = pPrnList->First(); + while ( pInfo ) + { + if ( pInfo->mpSalQueueInfo->maDriver == *pDriver ) + return pInfo->mpSalQueueInfo; + pInfo = pPrnList->Next(); + } + } + + // Und wenn wir immer noch keinen gefunden, dann wir der + // Default-Drucker genommen + XubString aPrinterName = GetDefaultPrinterName(); + pInfo = pPrnList->First(); + while ( pInfo ) + { + if ( pInfo->mpSalQueueInfo->maPrinterName == aPrinterName ) + return pInfo->mpSalQueueInfo; + pInfo = pPrnList->Next(); + } + + // Und wenn wir diesen auch nicht finden, nehmen wir den ersten + // in der Liste, denn einige Installationen zerstoeren den + // Namen und andere Programme weichen dann normalerweise noch + // auf irgendeinen Drucker aus + pInfo = pPrnList->First(); + if ( pInfo ) + return pInfo->mpSalQueueInfo; + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +void Printer::ImplUpdatePageData() +{ +#ifndef REMOTE_APPSERVER + // we need a graphics + if ( !ImplGetGraphics() ) + return; + + mpGraphics->GetResolution( mnDPIX, mnDPIY ); + mpInfoPrinter->GetPageInfo( maJobSetup.ImplGetConstData(), + mnOutWidth, mnOutHeight, + maPageOffset.X(), maPageOffset.Y(), + maPaperSize.Width(), maPaperSize.Height() ); +#else + if ( mpInfoPrinter && mpGraphics ) + { + mpGraphics->GetResolution( mnDPIX, mnDPIY ); + mpInfoPrinter->GetPageInfo( mnOutWidth, mnOutHeight, + maPageOffset.X(), maPageOffset.Y(), + maPaperSize.Width(), maPaperSize.Height() ); + } +#endif +} + +// ----------------------------------------------------------------------- + +void Printer::ImplUpdateFontList() +{ + ImplUpdateFontData( TRUE ); +} + +// ----------------------------------------------------------------------- + +Printer::Printer() +{ + ImplInitData(); + SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( GetDefaultPrinterName(), NULL ); + if ( pInfo ) + { + ImplInit( pInfo ); + if ( !IsDisplayPrinter() ) + mbDefPrinter = TRUE; + } + else + ImplInitDisplay( NULL ); +} + +// ----------------------------------------------------------------------- + +Printer::Printer( const Window* pWindow ) +{ + ImplInitData(); + ImplInitDisplay( pWindow ); +} + +// ----------------------------------------------------------------------- + +Printer::Printer( const JobSetup& rJobSetup ) : + maJobSetup( rJobSetup ) +{ + ImplInitData(); + SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rJobSetup.mpData->maPrinterName, + &rJobSetup.mpData->maDriver ); + if ( pInfo ) + { + ImplInit( pInfo ); + SetJobSetup( rJobSetup ); + } + else + { + ImplInitDisplay( NULL ); + maJobSetup = JobSetup(); + } +} + +// ----------------------------------------------------------------------- + +Printer::Printer( const QueueInfo& rQueueInfo ) +{ + ImplInitData(); + SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rQueueInfo.GetPrinterName(), + &rQueueInfo.GetDriver() ); + if ( pInfo ) + ImplInit( pInfo ); + else + ImplInitDisplay( NULL ); +} + +// ----------------------------------------------------------------------- + +Printer::Printer( const XubString& rPrinterName ) +{ + ImplInitData(); + SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rPrinterName, NULL ); + if ( pInfo ) + ImplInit( pInfo ); + else + ImplInitDisplay( NULL ); +} + +// ----------------------------------------------------------------------- + +Printer::~Printer() +{ + DBG_ASSERT( !IsPrinting(), "Printer::~Printer() - Job is printing" ); + DBG_ASSERT( !IsJobActive(), "Printer::~Printer() - Job is active" ); + DBG_ASSERT( !mpQPrinter, "Printer::~Printer() - QueuePrinter not destroyed" ); + DBG_ASSERT( !mpQMtf, "Printer::~Printer() - QueueMetafile not destroyed" ); + +#ifndef REMOTE_APPSERVER + ImplReleaseGraphics(); + if ( mpInfoPrinter ) + ImplGetSVData()->mpDefInst->DestroyInfoPrinter( mpInfoPrinter ); +#else + if ( mpInfoPrinter ) + { + if( mpGraphics ) + mpGraphics->SetInterface( REF( NMSP_CLIENT::XRmOutputDevice )() ); + + ImplReleaseServerGraphics(); + + if ( mpGetDevFontList ) + { + delete mpGetDevFontList; + mpGetDevFontList = NULL; + } + if ( mpGetDevSizeList ) + { + delete mpGetDevSizeList; + mpGetDevSizeList = NULL; + } + delete mpGraphics, mpGraphics = NULL; + delete mpInfoPrinter, mpInfoPrinter = NULL; + } +#endif + if ( mpDisplayDev ) + delete mpDisplayDev; + else + { + // OutputDevice-Dtor versucht das gleiche, deshalb muss hier + // der FontEntry auch auf NULL gesetzt werden + if ( mpFontEntry ) + { + mpFontCache->Release( mpFontEntry ); + mpFontEntry = NULL; + } + if ( mpGetDevFontList ) + { + delete mpGetDevFontList; + mpGetDevFontList = NULL; + } + if ( mpGetDevSizeList ) + { + delete mpGetDevSizeList; + mpGetDevSizeList = NULL; + } + delete mpFontList; + delete mpFontCache; + } + + // Printer aus der Liste eintragen + ImplSVData* pSVData = ImplGetSVData(); + if ( mpPrev ) + mpPrev->mpNext = mpNext; + else + pSVData->maGDIData.mpFirstPrinter = mpNext; + if ( mpNext ) + mpNext->mpPrev = mpPrev; + else + pSVData->maGDIData.mpLastPrinter = mpPrev; +} + +// ----------------------------------------------------------------------- + +ULONG Printer::GetCapabilities( USHORT nType ) const +{ + if ( IsDisplayPrinter() ) + return FALSE; + +#ifndef REMOTE_APPSERVER + return mpInfoPrinter->GetCapabilities( maJobSetup.ImplGetConstData(), nType ); +#else + return mpInfoPrinter->GetCapabilities( nType ); +#endif +} + +// ----------------------------------------------------------------------- + +BOOL Printer::HasSupport( PrinterSupport eFeature, BOOL bInJob ) const +{ + switch ( eFeature ) + { + case SUPPORT_SET_ORIENTATION: + return (BOOL)GetCapabilities( PRINTER_CAPABILITIES_SETORIENTATION ); + case SUPPORT_SET_PAPERBIN: + return (BOOL)GetCapabilities( PRINTER_CAPABILITIES_SETPAPERBIN ); + case SUPPORT_SET_PAPERSIZE: + return (BOOL)GetCapabilities( PRINTER_CAPABILITIES_SETPAPERSIZE ); + case SUPPORT_SET_PAPER: + return (BOOL)GetCapabilities( PRINTER_CAPABILITIES_SETPAPER ); + case SUPPORT_COPY: + return (GetCapabilities( PRINTER_CAPABILITIES_COPIES ) != 0); + case SUPPORT_COLLATECOPY: + return (GetCapabilities( PRINTER_CAPABILITIES_COLLATECOPIES ) != 0); + case SUPPORT_SETUPDIALOG: + return (BOOL)GetCapabilities( PRINTER_CAPABILITIES_SUPPORTDIALOG ); + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +BOOL Printer::SetJobSetup( const JobSetup& rSetup ) +{ + if ( IsDisplayPrinter() || mbInPrintPage ) + return FALSE; + + JobSetup aJobSetup = rSetup; + +#ifndef REMOTE_APPSERVER + ImplReleaseGraphics(); + if ( mpInfoPrinter->SetPrinterData( aJobSetup.ImplGetData() ) ) + { + ImplUpdateJobSetupPaper( aJobSetup ); + mbNewJobSetup = TRUE; + maJobSetup = aJobSetup; + ImplUpdatePageData(); + ImplUpdateFontList(); + return TRUE; + } + + return FALSE; +#else + if ( mpInfoPrinter ) + { + NMSP_CLIENT::RmJobSetup aRmJobSetup; + + PRINTERSEQ_SET( aJobSetup, aRmJobSetup, NMSP_CLIENT::RmJobSetup ); + if ( mpInfoPrinter->SetJobSetup( aRmJobSetup ) ) + { + PRINTERSEQ_GET( aRmJobSetup, aJobSetup ); + mbNewJobSetup = TRUE; + maJobSetup = aJobSetup; + ImplUpdatePageData(); + ImplUpdateFontList(); + return TRUE; + } + else + return FALSE; + } + return FALSE; +#endif +} + +// ----------------------------------------------------------------------- + +#ifdef REMOTE_APPSERVER +IMPL_LINK( Printer, UserSetupCompleted, ::com::sun::star::uno::Any*, pResult ) +{ + ::vos::OGuard guard( Application::GetSolarMutex( ) ); + + if( pResult->hasValue() ) + { + mbUserSetupResult = TRUE; + + ::com::sun::star::portal::client::RmJobSetup aRmJobSetup; + *pResult >>= aRmJobSetup; + JobSetup aJobSetup; + PRNSEQ_GET( aRmJobSetup, aJobSetup ); + + ImplUpdateJobSetupPaper( aJobSetup ); + mbNewJobSetup = TRUE; + maJobSetup = aJobSetup; + ImplUpdatePageData(); + ImplUpdateFontList(); + } + else + mbUserSetupResult = FALSE; + + mbUserSetupCompleted = TRUE; + return 0; +} +#endif + +BOOL Printer::Setup( Window* pWindow ) +{ + if ( IsDisplayPrinter() ) + return FALSE; + + if ( IsJobActive() || IsPrinting() ) + return FALSE; + +#ifndef REMOTE_APPSERVER + JobSetup aJobSetup = maJobSetup; + SalFrame* pFrame; + if ( !pWindow ) + pFrame = ImplGetDefaultWindow()->ImplGetFrame(); + else + pFrame = pWindow->ImplGetFrame(); + ImplReleaseGraphics(); + ImplSVData* pSVData = ImplGetSVData(); + pSVData->maAppData.mnModalMode++; + nImplSysDialog++; + BOOL bSetup = mpInfoPrinter->Setup( pFrame, aJobSetup.ImplGetData() ); + pSVData->maAppData.mnModalMode--; + nImplSysDialog--; + if ( bSetup ) + { + ImplUpdateJobSetupPaper( aJobSetup ); + mbNewJobSetup = TRUE; + maJobSetup = aJobSetup; + ImplUpdatePageData(); + ImplUpdateFontList(); + return TRUE; + } + return FALSE; +#else + NMSP_CLIENT::RmJobSetup aRmJobSetup; + PRNSEQ_SET( aRmJobSetup, maJobSetup ); + mpInfoPrinter->SetJobSetup( aRmJobSetup ); + RmFrameWindow* pFrame; + if ( !pWindow ) + pFrame = ImplGetDefaultWindow()->ImplGetFrame(); + else + pFrame = pWindow->ImplGetFrame(); + mbUserSetupCompleted = FALSE; + mpInfoPrinter->UserSetup( pFrame->GetFrameInterface(), pFrame->InsertUserEventLink( LINK( this, Printer, UserSetupCompleted ) ) ); + while( ! mbUserSetupCompleted ) + Application::Reschedule(); + return mbUserSetupResult; +#endif +} + +// ----------------------------------------------------------------------- + +BOOL Printer::SetPrinterProps( const Printer* pPrinter ) +{ + if ( IsJobActive() || IsPrinting() ) + return FALSE; + + ImplSVData* pSVData = ImplGetSVData(); + + mbDefPrinter = pPrinter->mbDefPrinter; + maPrintFile = pPrinter->maPrintFile; + mbPrintFile = pPrinter->mbPrintFile; + mnCopyCount = pPrinter->mnCopyCount; + mbCollateCopy = pPrinter->mbCollateCopy; + mnPageQueueSize = pPrinter->mnPageQueueSize; + + if ( pPrinter->IsDisplayPrinter() ) + { + // Alten Printer zerstoeren + if ( !IsDisplayPrinter() ) + { +#ifndef REMOTE_APPSERVER + ImplReleaseGraphics(); + pSVData->mpDefInst->DestroyInfoPrinter( mpInfoPrinter ); +#else + if ( mpInfoPrinter ) + { + if( mpGraphics ) + mpGraphics->SetInterface( REF( NMSP_CLIENT::XRmOutputDevice )() ); + + ImplReleaseServerGraphics(); + delete mpGraphics, mpGraphics = NULL; + delete mpInfoPrinter, mpInfoPrinter = NULL; + } +#endif + if ( mpFontEntry ) + { + mpFontCache->Release( mpFontEntry ); + mpFontEntry = NULL; + } + if ( mpGetDevFontList ) + { + delete mpGetDevFontList; + mpGetDevFontList = NULL; + } + if ( mpGetDevSizeList ) + { + delete mpGetDevSizeList; + mpGetDevSizeList = NULL; + } + delete mpFontList; + delete mpFontCache; + mbInitFont = TRUE; + mbNewFont = TRUE; + mpInfoPrinter = NULL; + } + + // Neuen Printer bauen + ImplInitDisplay( NULL ); + return TRUE; + } + + // Alten Printer zerstoeren? + if ( GetName() != pPrinter->GetName() ) + { +#ifndef REMOTE_APPSERVER + ImplReleaseGraphics(); +#endif + if ( mpDisplayDev ) + { + delete mpDisplayDev; + mpDisplayDev = NULL; + } + else + { +#ifndef REMOTE_APPSERVER + pSVData->mpDefInst->DestroyInfoPrinter( mpInfoPrinter ); +#else + if ( mpInfoPrinter ) + { + if( mpGraphics ) + mpGraphics->SetInterface( REF( NMSP_CLIENT::XRmOutputDevice )() ); + + ImplReleaseServerGraphics(); + delete mpGraphics, mpGraphics = NULL; + delete mpInfoPrinter, mpInfoPrinter = NULL; + } +#endif + + if ( mpFontEntry ) + { + mpFontCache->Release( mpFontEntry ); + mpFontEntry = NULL; + } + if ( mpGetDevFontList ) + { + delete mpGetDevFontList; + mpGetDevFontList = NULL; + } + if ( mpGetDevSizeList ) + { + delete mpGetDevSizeList; + mpGetDevSizeList = NULL; + } + delete mpFontList; + delete mpFontCache; + mbInitFont = TRUE; + mbNewFont = TRUE; + mpInfoPrinter = NULL; + } + + // Neuen Printer bauen + XubString maDriver = pPrinter->GetDriverName(); + SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( pPrinter->GetName(), &maDriver ); + if ( pInfo ) + { + ImplInit( pInfo ); + SetJobSetup( pPrinter->GetJobSetup() ); + } + else + ImplInitDisplay( NULL ); + } + else + SetJobSetup( pPrinter->GetJobSetup() ); + + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL Printer::SetOrientation( Orientation eOrientation ) +{ + if ( mbInPrintPage ) + return FALSE; + + if ( maJobSetup.ImplGetConstData()->meOrientation != eOrientation ) + { + JobSetup aJobSetup = maJobSetup; + ImplJobSetup* pSetupData = aJobSetup.ImplGetData(); + pSetupData->meOrientation = eOrientation; + + if ( IsDisplayPrinter() ) + { + mbNewJobSetup = TRUE; + maJobSetup = aJobSetup; + return TRUE; + } + +#ifndef REMOTE_APPSERVER + ImplReleaseGraphics(); + if ( mpInfoPrinter->SetData( SAL_JOBSET_ORIENTATION, pSetupData ) ) + { + ImplUpdateJobSetupPaper( aJobSetup ); +#else + NMSP_CLIENT::RmJobSetup aRmJobSetup; + PRINTERSEQ_SET( aJobSetup, aRmJobSetup, NMSP_CLIENT::RmJobSetup ); + if ( mpInfoPrinter->SetOrientation( (unsigned short)eOrientation, aRmJobSetup ) ) + { + PRINTERSEQ_GET( aRmJobSetup, aJobSetup ); +#endif + mbNewJobSetup = TRUE; + maJobSetup = aJobSetup; + ImplUpdatePageData(); + ImplUpdateFontList(); + return TRUE; + } + else + return FALSE; + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +Orientation Printer::GetOrientation() const +{ + return maJobSetup.ImplGetConstData()->meOrientation; +} + +// ----------------------------------------------------------------------- + +BOOL Printer::SetPaperBin( USHORT nPaperBin ) +{ + if ( mbInPrintPage ) + return FALSE; + + if ( (maJobSetup.ImplGetConstData()->mnPaperBin != nPaperBin) && + (nPaperBin < GetPaperBinCount()) ) + { + JobSetup aJobSetup = maJobSetup; + ImplJobSetup* pSetupData = aJobSetup.ImplGetData(); + pSetupData->mnPaperBin = nPaperBin; + + if ( IsDisplayPrinter() ) + { + mbNewJobSetup = TRUE; + maJobSetup = aJobSetup; + return TRUE; + } + +#ifndef REMOTE_APPSERVER + ImplReleaseGraphics(); + if ( mpInfoPrinter->SetData( SAL_JOBSET_PAPERBIN, pSetupData ) ) + { + ImplUpdateJobSetupPaper( aJobSetup ); +#else + NMSP_CLIENT::RmJobSetup aRmJobSetup; + PRINTERSEQ_SET( aJobSetup, aRmJobSetup, NMSP_CLIENT::RmJobSetup ); + if ( mpInfoPrinter->SetPaperBin( nPaperBin, aRmJobSetup ) ) + { + PRINTERSEQ_GET( aRmJobSetup, aJobSetup ); +#endif + mbNewJobSetup = TRUE; + maJobSetup = aJobSetup; + ImplUpdatePageData(); + ImplUpdateFontList(); + return TRUE; + } + else + return FALSE; + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +USHORT Printer::GetPaperBin() const +{ + return maJobSetup.ImplGetConstData()->mnPaperBin; +} + +// ----------------------------------------------------------------------- + +BOOL Printer::SetPaper( Paper ePaper ) +{ + if ( mbInPrintPage ) + return FALSE; + + if ( maJobSetup.ImplGetConstData()->mePaperFormat != ePaper ) + { + JobSetup aJobSetup = maJobSetup; + ImplJobSetup* pSetupData = aJobSetup.ImplGetData(); + pSetupData->mePaperFormat = ePaper; + if ( ePaper != PAPER_USER ) + { + pSetupData->mnPaperWidth = ImplPaperFormats[((USHORT)ePaper)*2]; + pSetupData->mnPaperHeight = ImplPaperFormats[((USHORT)ePaper)*2+1]; + } + + if ( IsDisplayPrinter() ) + { + mbNewJobSetup = TRUE; + maJobSetup = aJobSetup; + return TRUE; + } + +#ifndef REMOTE_APPSERVER + ImplReleaseGraphics(); + if ( mpInfoPrinter->SetData( SAL_JOBSET_PAPERSIZE, pSetupData ) ) + { + ImplUpdateJobSetupPaper( aJobSetup ); +#else + NMSP_CLIENT::RmJobSetup aRmJobSetup; + PRINTERSEQ_SET( aJobSetup, aRmJobSetup, NMSP_CLIENT::RmJobSetup ); + if ( mpInfoPrinter->SetPaper( (unsigned short)ePaper, aRmJobSetup ) ) + { + PRINTERSEQ_GET( aRmJobSetup, aJobSetup ); +#endif + mbNewJobSetup = TRUE; + maJobSetup = aJobSetup; + ImplUpdatePageData(); + ImplUpdateFontList(); + return TRUE; + } + else + return FALSE; + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +BOOL Printer::SetPaperSizeUser( const Size& rSize ) +{ + if ( mbInPrintPage ) + return FALSE; + + MapMode aMap100thMM( MAP_100TH_MM ); + Size aPixSize = LogicToPixel( rSize ); + Size aPageSize = PixelToLogic( aPixSize, aMap100thMM ); + if ( (maJobSetup.ImplGetConstData()->mePaperFormat != PAPER_USER) || + (maJobSetup.ImplGetConstData()->mnPaperWidth != aPageSize.Width()) || + (maJobSetup.ImplGetConstData()->mnPaperHeight != aPageSize.Height()) ) + { + JobSetup aJobSetup = maJobSetup; + ImplJobSetup* pSetupData = aJobSetup.ImplGetData(); + pSetupData->mePaperFormat = PAPER_USER; + pSetupData->mnPaperWidth = aPageSize.Width(); + pSetupData->mnPaperHeight = aPageSize.Height(); + + if ( IsDisplayPrinter() ) + { + mbNewJobSetup = TRUE; + maJobSetup = aJobSetup; + return TRUE; + } + +#ifndef REMOTE_APPSERVER + ImplReleaseGraphics(); + if ( mpInfoPrinter->SetData( SAL_JOBSET_PAPERSIZE, pSetupData ) ) + { + ImplUpdateJobSetupPaper( aJobSetup ); +#else + NMSP_CLIENT::RmJobSetup aRmJobSetup; + PRINTERSEQ_SET( aJobSetup, aRmJobSetup, NMSP_CLIENT::RmJobSetup ); + if ( mpInfoPrinter->SetPaperSizeUser( aPixSize.Width(), aPixSize.Height(), aRmJobSetup ) ) + { + PRINTERSEQ_GET( aRmJobSetup, aJobSetup ); +#endif + mbNewJobSetup = TRUE; + maJobSetup = aJobSetup; + ImplUpdatePageData(); + ImplUpdateFontList(); + return TRUE; + } + else + return FALSE; + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +Paper Printer::GetPaper() const +{ + return maJobSetup.ImplGetConstData()->mePaperFormat; +} + +// ----------------------------------------------------------------------- + +USHORT Printer::GetPaperBinCount() const +{ + if ( IsDisplayPrinter() ) + return 0; + +#ifndef REMOTE_APPSERVER + return (USHORT)mpInfoPrinter->GetPaperBinCount( maJobSetup.ImplGetConstData() ); +#else + if ( mpInfoPrinter ) + return mpInfoPrinter->GetPaperBinCount(); + else + return 0; +#endif +} + +// ----------------------------------------------------------------------- + +XubString Printer::GetPaperBinName( USHORT nPaperBin ) const +{ + if ( IsDisplayPrinter() ) + return ImplGetSVEmptyStr(); + +#ifndef REMOTE_APPSERVER + if ( nPaperBin < GetPaperBinCount() ) + return mpInfoPrinter->GetPaperBinName( maJobSetup.ImplGetConstData(), nPaperBin ); + else + return ImplGetSVEmptyStr(); +#else + if ( mpInfoPrinter ) + return (String)mpInfoPrinter->GetPaperBinName( nPaperBin ); + else + return ImplGetSVEmptyStr(); +#endif +} + +// ----------------------------------------------------------------------- + +BOOL Printer::SetCopyCount( USHORT nCopy, BOOL bCollate ) +{ + mnCopyCount = nCopy; + return TRUE; +} + +// ----------------------------------------------------------------------- + +void Printer::Error() +{ + maErrorHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Printer::StartPrint() +{ + maStartPrintHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Printer::EndPrint() +{ + maEndPrintHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Printer::PrintPage() +{ + maPrintPageHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +#ifndef REMOTE_APPSERVER + +ULONG ImplSalPrinterErrorCodeToVCL( ULONG nError ) +{ + ULONG nVCLError; + switch ( nError ) + { + case 0: + nVCLError = PRINTER_OK; + break; + case SAL_PRINTER_ERROR_ABORT: + nVCLError = PRINTER_ABORT; + break; + default: + nVCLError = PRINTER_GENERALERROR; + break; + } + + return nVCLError; +} + +// ----------------------------------------------------------------------- + +void Printer::ImplEndPrint() +{ + mbPrinting = FALSE; + mnCurPrintPage = 0; + maJobName.Erase(); + mpQPrinter->Destroy(); + mpQPrinter = NULL; + EndPrint(); +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( Printer, ImplDestroyPrinterAsync, void*, pSalPrinter ) +{ + SalPrinter* pPrinter = (SalPrinter*)pSalPrinter; + ImplSVData* pSVData = ImplGetSVData(); + pSVData->mpDefInst->DestroyPrinter( pPrinter ); + return 0; +} + +// ----------------------------------------------------------------------- + +#else + +// ----------------------------------------------------------------------- + +static void ImplDeletePrintSpooler( PrintSpooler* pPrintSpooler ) +{ + if( pPrintSpooler != 0 ) + { + pPrintSpooler->mxPrintSpooler = REF( NMSP_CLIENT::XRmPrintSpooler )(); + } +} + +#endif + +// ----------------------------------------------------------------------- + +BOOL Printer::StartJob( const XubString& rJobName ) +{ + mnError = PRINTER_OK; + + if ( IsDisplayPrinter() ) + return FALSE; + + if ( IsJobActive() || IsPrinting() ) + return FALSE; + +#ifndef REMOTE_APPSERVER + ULONG nCopies = mnCopyCount; + BOOL bCollateCopy = mbCollateCopy; + BOOL bUserCopy = FALSE; + if ( IsQueuePrinter() ) + { + if ( ((ImplQPrinter*)this)->IsUserCopy() ) + { + nCopies = 1; + bCollateCopy = FALSE; + } + } + else if ( nCopies > 1 ) + { + ULONG nDevCopy; + if ( bCollateCopy ) + nDevCopy = GetCapabilities( PRINTER_CAPABILITIES_COLLATECOPIES ); + else + nDevCopy = GetCapabilities( PRINTER_CAPABILITIES_COPIES ); + // Muessen Kopien selber gemacht werden? + if ( nCopies > nDevCopy ) + { + bUserCopy = TRUE; + nCopies = 1; + bCollateCopy = FALSE; + if ( !mnPageQueueSize ) + mnPageQueueSize = 1; + } + } + else + bCollateCopy = FALSE; + + if ( !mnPageQueueSize ) + { + ImplSVData* pSVData = ImplGetSVData(); + mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter ); + + if ( !mpPrinter ) + return FALSE; + + XubString* pPrintFile; + if ( mbPrintFile ) + pPrintFile = &maPrintFile; + else + pPrintFile = NULL; + + if ( !mpPrinter->StartJob( pPrintFile, rJobName, Application::GetDisplayName(), + nCopies, bCollateCopy, + maJobSetup.ImplGetConstData() ) ) + { + mnError = ImplSalPrinterErrorCodeToVCL( mpPrinter->GetErrorCode() ); + if ( !mnError ) + mnError = PRINTER_GENERALERROR; + ImplSVData* pSVData = ImplGetSVData(); + pSVData->mpDefInst->DestroyPrinter( mpPrinter ); + mpPrinter = NULL; + return FALSE; + } + + mbNewJobSetup = FALSE; + maJobName = rJobName; + mnCurPage = 1; + mnCurPrintPage = 1; + mbJobActive = TRUE; + mbPrinting = TRUE; + StartPrint(); + } + else + { + mpQPrinter = new ImplQPrinter( this ); + mpQPrinter->SetUserCopy( bUserCopy ); + if ( mpQPrinter->StartJob( rJobName ) ) + { + mbNewJobSetup = FALSE; + maJobName = rJobName; + mnCurPage = 1; + mbJobActive = TRUE; + mbPrinting = TRUE; + StartPrint(); + mpQPrinter->StartQueuePrint(); + } + else + { + mnError = mpQPrinter->GetErrorCode(); + mpQPrinter->Destroy(); + mpQPrinter = NULL; + return FALSE; + } + } +#else + BOOL bResult = FALSE; + ImplSVData* pSVData = ImplGetSVData(); + + String aServerName( maPrinterName.GetToken( 1, '@' ) ); + + // build a new connection if not client + Reference< ::com::sun::star::lang::XMultiServiceFactory > xServerFactory; + Reference< ::com::sun::star::connection::XConnection > xConnection; + Reference< ::com::sun::star::bridge::XBridgeFactory > xBridgeFactory; + + if( ! aServerName.EqualsAscii( RVP_CLIENT_SERVER_NAME ) ) + pSVData->mpRemotePrinterList->CreateNewPrinterConnection( maPrinterName.GetToken( 1, '@' ), xServerFactory, xConnection, xBridgeFactory ); + else + xServerFactory = pSVData->mxClientFactory; + if( xServerFactory.is() ) + { + REF( NMSP_CLIENT::XRmSpoolLauncher ) xLauncher( xServerFactory->createInstance( ::rtl::OUString::createFromAscii( "OfficeSpoolLauncher.stardiv.de" ) ), NMSP_UNO::UNO_QUERY ); + if( xLauncher.is() && + xLauncher->LaunchSpooler( pSVData->mpUserInfo->sName, + pSVData->mpUserInfo->sPassword ) ) + { + if( xBridgeFactory.is() ) // else this a the client connection + { + // get objects from transferred sospool connection + xServerFactory = Reference< ::com::sun::star::lang::XMultiServiceFactory >(); + Reference< ::com::sun::star::bridge::XBridge > + xBridge( xBridgeFactory->createBridge( ::rtl::OUString(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "iiop" ) ), xConnection, Reference< ::com::sun::star::bridge::XInstanceProvider >() ) ); + xServerFactory = Reference< ::com::sun::star::lang::XMultiServiceFactory >( xBridge->getInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SpoolMultiServiceFactory.sprintd.daemons.stardiv.de" ) ) ), UNO_QUERY ); + } + + mpPrinter = new PrintSpooler(); + mpPrinter->mxPrintSpooler = REF( NMSP_CLIENT::XRmPrintSpooler )( xServerFactory->createInstance( ::rtl::OUString::createFromAscii( "OfficePrintSpooler.stardiv.de" ) ), NMSP_UNO::UNO_QUERY ); + if( mpPrinter->mxPrintSpooler.is() ) + { + NMSP_CLIENT::RmJobSetup aRmJobSetup; + PRNSEQ_SET( aRmJobSetup, maJobSetup ); + mpPrinter->mxPrintSpooler->Create( aRmJobSetup ); + bResult = mpPrinter->mxPrintSpooler->StartJob( mnCopyCount, mbCollateCopy, rJobName, maPrintFile, mbPrintFile ); + } + } + + if ( bResult ) + { + mbNewJobSetup = FALSE; + maJobName = rJobName; + mnCurPage = 1; + mnCurPrintPage = 1; + mbJobActive = TRUE; + mbPrinting = TRUE; + } + else if ( mpPrinter && mpPrinter->mxPrintSpooler.is() ) + { + ImplDeletePrintSpooler( mpPrinter ); + mpPrinter = NULL; + } + } + + if ( !bResult ) + mnError = PRINTER_GENERALERROR; + + return bResult; +#endif + + return TRUE; +} + +// ----------------------------------------------------------------------- + +BOOL Printer::EndJob() +{ + if ( !IsJobActive() ) + return FALSE; + + DBG_ASSERT( !mbInPrintPage, "Printer::EndJob() - StartPage() without EndPage() called" ); + + mbJobActive = FALSE; + +#ifndef REMOTE_APPSERVER + if ( mpPrinter || mpQPrinter ) + { + ImplReleaseGraphics(); + + mnCurPage = 0; + + if ( mpPrinter ) + { + mbPrinting = FALSE; + mnCurPrintPage = 0; + maJobName.Erase(); + + mbDevOutput = FALSE; + mpPrinter->EndJob(); + // Hier den Drucker nicht asyncron zerstoeren, da es + // W95 nicht verkraftet, wenn gleichzeitig gedruckt wird + // und ein Druckerobjekt zerstoert wird + ImplGetSVData()->mpDefInst->DestroyPrinter( mpPrinter ); + mpPrinter = NULL; + EndPrint(); + } + else + mpQPrinter->EndQueuePrint(); + + return TRUE; + } +#else + if ( mpPrinter ) + { + mpPrinter->mxPrintSpooler->EndJob(); + mbPrinting = FALSE; + mnCurPage = 0; + mnCurPrintPage = 0; + maJobName.Erase(); + EndPrint(); + + ImplDeletePrintSpooler( mpPrinter ); + mpPrinter = NULL; + + return TRUE; + } +#endif + + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL Printer::AbortJob() +{ + // Wenn wir einen Queue-Printer haben, kann man diesen noch mit + // AbortJob() abbrechen, solange dieser noch am Drucken ist + if ( !IsJobActive() && !IsPrinting() ) + return FALSE; + + mbJobActive = FALSE; + mbInPrintPage = FALSE; + mpJobGraphics = NULL; + +#ifndef REMOTE_APPSERVER + if ( mpPrinter || mpQPrinter ) + { + mbPrinting = FALSE; + mnCurPage = 0; + mnCurPrintPage = 0; + maJobName.Erase(); + + if ( mpPrinter ) + { + ImplReleaseGraphics(); + mbDevOutput = FALSE; + mpPrinter->AbortJob(); + Application::PostUserEvent( LINK( this, Printer, ImplDestroyPrinterAsync ), mpPrinter ); + mpPrinter = NULL; + EndPrint(); + } + else + { + mpQPrinter->AbortQueuePrint(); + mpQPrinter->Destroy(); + mpQPrinter = NULL; + if ( mpQMtf ) + { + mpQMtf->Clear(); + delete mpQMtf; + mpQMtf = NULL; + } + EndPrint(); + } + + return TRUE; + } +#else + if ( mpPrinter ) + { + mpPrinter->mxPrintSpooler->AbortJob(); + if ( mpQMtf ) + { + mpQMtf->Clear(); + delete mpQMtf; + mpQMtf = NULL; + } + + mbPrinting = FALSE; + mnCurPage = 0; + mnCurPrintPage = 0; + maJobName.Erase(); + ImplDeletePrintSpooler( mpPrinter ); + mpPrinter = NULL; + EndPrint(); + + return TRUE; + } +#endif + + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL Printer::StartPage() +{ + if ( !IsJobActive() ) + return FALSE; + +#ifndef REMOTE_APPSERVER + if ( mpPrinter || mpQPrinter ) + { + if ( mpPrinter ) + { + SalGraphics* pGraphics = mpPrinter->StartPage( maJobSetup.ImplGetConstData(), mbNewJobSetup ); + if ( pGraphics ) + { + ImplReleaseGraphics(); + mpJobGraphics = pGraphics; + } + mbDevOutput = TRUE; + } + else + { + ImplGetGraphics(); + mpJobGraphics = mpGraphics; + } + + // PrintJob not aborted ??? + if ( IsJobActive() ) + { + mbInPrintPage = TRUE; + mnCurPage++; + if ( mpQPrinter ) + { + mpQMtf = new GDIMetaFile; + mpQMtf->Record( this ); + mpQMtf->SaveStatus(); + } + else + { + mnCurPrintPage++; + PrintPage(); + } + } + + return TRUE; + } +#else + if ( mpPrinter ) + { + mpQMtf = new GDIMetaFile; + mpQMtf->Record( this ); + mpQMtf->SaveStatus(); + + mbInPrintPage = TRUE; + mnCurPage++; + mnCurPrintPage++; + PrintPage(); + + return TRUE; + } +#endif + + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL Printer::EndPage() +{ + if ( !IsJobActive() ) + return FALSE; + + mbInPrintPage = FALSE; + +#ifndef REMOTE_APPSERVER + if ( mpPrinter || mpQPrinter ) + { + if ( mpPrinter ) + { + mpPrinter->EndPage(); + ImplReleaseGraphics(); + mbDevOutput = FALSE; + } + else if ( mpQPrinter ) + { + // Eigentuemeruebergang an QPrinter + mpQMtf->Stop(); + mpQMtf->WindStart(); + GDIMetaFile* pPage = mpQMtf; + mpQMtf = NULL; + mpQPrinter->AddQueuePage( pPage, mnCurPage, mbNewJobSetup ); + } + + mpJobGraphics = NULL; + mbNewJobSetup = FALSE; + + return TRUE; + } +#else + if ( mpPrinter && mpQMtf ) + { + mpQMtf->Stop(); + mpQMtf->WindStart(); + + PrinterPage aPage( mpQMtf, mbNewJobSetup, GetJobSetup() ); + NMSP_CLIENT::RmPrinterPage aRmPage; + PRINTERSEQ_SET( aPage, aRmPage, NMSP_CLIENT::RmPrinterPage ); + mpPrinter->mxPrintSpooler->SpoolPage( aRmPage ); + mpQMtf = NULL; + mbNewJobSetup = FALSE; + + return TRUE; + } +#endif + + return FALSE; +} diff --git a/vcl/source/gdi/print2.cxx b/vcl/source/gdi/print2.cxx new file mode 100644 index 000000000000..9e301b906012 --- /dev/null +++ b/vcl/source/gdi/print2.cxx @@ -0,0 +1,543 @@ +/************************************************************************* + * + * $RCSfile: print2.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_PRINT_CXX +#define _SPOOLPRINTER_EXT + +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _SV_VIRDEV_HXX +#include <virdev.hxx> +#endif +#ifndef _SV_METAACT_HXX +#include <metaact.hxx> +#endif +#ifndef _SV_GDIMTF_HXX +#include <gdimtf.hxx> +#endif +#ifndef _SV_PRINT_H +#include <print.h> +#endif +#ifndef _SV_PRINT_HXX +#include <print.hxx> +#endif +#ifndef _SV_SVAPP_HXX +#include <svapp.hxx> +#endif + +// ----------- +// - Defines - +// ----------- + +#define MAX_BANDWIDTH 1000000 + +// ----------- +// - statics - +// ----------- + +static USHORT aSpecialPrintActions[] = +{ + META_TRANSPARENT_ACTION, + META_FLOATTRANSPARENT_ACTION +}; + +// ----------------- +// - ImplCheckRect - +// ----------------- + +struct ImplCheckRect +{ + Rectangle* mpRect; + MetaAction* mpAct; + ImplCheckRect* mpNext; + BOOL mbSpecialOutput; + + ImplCheckRect() { } + ~ImplCheckRect() { delete mpRect; } + void ImplCreate( MetaAction* pAct, OutputDevice* pOut, BOOL bSpecial ); + BOOL Intersects( const ImplCheckRect& rRect ) + { + return( mpRect && rRect.mpRect ) ? mpRect->IsOver( *rRect.mpRect ) : FALSE; + } +}; + +// ----------------------------------------------------------------------------- + +void ImplCheckRect::ImplCreate( MetaAction* pAct, OutputDevice* pOut, BOOL bSpecial ) +{ + mpAct = pAct; + mpNext = NULL; + + switch( mpAct->GetType() ) + { + case( META_PIXEL_ACTION ): + mpRect = new Rectangle( ( (MetaPixelAction*) mpAct )->GetPoint(), Size( 1, 1 ) ); + break; + + case( META_POINT_ACTION ): + mpRect = new Rectangle( ( (MetaPointAction*) mpAct )->GetPoint(), Size( 1, 1 ) ); + break; + + case( META_LINE_ACTION ): + { + MetaLineAction* pA = (MetaLineAction*) mpAct; + mpRect = new Rectangle( pA->GetStartPoint(), pA->GetEndPoint() ); + } + break; + + case( META_RECT_ACTION ): + mpRect = new Rectangle( ( (MetaRectAction*) mpAct )->GetRect() ); + break; + + case( META_ROUNDRECT_ACTION ): + { + MetaRoundRectAction* pA = (MetaRoundRectAction*) mpAct; + mpRect = new Rectangle( Polygon( pA->GetRect(), + pA->GetHorzRound(), + pA->GetVertRound() ).GetBoundRect() ); + } + break; + + case( META_ELLIPSE_ACTION ): + { + MetaEllipseAction* pA = (MetaEllipseAction*) mpAct; + const Rectangle& rRect = pA->GetRect(); + mpRect = new Rectangle( Polygon( rRect.Center(), + rRect.GetWidth() >> 1, + rRect.GetHeight() >> 1 ).GetBoundRect() ); + } + break; + + case( META_ARC_ACTION ): + { + MetaArcAction* pA = (MetaArcAction*) mpAct; + mpRect = new Rectangle( Polygon( pA->GetRect(), + pA->GetStartPoint(), + pA->GetEndPoint(), POLY_ARC ).GetBoundRect() ); + } + break; + + case( META_PIE_ACTION ): + { + MetaPieAction* pA = (MetaPieAction*) mpAct; + mpRect = new Rectangle( Polygon( pA->GetRect(), + pA->GetStartPoint(), + pA->GetEndPoint(), POLY_PIE ).GetBoundRect() ); + } + break; + + case( META_CHORD_ACTION ): + { + MetaChordAction* pA = (MetaChordAction*) mpAct; + mpRect = new Rectangle( Polygon( pA->GetRect(), + pA->GetStartPoint(), + pA->GetEndPoint(), POLY_CHORD ).GetBoundRect() ); + } + break; + + case( META_POLYLINE_ACTION ): + { + MetaPolyLineAction* pA = (MetaPolyLineAction*) mpAct; + mpRect = new Rectangle( pA->GetPolygon().GetBoundRect() ); + } + break; + + case( META_POLYGON_ACTION ): + { + MetaPolygonAction* pA = (MetaPolygonAction*) mpAct; + mpRect = new Rectangle( pA->GetPolygon().GetBoundRect() ); + } + break; + + case( META_POLYPOLYGON_ACTION ): + { + MetaPolyPolygonAction* pA = (MetaPolyPolygonAction*) mpAct; + mpRect = new Rectangle( pA->GetPolyPolygon().GetBoundRect() ); + } + break; + + case( META_BMP_ACTION ): + { + MetaBmpAction* pA = (MetaBmpAction*) mpAct; + mpRect = new Rectangle( pA->GetPoint(), pOut->PixelToLogic( pA->GetBitmap().GetSizePixel() ) ); + } + break; + + case( META_BMPSCALE_ACTION ): + { + MetaBmpScaleAction* pA = (MetaBmpScaleAction*) mpAct; + mpRect = new Rectangle( pA->GetPoint(), pA->GetSize() ); + } + break; + + case( META_BMPSCALEPART_ACTION ): + { + MetaBmpScalePartAction* pA = (MetaBmpScalePartAction*) mpAct; + mpRect = new Rectangle( pA->GetDestPoint(), pA->GetDestSize() ); + } + break; + + case( META_BMPEX_ACTION ): + { + MetaBmpExAction* pA = (MetaBmpExAction*) mpAct; + mpRect = new Rectangle( pA->GetPoint(), pOut->PixelToLogic( pA->GetBitmapEx().GetSizePixel() ) ); + } + break; + + case( META_BMPEXSCALE_ACTION ): + { + MetaBmpExScaleAction* pA = (MetaBmpExScaleAction*) mpAct; + mpRect = new Rectangle( pA->GetPoint(), pA->GetSize() ); + } + break; + + case( META_BMPEXSCALEPART_ACTION ): + { + MetaBmpExScalePartAction* pA = (MetaBmpExScalePartAction*) mpAct; + mpRect = new Rectangle( pA->GetDestPoint(), pA->GetDestSize() ); + } + break; + + case( META_MASK_ACTION ): + { + MetaMaskAction* pA = (MetaMaskAction*) mpAct; + mpRect = new Rectangle( pA->GetPoint(), pOut->PixelToLogic( pA->GetBitmap().GetSizePixel() ) ); + } + break; + + case( META_MASKSCALE_ACTION ): + { + MetaMaskScaleAction* pA = (MetaMaskScaleAction*) mpAct; + mpRect = new Rectangle( pA->GetPoint(), pA->GetSize() ); + } + break; + + case( META_MASKSCALEPART_ACTION ): + { + MetaMaskScalePartAction* pA = (MetaMaskScalePartAction*) mpAct; + mpRect = new Rectangle( pA->GetDestPoint(), pA->GetDestSize() ); + } + break; + + case( META_GRADIENT_ACTION ): + mpRect = new Rectangle( ( (MetaGradientAction*) mpAct )->GetRect() ); + break; + + case( META_HATCH_ACTION ): + mpRect = new Rectangle( ( (MetaHatchAction*) mpAct )->GetPolyPolygon().GetBoundRect() ); + break; + + case( META_WALLPAPER_ACTION ): + mpRect = new Rectangle( ( (MetaWallpaperAction*) mpAct )->GetRect() ); + break; + + case( META_TRANSPARENT_ACTION ): + mpRect = new Rectangle( ( (MetaTransparentAction*) mpAct )->GetPolyPolygon().GetBoundRect() ); + break; + + case( META_FLOATTRANSPARENT_ACTION ): + { + MetaFloatTransparentAction* pA = (MetaFloatTransparentAction*) mpAct; + mpRect = new Rectangle( pA->GetPoint(), pA->GetSize() ); + } + break; + + case( META_EPS_ACTION ): + { + MetaEPSAction* pA = (MetaEPSAction*) mpAct; + mpRect = new Rectangle( pA->GetPoint(), pA->GetSize() ); + } + break; + + case( META_TEXT_ACTION ): + { + MetaTextAction* pA = (MetaTextAction*) mpAct; + const Point aPt( pOut->LogicToPixel( pA->GetPoint() ) ); + const XubString aString( pA->GetText(), pA->GetIndex(), pA->GetLen() ); + mpRect = new Rectangle( pOut->PixelToLogic( pOut->ImplGetTextBoundRect( aPt.X(), aPt.Y(), aString.GetBuffer(), aString.Len(), NULL ) ) ); + } + break; + + case( META_TEXTARRAY_ACTION ): + { + MetaTextArrayAction* pA = (MetaTextArrayAction*) mpAct; + const Point aPt( pOut->LogicToPixel( pA->GetPoint() ) ); + const XubString aString( pA->GetText(), pA->GetIndex(), pA->GetLen() ); + mpRect = new Rectangle( pOut->PixelToLogic( pOut->ImplGetTextBoundRect( aPt.X(), aPt.Y(), aString.GetBuffer(), aString.Len(), pA->GetDXArray() ) ) ); + } + break; + + case( META_TEXTRECT_ACTION ): + { + MetaTextRectAction* pA = (MetaTextRectAction*) mpAct; + mpRect = new Rectangle( pA->GetRect() ); + } + break; + + case( META_STRETCHTEXT_ACTION ): + case( META_TEXTLINE_ACTION ): + mpRect = NULL; + // !!! DBG_ERROR( "Missing" ); + break; + + default: + mpRect = NULL; + break; + } + + if( mpRect ) + { + *mpRect = pOut->LogicToPixel( *mpRect ); + mbSpecialOutput = bSpecial; + } + else + mbSpecialOutput = FALSE; +} + +// ----------- +// - Printer - +// ----------- + +void Printer::GetPreparedMetaFile( const GDIMetaFile& rInMtf, GDIMetaFile& rOutMtf, ULONG nFlags ) +{ + const ULONG nSpecialCount = sizeof( aSpecialPrintActions ) / sizeof( aSpecialPrintActions[ 0 ] ); + MetaAction* pAct; + ULONG i, j; + BOOL bSpecial = FALSE; + + rOutMtf.Clear(); + + // look, if we've got special actions + for( pAct = ( (GDIMetaFile&) rInMtf ).FirstAction(); pAct && !bSpecial; pAct = ( (GDIMetaFile&) rInMtf ).NextAction() ) + for( i = 0; i < nSpecialCount; i++ ) + if( pAct->GetType() == aSpecialPrintActions[ i ] ) + bSpecial = TRUE; + + // separate actions which are special actions or which are affected by special actions + if( bSpecial ) + { + Rectangle aBoundPixel; + const ULONG nCount = rInMtf.GetActionCount(); + VirtualDevice aPaintVDev; + ImplCheckRect* pRects = new ImplCheckRect[ nCount ]; + ImplCheckRect* pIListFirst = NULL; + ImplCheckRect* pIListPrev = NULL; + ImplCheckRect* pIListAct = NULL; + ImplCheckRect* pOListFirst = NULL; + ImplCheckRect* pOListLast = NULL; + ImplCheckRect* pOListAct = NULL; + ImplCheckRect* pO; + + aPaintVDev.mnDPIX = mnDPIX; + aPaintVDev.mnDPIY = mnDPIY; + aPaintVDev.mbOutput = FALSE; + + // create list of special action rects + for( i = 0, pO = pRects, pAct = ( (GDIMetaFile&) rInMtf ).FirstAction(); pAct; + pAct = ( (GDIMetaFile&) rInMtf ).NextAction(), i++, pO++ ) + { + for( j = 0, bSpecial = FALSE; j < nSpecialCount && !bSpecial; j++ ) + if( pAct->GetType() == aSpecialPrintActions[ j ] ) + bSpecial = TRUE; + + // execute action to get correct MapMode's etc. + pAct->Execute( &aPaintVDev ); + + // create (bounding) rect object + pO->ImplCreate( pAct, &aPaintVDev, bSpecial ); + + // add object to one of the lists + if( pO->mbSpecialOutput ) + { + if( !pOListFirst ) + pOListFirst = pOListAct = pOListLast = pO; + else + pOListAct = pOListAct->mpNext = pOListLast = pO; + } + else + { + if( !pIListFirst ) + pIListFirst = pIListAct = pO; + else + pIListAct = pIListAct->mpNext = pO; + } + } + + // find all intersections and create list of (bitmap) + for( pO = pOListFirst; pO; pO = pO->mpNext ) + { + pIListPrev = NULL, pIListAct = pIListFirst; + + while( pIListAct ) + { + // move act object from in list to out list? + if( pIListAct->Intersects( *pO ) ) + { + // mark it as special object + pIListAct->mbSpecialOutput = TRUE; + + if( pIListPrev ) + pIListPrev->mpNext = pIListAct->mpNext; + else + pIListFirst = pIListAct->mpNext; + + pOListLast = pOListLast->mpNext = pIListAct; + } + else + pIListPrev = pIListAct; + + pIListAct = pIListAct->mpNext; + pOListLast->mpNext = NULL; + } + } + + // calculate bounding rectangle of special actions + for( pO = pOListFirst; pO; pO = pO->mpNext ) + aBoundPixel.Union( *pO->mpRect ); + + const Size aSzPix( aBoundPixel.GetSize() ); + + // create new bitmap action first + if( aSzPix.Width() && aSzPix.Height() ) + { + Point aDstPtPix( aBoundPixel.TopLeft() ); + Size aDstSzPix( aSzPix.Width(), Max( MAX_BANDWIDTH / aSzPix.Width(), 2L ) ); + const long nLastY = aDstPtPix.Y() + aSzPix.Height() - 1L; + VirtualDevice aMapVDev; + + rOutMtf.AddAction( new MetaPushAction( PUSH_MAPMODE ) ); + rOutMtf.AddAction( new MetaMapModeAction() ); + + aPaintVDev.mbOutput = TRUE; + aMapVDev.mbOutput = FALSE; + + while( aDstPtPix.Y() <= nLastY ) + { + if( ( aDstPtPix.Y() + aDstSzPix.Height() - 1L ) > nLastY ) + aDstSzPix.Height() = nLastY - aDstPtPix.Y() + 1L; + + if( aPaintVDev.SetOutputSizePixel( aDstSzPix ) ) + { + aPaintVDev.Push(); + aMapVDev.Push(); + + aMapVDev.mnDPIX = aPaintVDev.mnDPIX = mnDPIX; + aMapVDev.mnDPIY = aPaintVDev.mnDPIY = mnDPIY; + + for( i = 0, pO = pRects; i < nCount; i++, pO++ ) + { + MetaAction* pAction = pO->mpAct; + const USHORT nType = pAction->GetType(); + + if( META_MAPMODE_ACTION == nType ) + { + pAction->Execute( &aMapVDev ); + + MapMode aMtfMap( aMapVDev.GetMapMode() ); + const Point aNewOrg( aMapVDev.PixelToLogic( aDstPtPix ) ); + + aMtfMap.SetOrigin( Point( -aNewOrg.X(), -aNewOrg.Y() ) ); + aPaintVDev.SetMapMode( aMtfMap ); + } + else if( ( META_PUSH_ACTION == nType ) || ( META_POP_ACTION ) == nType ) + { + pAction->Execute( &aMapVDev ); + pAction->Execute( &aPaintVDev ); + } + else + pAction->Execute( &aPaintVDev ); + + if( !( i % 4 ) ) + Application::Reschedule(); + } + + aPaintVDev.mbMap = FALSE; + Bitmap aBandBmp( aPaintVDev.GetBitmap( Point(), aDstSzPix ) ); +#ifdef DEBUG + aBandBmp.Invert(); +#endif + rOutMtf.AddAction( new MetaBmpScaleAction( aDstPtPix, aDstSzPix, aBandBmp ) ); + aPaintVDev.mbMap = TRUE; + + aMapVDev.Pop(); + aPaintVDev.Pop(); + } + + // overlapping bands to avoid missing lines (e.g. PostScript) + aDstPtPix.Y() += aDstSzPix.Height(); + } + + rOutMtf.AddAction( new MetaPopAction() ); + } + + // add normal actions + for( i = 0, pO = pRects; i < nCount; i++, pO++ ) + if( !pO->mbSpecialOutput ) + rOutMtf.AddAction( ( pO->mpAct->Duplicate(), pO->mpAct ) ); + + rOutMtf.SetPrefMapMode( rInMtf.GetPrefMapMode() ); + rOutMtf.SetPrefSize( rInMtf.GetPrefSize() ); + delete[] pRects; + } + else + rOutMtf = rInMtf; +} diff --git a/vcl/source/gdi/regband.cxx b/vcl/source/gdi/regband.cxx new file mode 100644 index 000000000000..51a0a366727b --- /dev/null +++ b/vcl/source/gdi/regband.cxx @@ -0,0 +1,785 @@ +/************************************************************************* + * + * $RCSfile: regband.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_REGBAND_CXX + +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _SV_SALBTYPE_HXX +#include <salbtype.hxx> +#endif +#ifndef _SV_REGBAND_HXX +#include <regband.hxx> +#endif + +// ======================================================================= +// +// ImplRegionBand +// +// Jedes Band enthaelt die zwischen der enthaltenen Ober- und Untergrenze +// enthaltenen Rechtecke. Bei den Operationen Union, Intersect, XOr und +// Exclude werden immer Rechtecke der gleichen Hoehe ausgewerte; die +// Grenzen der Baender sind immer so zu waehlen, dasz dies moeglich ist. +// +// Die Rechtecke in den Baendern werden nach Moeglichkeit zusammengefaszt. +// +// Bei der Umwandlung von Polygonen werden alle Punkte des Polygons +// in die einzelnen Baender eingetragen (sie stehen fuer jedes Band als +// Punkte in einer Liste). Nach dem Eintragen der Punkte werden diese +// in Rechtecke umgewandelt und die Liste der Punkte geloescht. +// +// ----------------------------------------------------------------------- + +ImplRegionBand::ImplRegionBand( long nTop, long nBottom ) +{ + // save boundaries + mnYTop = nTop; + mnYBottom = nBottom; + + // initialize lists + mpNextBand = NULL; + mpPrevBand = NULL; + mpFirstSep = NULL; + mpFirstBandPoint = NULL; + mbTouched = FALSE; +} + +// ----------------------------------------------------------------------- + +ImplRegionBand::ImplRegionBand( const ImplRegionBand& rRegionBand ) +{ + // copy boundaries + mnYTop = rRegionBand.mnYTop; + mnYBottom = rRegionBand.mnYBottom; + mbTouched = rRegionBand.mbTouched; + + // initialisation + mpNextBand = NULL; + mpPrevBand = NULL; + mpFirstSep = NULL; + mpFirstBandPoint = NULL; + + // copy all elements of the list with separations + ImplRegionBandSep* pNewSep; + ImplRegionBandSep* pPrevSep; + ImplRegionBandSep* pSep = rRegionBand.mpFirstSep; + while ( pSep ) + { + // create new and copy data + pNewSep = new ImplRegionBandSep; + pNewSep->mnXLeft = pSep->mnXLeft; + pNewSep->mnXRight = pSep->mnXRight; + pNewSep->mbRemoved = pSep->mbRemoved; + pNewSep->mpNextSep = NULL; + if ( pSep == rRegionBand.mpFirstSep ) + mpFirstSep = pNewSep; + else + pPrevSep->mpNextSep = pNewSep; + + pPrevSep = pNewSep; + pSep = pSep->mpNextSep; + } +} + +// ----------------------------------------------------------------------- + +ImplRegionBand::~ImplRegionBand() +{ + DBG_ASSERT( mpFirstBandPoint == NULL, "ImplRegionBand::~ImplRegionBand -> pointlist not empty" ); + + // delete elements of the list + ImplRegionBandSep* pSep = mpFirstSep; + while ( pSep ) + { + ImplRegionBandSep* pTempSep = pSep->mpNextSep; + delete pSep; + pSep = pTempSep; + } + + // delete elements of the list + ImplRegionBandPoint* pPoint = mpFirstBandPoint; + while ( pPoint ) + { + ImplRegionBandPoint* pTempPoint = pPoint->mpNextBandPoint; + delete pPoint; + pPoint = pTempPoint; + } +} + +// ----------------------------------------------------------------------- +// +// generate separations from lines and process union with existing +// separations + +void ImplRegionBand::ProcessPoints() +{ + // check Pointlist + ImplRegionBandPoint* pRegionBandPoint = mpFirstBandPoint; + while ( pRegionBandPoint ) + { + // within list? + if ( pRegionBandPoint && pRegionBandPoint->mpNextBandPoint ) + { + // start/stop? + if ( pRegionBandPoint->mbEndPoint && pRegionBandPoint->mpNextBandPoint->mbEndPoint ) + { + // same direction? -> remove next point! + if ( pRegionBandPoint->meLineType == pRegionBandPoint->mpNextBandPoint->meLineType ) + { + ImplRegionBandPoint* pSaveRegionBandPoint = pRegionBandPoint->mpNextBandPoint; + pRegionBandPoint->mpNextBandPoint = pRegionBandPoint->mpNextBandPoint->mpNextBandPoint; + delete pSaveRegionBandPoint; + } + } + } + + // continue with next element in the list + pRegionBandPoint = pRegionBandPoint->mpNextBandPoint; + } + + pRegionBandPoint = mpFirstBandPoint; + while ( pRegionBandPoint && pRegionBandPoint->mpNextBandPoint ) + { + Union( pRegionBandPoint->mnX, pRegionBandPoint->mpNextBandPoint->mnX ); + + ImplRegionBandPoint* pNextBandPoint = pRegionBandPoint->mpNextBandPoint->mpNextBandPoint; + + // remove allready processed points + delete pRegionBandPoint->mpNextBandPoint; + delete pRegionBandPoint; + + // continue with next element in the list + pRegionBandPoint = pNextBandPoint; + } + + // remove last element if necessary + if ( pRegionBandPoint ) + delete pRegionBandPoint; + + // list is now empty + mpFirstBandPoint = NULL; +} + +// ----------------------------------------------------------------------- +// +// generate separations from lines and process union with existing +// separations + +BOOL ImplRegionBand::InsertPoint( long nX, long nLineId, + BOOL bEndPoint, LineType eLineType ) +{ + if ( !mpFirstBandPoint ) + { + mpFirstBandPoint = new ImplRegionBandPoint; + mpFirstBandPoint->mnX = nX; + mpFirstBandPoint->mnLineId = nLineId; + mpFirstBandPoint->mbEndPoint = bEndPoint; + mpFirstBandPoint->meLineType = eLineType; + mpFirstBandPoint->mpNextBandPoint = NULL; + return TRUE; + } + + // look if line allready touched the band + ImplRegionBandPoint* pRegionBandPoint = mpFirstBandPoint; + ImplRegionBandPoint* pLastTestedRegionBandPoint = NULL; + while( pRegionBandPoint ) + { + if ( pRegionBandPoint->mnLineId == nLineId ) + { + if ( bEndPoint ) + { + if( !pRegionBandPoint->mbEndPoint ) + { + // remove old band point + if( !mpFirstBandPoint->mpNextBandPoint ) + { + // if we've only got one point => replace first point + pRegionBandPoint->mnX = nX; + pRegionBandPoint->mbEndPoint = TRUE; + return TRUE; + } + else + { + // remove current point + if( !pLastTestedRegionBandPoint ) + { + // remove and delete old first point + ImplRegionBandPoint* pSaveBandPoint = mpFirstBandPoint; + mpFirstBandPoint = mpFirstBandPoint->mpNextBandPoint; + delete pSaveBandPoint; + } + else + { + // remove and delete current band point + pLastTestedRegionBandPoint->mpNextBandPoint = pRegionBandPoint->mpNextBandPoint; + delete pRegionBandPoint; + } + + break; + } + } + } + else + return FALSE; + } + + // use next element + pLastTestedRegionBandPoint = pRegionBandPoint; + pRegionBandPoint = pRegionBandPoint->mpNextBandPoint; + } + + // search appropriate position and insert point into the list + ImplRegionBandPoint* pNewRegionBandPoint; + + pRegionBandPoint = mpFirstBandPoint; + pLastTestedRegionBandPoint = NULL; + while ( pRegionBandPoint ) + { + // new point completly left? -> insert as first point + if ( nX <= pRegionBandPoint->mnX ) + { + pNewRegionBandPoint = new ImplRegionBandPoint; + pNewRegionBandPoint->mnX = nX; + pNewRegionBandPoint->mnLineId = nLineId; + pNewRegionBandPoint->mbEndPoint = bEndPoint; + pNewRegionBandPoint->meLineType = eLineType; + pNewRegionBandPoint->mpNextBandPoint = pRegionBandPoint; + + // connections to the new point + if ( !pLastTestedRegionBandPoint ) + mpFirstBandPoint = pNewRegionBandPoint; + else + pLastTestedRegionBandPoint->mpNextBandPoint = pNewRegionBandPoint; + + return TRUE; + } + + // use next element + pLastTestedRegionBandPoint = pRegionBandPoint; + pRegionBandPoint = pRegionBandPoint->mpNextBandPoint; + } + + // not inserted -> add to the end of the list + pNewRegionBandPoint = new ImplRegionBandPoint; + pNewRegionBandPoint->mnX = nX; + pNewRegionBandPoint->mnLineId = nLineId; + pNewRegionBandPoint->mbEndPoint = bEndPoint; + pNewRegionBandPoint->meLineType = eLineType; + pNewRegionBandPoint->mpNextBandPoint = NULL; + + // connections to the new point + pLastTestedRegionBandPoint->mpNextBandPoint = pNewRegionBandPoint; + + return TRUE; +} + +// ----------------------------------------------------------------------- + +void ImplRegionBand::MoveX( long nHorzMove ) +{ + // move all x-separations + ImplRegionBandSep* pSep = mpFirstSep; + while ( pSep ) + { + pSep->mnXLeft += nHorzMove; + pSep->mnXRight += nHorzMove; + pSep = pSep->mpNextSep; + } +} + +// ----------------------------------------------------------------------- + +void ImplRegionBand::ScaleX( double fHorzScale ) +{ + ImplRegionBandSep* pSep = mpFirstSep; + while ( pSep ) + { + pSep->mnXLeft = FRound( pSep->mnXLeft * fHorzScale ); + pSep->mnXRight = FRound( pSep->mnXRight * fHorzScale ); + pSep = pSep->mpNextSep; + } +} + +// ----------------------------------------------------------------------- +// +// combine overlaping sparations + +BOOL ImplRegionBand::OptimizeBand() +{ + ImplRegionBandSep* pPrevSep; + ImplRegionBandSep* pSep = mpFirstSep; + while ( pSep ) + { + // remove? + if ( pSep->mbRemoved || (pSep->mnXRight < pSep->mnXLeft) ) + { + ImplRegionBandSep* pOldSep = pSep; + if ( pSep == mpFirstSep ) + mpFirstSep = pSep->mpNextSep; + else + pPrevSep->mpNextSep = pSep->mpNextSep; + pSep = pSep->mpNextSep; + delete pOldSep; + continue; + } + + // overlaping separations? -> combine! + if ( pSep->mpNextSep ) + { + if ( (pSep->mnXRight+1) >= pSep->mpNextSep->mnXLeft ) + { + if ( pSep->mpNextSep->mnXRight > pSep->mnXRight ) + pSep->mnXRight = pSep->mpNextSep->mnXRight; + + ImplRegionBandSep* pOldSep = pSep->mpNextSep; + pSep->mpNextSep = pOldSep->mpNextSep; + delete pOldSep; + continue; + } + } + + pPrevSep = pSep; + pSep = pSep->mpNextSep; + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +void ImplRegionBand::Union( long nXLeft, long nXRight ) +{ + DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::Union(): nxLeft > nXRight" ); + + // band empty? -> add element + if ( !mpFirstSep ) + { + mpFirstSep = new ImplRegionBandSep; + mpFirstSep->mnXLeft = nXLeft; + mpFirstSep->mnXRight = nXRight; + mpFirstSep->mbRemoved = FALSE; + mpFirstSep->mpNextSep = NULL; + return; + } + + // process real union + ImplRegionBandSep* pNewSep; + ImplRegionBandSep* pPrevSep; + ImplRegionBandSep* pSep = mpFirstSep; + while ( pSep ) + { + // new separation completely inside? nothing to do! + if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) ) + return; + + // new separation completly left? -> new separation! + if ( nXRight < pSep->mnXLeft ) + { + pNewSep = new ImplRegionBandSep; + pNewSep->mnXLeft = nXLeft; + pNewSep->mnXRight = nXRight; + pNewSep->mbRemoved = FALSE; + + pNewSep->mpNextSep = pSep; + if ( pSep == mpFirstSep ) + mpFirstSep = pNewSep; + else + pPrevSep->mpNextSep = pNewSep; + break; + } + + // new separation overlaping from left? -> extend boundary + if ( (nXRight >= pSep->mnXLeft) && (nXLeft <= pSep->mnXLeft) ) + pSep->mnXLeft = nXLeft; + + // new separation overlaping from right? -> extend boundary + if ( (nXLeft <= pSep->mnXRight) && (nXRight > pSep->mnXRight) ) + { + pSep->mnXRight = nXRight; + break; + } + + // not inserted, but last element? -> add to the end of the list + if ( !pSep->mpNextSep && (nXLeft > pSep->mnXRight) ) + { + pNewSep = new ImplRegionBandSep; + pNewSep->mnXLeft = nXLeft; + pNewSep->mnXRight = nXRight; + pNewSep->mbRemoved = FALSE; + + pSep->mpNextSep = pNewSep; + pNewSep->mpNextSep = NULL; + break; + } + + pPrevSep = pSep; + pSep = pSep->mpNextSep; + } + + OptimizeBand(); +} + +// ----------------------------------------------------------------------- + +void ImplRegionBand::Intersect( long nXLeft, long nXRight ) +{ + DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::Intersect(): nxLeft > nXRight" ); + + // band has been touched + mbTouched = TRUE; + + // band empty? -> nothing to do + if ( !mpFirstSep ) + return; + + // process real intersection + ImplRegionBandSep* pSep = mpFirstSep; + while ( pSep ) + { + // new separation completly outside? -> remove separation + if ( (nXRight < pSep->mnXLeft) || (nXLeft > pSep->mnXRight) ) + // will be removed from the optimizer + pSep->mbRemoved = TRUE; + + // new separation overlaping from left? -> reduce right boundary + if ( (nXLeft <= pSep->mnXLeft) && + (nXRight <= pSep->mnXRight) && + (nXRight >= pSep->mnXLeft) ) + pSep->mnXRight = nXRight; + + // new separation overlaping from right? -> reduce right boundary + if ( (nXLeft >= pSep->mnXLeft) && + (nXLeft <= pSep->mnXRight) && + (nXRight >= pSep->mnXRight) ) + pSep->mnXLeft = nXLeft; + + // new separation within the actual one? -> reduce both boundaries + if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) ) + { + pSep->mnXRight = nXRight; + pSep->mnXLeft = nXLeft; + } + + pSep = pSep->mpNextSep; + } + + OptimizeBand(); +} + +// ----------------------------------------------------------------------- + +void ImplRegionBand::Exclude( long nXLeft, long nXRight ) +{ + DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::Exclude(): nxLeft > nXRight" ); + + // band has been touched + mbTouched = TRUE; + + // band empty? -> nothing to do + if ( !mpFirstSep ) + return; + + // process real exclusion + ImplRegionBandSep* pNewSep; + ImplRegionBandSep* pPrevSep; + ImplRegionBandSep* pSep = mpFirstSep; + while ( pSep ) + { + BOOL bSepProcessed = FALSE; + + // new separation completely overlapping? -> remove separation + if ( (nXLeft <= pSep->mnXLeft) && (nXRight >= pSep->mnXRight) ) + { + // will be removed from the optimizer + pSep->mbRemoved = TRUE; + bSepProcessed = TRUE; + } + + // new separation overlaping from left? -> reduce boundary + if ( !bSepProcessed ) + { + if ( (nXRight >= pSep->mnXLeft) && (nXLeft <= pSep->mnXLeft) ) + { + pSep->mnXLeft = nXRight+1; + bSepProcessed = TRUE; + } + } + + // new separation overlaping from right? -> reduce boundary + if ( !bSepProcessed ) + { + if ( (nXLeft <= pSep->mnXRight) && (nXRight > pSep->mnXRight) ) + { + pSep->mnXRight = nXLeft-1; + bSepProcessed = TRUE; + } + } + + // new separation within the actual one? -> reduce boundary + // and add new entry for reminder + if ( !bSepProcessed ) + { + if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) ) + { + pNewSep = new ImplRegionBandSep; + pNewSep->mnXLeft = pSep->mnXLeft; + pNewSep->mnXRight = nXLeft-1; + pNewSep->mbRemoved = FALSE; + + pSep->mnXLeft = nXRight+1; + + // connections from the new separation + pNewSep->mpNextSep = pSep; + + // connections to the new separation + if ( pSep == mpFirstSep ) + mpFirstSep = pNewSep; + else + pPrevSep->mpNextSep = pNewSep; + } + } + + pPrevSep = pSep; + pSep = pSep->mpNextSep; + } + + OptimizeBand(); +} + +// ----------------------------------------------------------------------- + +void ImplRegionBand::XOr( long nXLeft, long nXRight ) +{ + DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::XOr(): nxLeft > nXRight" ); + + // band empty? -> add element + if ( !mpFirstSep ) + { + mpFirstSep = new ImplRegionBandSep; + mpFirstSep->mnXLeft = nXLeft; + mpFirstSep->mnXRight = nXRight; + mpFirstSep->mbRemoved = FALSE; + mpFirstSep->mpNextSep = NULL; + return; + } + + // process real xor + ImplRegionBandSep* pNewSep; + ImplRegionBandSep* pPrevSep; + ImplRegionBandSep* pSep = mpFirstSep; + while ( pSep ) + { + // new separation completely overlapping? + // -> move boundaries to left remainder + // -> reduce boundaries of new separation + if ( (nXLeft <= pSep->mnXLeft) && (nXRight >= pSep->mnXRight) ) + { + int iOldXRight = pSep->mnXRight; + pSep->mnXRight = pSep->mnXLeft; + pSep->mnXLeft = nXLeft; + nXLeft = pSep->mnXRight; + } + + // new separation overlaping from left? + // -> move boundaries to left remainder + // -> set boundaries of new separation to right remainder + if ( (nXRight >= pSep->mnXLeft) && (nXLeft <= pSep->mnXLeft) ) + { + int iOldXRight = pSep->mnXRight; + pSep->mnXRight = pSep->mnXLeft; + pSep->mnXLeft = nXLeft; + nXLeft = pSep->mnXRight; + } + + // new separation overlaping from right? -> reduce boundary + if ( (nXLeft <= pSep->mnXRight) && (nXRight > pSep->mnXRight) ) + pSep->mnXRight = nXLeft; + + // new separation within the actual one? -> reduce boundary + // and add new entry for reminder + if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) ) + { + pNewSep = new ImplRegionBandSep; + pNewSep->mnXLeft = pSep->mnXLeft; + pNewSep->mnXRight = nXLeft; + + pSep->mnXLeft = nXRight; + + // connections from the new separation + pNewSep->mpNextSep = pSep; + + // connections to the new separation + if ( pSep == mpFirstSep ) + mpFirstSep = pNewSep; + else + pPrevSep->mpNextSep = pNewSep; + } + + pPrevSep = pSep; + pSep = pSep->mpNextSep; + } + + OptimizeBand(); +} + +// ----------------------------------------------------------------------- + +BOOL ImplRegionBand::IsInside( long nX ) +{ + ImplRegionBandSep* pSep = mpFirstSep; + while ( pSep ) + { + if ( (pSep->mnXLeft <= nX) && (pSep->mnXRight >= nX) ) + return TRUE; + + pSep = pSep->mpNextSep; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL ImplRegionBand::IsOver( long nLeft, long nRight ) +{ + ImplRegionBandSep* pSep = mpFirstSep; + while ( pSep ) + { + if ( (pSep->mnXLeft < nRight) && (pSep->mnXRight > nLeft) ) + return TRUE; + + pSep = pSep->mpNextSep; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL ImplRegionBand::IsInside( long nLeft, long nRight ) +{ + ImplRegionBandSep* pSep = mpFirstSep; + while ( pSep ) + { + if ( (pSep->mnXLeft >= nLeft) && (nRight <= pSep->mnXRight) ) + return TRUE; + + pSep = pSep->mpNextSep; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +long ImplRegionBand::GetXLeftBoundary() const +{ + DBG_ASSERT( mpFirstSep != NULL, "ImplRegionBand::XLeftBoundary -> no separation in band!" ); + + return mpFirstSep->mnXLeft; +} + +// ----------------------------------------------------------------------- + +long ImplRegionBand::GetXRightBoundary() const +{ + DBG_ASSERT( mpFirstSep != NULL, "ImplRegionBand::XRightBoundary -> no separation in band!" ); + + // search last separation + ImplRegionBandSep* pSep = mpFirstSep; + while ( pSep->mpNextSep ) + pSep = pSep->mpNextSep; + return pSep->mnXRight; +} + +// ----------------------------------------------------------------------- + +BOOL ImplRegionBand::operator==( const ImplRegionBand& rRegionBand ) const +{ + ImplRegionBandSep* pOwnRectBandSep = mpFirstSep; + ImplRegionBandSep* pSecondRectBandSep = rRegionBand.mpFirstSep; + while ( pOwnRectBandSep && pSecondRectBandSep ) + { + // get boundaries of current rectangle + long nOwnXLeft = pOwnRectBandSep->mnXLeft; + long nSecondXLeft = pSecondRectBandSep->mnXLeft; + if ( nOwnXLeft != nSecondXLeft ) + return FALSE; + + long nOwnXRight = pOwnRectBandSep->mnXRight; + long nSecondXRight = pSecondRectBandSep->mnXRight; + if ( nOwnXRight != nSecondXRight ) + return FALSE; + + // get next separation from current band + pOwnRectBandSep = pOwnRectBandSep->mpNextSep; + + // get next separation from current band + pSecondRectBandSep = pSecondRectBandSep->mpNextSep; + } + + // differnt number of separations? + if ( pOwnRectBandSep || pSecondRectBandSep ) + return FALSE; + + return TRUE; +} diff --git a/vcl/source/gdi/region.cxx b/vcl/source/gdi/region.cxx new file mode 100644 index 000000000000..000cad2a909b --- /dev/null +++ b/vcl/source/gdi/region.cxx @@ -0,0 +1,2458 @@ +/************************************************************************* + * + * $RCSfile: region.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_REGION_CXX + +#include <limits.h> + +#ifndef _VCOMPAT_HXX +#include <tools/vcompat.hxx> +#endif +#ifndef _SV_SALBTYPE_HXX +#include <salbtype.hxx> +#endif +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _REGION_H +#include <region.h> +#endif +#ifndef _REGION_HXX +#include <region.hxx> +#endif +#ifndef _REGBAND_HXX +#include <regband.hxx> +#endif + +// ======================================================================= +// +// ImplRegionBand +// +// Die Klassen RegionBand/ImplRegionBand speichert Regionen in Form von +// Rechtecken ab. Die Region ist in Y-Richtung in Baendern unterteilt, die +// wiederum ein oder mehrere Rechtecke mit der Hoehe des Bandes enthalten. +// +// Leere Baender werden entfernt. +// +// Polygone und PolyPolygone werden ebenfalls in Rechtecke zerlegt und in +// der Baendern abgelegt. Hierzu werden alle Punkte der einzelnen Polygone +// mit dem Bresenham-Algorithmus berechnet und in die Baender eingetragen. +// Nach der vollstaendigen Berechung aller Kanten werden die entsprechenden +// Rechntecke berechnet + +// ======================================================================= + +static ImplRegionBase aImplNullRegion = { 0, 0, NULL }; +static ImplRegionBase aImplEmptyRegion = { 0, 0, NULL }; + +// ======================================================================= + +DBG_NAME( Region ); +DBG_NAMEEX( Polygon ); +DBG_NAMEEX( PolyPolygon ); + +// ----------------------------------------------------------------------- + +#ifdef DBG_UTIL +const char* ImplDbgTestRegion( const void* pObj ) +{ + Region* pRegion = (Region*)pObj; + ImplRegion* pImplRegion = pRegion->ImplGetImplRegion(); + + if ( aImplNullRegion.mnRefCount ) + return "Null-Region-RefCount modified"; + if ( aImplNullRegion.mnRectCount ) + return "Null-Region-RectCount modified"; + if ( aImplNullRegion.mpPolyPoly ) + return "Null-Region-PolyPoly modified"; + if ( aImplEmptyRegion.mnRefCount ) + return "Emptry-Region-RefCount modified"; + if ( aImplEmptyRegion.mnRectCount ) + return "Emptry-Region-RectCount modified"; + if ( aImplEmptyRegion.mpPolyPoly ) + return "Emptry-Region-PolyPoly modified"; + + if ( (pImplRegion != &aImplEmptyRegion) && (pImplRegion != &aImplNullRegion) ) + { + ULONG nCount = 0; + const ImplRegionBand* pBand = pImplRegion->ImplGetFirstRegionBand(); + while ( pBand ) + { + if ( pBand->mnYBottom < pBand->mnYTop ) + return "YBottom < YTop"; + if ( pBand->mpNextBand ) + { + if ( pBand->mnYBottom >= pBand->mpNextBand->mnYTop ) + return "overlapping bands in region"; + } + if ( pBand->mbTouched > 1 ) + return "Band-mbTouched overwrite"; + + ImplRegionBandSep* pSep = pBand->mpFirstSep; + while ( pSep ) + { + if ( pSep->mnXRight < pSep->mnXLeft ) + return "XLeft < XRight"; + if ( pSep->mpNextSep ) + { + if ( pSep->mnXRight >= pSep->mpNextSep->mnXLeft ) + return "overlapping separations in region"; + } + if ( pSep->mbRemoved > 1 ) + return "Sep-mbRemoved overwrite"; + + nCount++; + pSep = pSep->mpNextSep; + } + + pBand = pBand->mpNextBand; + } + + if ( pImplRegion->mnRectCount != nCount ) + return "mnRetCount is not valid"; + } + + return NULL; +} +#endif + +// ======================================================================= + +inline void Region::ImplPolyPolyRegionToBandRegion() +{ + if ( mpImplRegion->mpPolyPoly ) + ImplPolyPolyRegionToBandRegionFunc(); +} + +// ======================================================================= + +ImplRegion::ImplRegion() +{ + mnRefCount = 1; + mnRectCount = 0; + mpPolyPoly = NULL; + mpFirstBand = NULL; + mpLastCheckedBand = NULL; +} + +// ------------------------------------------------------------------------ + +ImplRegion::ImplRegion( const PolyPolygon& rPolyPoly ) +{ + mnRefCount = 1; + mnRectCount = 0; + mpFirstBand = NULL; + mpLastCheckedBand = NULL; + mpPolyPoly = new PolyPolygon( rPolyPoly ); +} + +// ----------------------------------------------------------------------- + +ImplRegion::ImplRegion( const ImplRegion& rImplRegion ) +{ + mnRefCount = 1; + mnRectCount = rImplRegion.mnRectCount; + mpFirstBand = NULL; + mpLastCheckedBand = NULL; + if ( rImplRegion.mpPolyPoly ) + mpPolyPoly = new PolyPolygon( *rImplRegion.mpPolyPoly ); + else + mpPolyPoly = NULL; + + // insert band(s) into the list + ImplRegionBand* pNewBand; + ImplRegionBand* pPrevBand; + ImplRegionBand* pBand = rImplRegion.mpFirstBand; + while ( pBand ) + { + pNewBand = new ImplRegionBand( *pBand ); + + // first element? -> set as first into the list + if ( pBand == rImplRegion.mpFirstBand ) + mpFirstBand = pNewBand; + else + pPrevBand->mpNextBand = pNewBand; + + pPrevBand = pNewBand; + pBand = pBand->mpNextBand; + } +} + +// ----------------------------------------------------------------------- + +ImplRegion::~ImplRegion() +{ + DBG_ASSERT( (this != &aImplEmptyRegion) && (this != &aImplNullRegion), + "ImplRegion::~ImplRegion() - Empty oder NULL-Region" ) + + ImplRegionBand* pBand = mpFirstBand; + while ( pBand ) + { + ImplRegionBand* pTempBand = pBand->mpNextBand; + delete pBand; + pBand = pTempBand; + } + + delete mpPolyPoly; +} + +// ----------------------------------------------------------------------- +// +// create complete range of bands in single steps + +void ImplRegion::CreateBandRange( long nYTop, long nYBottom ) +{ + // add top band + mpFirstBand = new ImplRegionBand( nYTop-1, nYTop-1 ); + + // begin first search from the first element + mpLastCheckedBand = mpFirstBand; + + ImplRegionBand* pBand = mpFirstBand; + for ( int i = nYTop; i <= nYBottom+1; i++ ) + { + // create new band + ImplRegionBand* pNewBand = new ImplRegionBand( i, i ); + pBand->mpNextBand = pNewBand; + if ( pBand != mpFirstBand ) + pNewBand->mpPrevBand = pBand; + + pBand = pBand->mpNextBand; + } +} + +// ----------------------------------------------------------------------- + +BOOL ImplRegion::InsertLine( const Point& rStartPt, const Point& rEndPt, + long nLineId ) +{ + long nX, nY; + + // lines consisting of a single point do not interest here + if ( rStartPt == rEndPt ) + return TRUE; + + LineType eLineType = (rStartPt.Y() > rEndPt.Y()) ? LINE_DESCENDING : LINE_ASCENDING; + if ( rStartPt.X() == rEndPt.X() ) + { + // vertical line + const long nEndY = rEndPt.Y(); + + nX = rStartPt.X(); + nY = rStartPt.Y(); + + if( nEndY > nY ) + { + for ( ; nY <= nEndY; nY++ ) + { + Point aNewPoint( nX, nY ); + InsertPoint( aNewPoint, nLineId, + (aNewPoint == rEndPt) || (aNewPoint == rStartPt), + eLineType ); + } + } + else + { + for ( ; nY >= nEndY; nY-- ) + { + Point aNewPoint( nX, nY ); + InsertPoint( aNewPoint, nLineId, + (aNewPoint == rEndPt) || (aNewPoint == rStartPt), + eLineType ); + } + } + } + else if ( rStartPt.Y() != rEndPt.Y() ) + { + const long nDX = labs( rEndPt.X() - rStartPt.X() ); + const long nDY = labs( rEndPt.Y() - rStartPt.Y() ); + const long nStartX = rStartPt.X(); + const long nStartY = rStartPt.Y(); + const long nEndX = rEndPt.X(); + const long nEndY = rEndPt.Y(); + const long nXInc = ( nStartX < nEndX ) ? 1L : -1L; + const long nYInc = ( nStartY < nEndY ) ? 1L : -1L; + + if ( nDX >= nDY ) + { + const long nDYX = ( nDY - nDX ) << 1; + const long nDY2 = nDY << 1; + long nD = nDY2 - nDX; + + for ( nX = nStartX, nY = nStartY; nX != nEndX; nX += nXInc ) + { + InsertPoint( Point( nX, nY ), nLineId, nStartX == nX, eLineType ); + + if ( nD < 0L ) + nD += nDY2; + else + nD += nDYX, nY += nYInc; + } + } + else + { + const long nDYX = ( nDX - nDY ) << 1; + const long nDY2 = nDX << 1; + long nD = nDY2 - nDY; + + for ( nX = nStartX, nY = nStartY; nY != nEndY; nY += nYInc ) + { + InsertPoint( Point( nX, nY ), nLineId, nStartY == nY, eLineType ); + + if ( nD < 0L ) + nD += nDY2; + else + nD += nDYX, nX += nXInc; + } + } + + // last point + InsertPoint( Point( nEndX, nEndY ), nLineId, TRUE, eLineType ); + } + + return TRUE; +} + +// ----------------------------------------------------------------------- +// +// search for appropriate place for the new point + +BOOL ImplRegion::InsertPoint( const Point &rPoint, long nLineID, + BOOL bEndPoint, LineType eLineType ) +{ + DBG_ASSERT( mpFirstBand != NULL, "ImplRegion::InsertPoint - no bands available!" ); + + if ( rPoint.Y() == mpLastCheckedBand->mnYTop ) + { + mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType ); + return TRUE; + } + + if ( rPoint.Y() > mpLastCheckedBand->mnYTop ) + { + // Search ascending + while ( mpLastCheckedBand ) + { + // Insert point if possible + if ( rPoint.Y() == mpLastCheckedBand->mnYTop ) + { + mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType ); + return TRUE; + } + + mpLastCheckedBand = mpLastCheckedBand->mpNextBand; + } + + DBG_ERROR( "ImplRegion::InsertPoint reached the end of the list!" ); + } + else + { + // Search descending + while ( mpLastCheckedBand ) + { + // Insert point if possible + if ( rPoint.Y() == mpLastCheckedBand->mnYTop ) + { + mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType ); + return TRUE; + } + + mpLastCheckedBand = mpLastCheckedBand->mpPrevBand; + } + + DBG_ERROR( "ImplRegion::InsertPoint reached the beginning of the list!" ); + } + + DBG_ERROR( "ImplRegion::InsertPoint point not inserted!" ); + + // reinitialize pointer (should never be reached!) + mpLastCheckedBand = mpFirstBand; + + return FALSE; +} + +// ----------------------------------------------------------------------- +// +// search for appropriate places for the new bands + +void ImplRegion::InsertBands( long nTop, long nBottom ) +{ + // region empty? -> set rectagle as first entry! + if ( !mpFirstBand ) + { + // add band with boundaries of the rectangle + mpFirstBand = new ImplRegionBand( nTop, nBottom ); + return; + } + + // find/insert bands for the boundaries of the rectangle + BOOL bTopBoundaryInserted = FALSE; + BOOL bTop2BoundaryInserted = FALSE; + BOOL bBottomBoundaryInserted = FALSE; + + // special case: top boundary is above the first band + ImplRegionBand* pNewBand; + if ( nTop < mpFirstBand->mnYTop ) + { + // create new band above the first in the list + pNewBand = new ImplRegionBand( nTop, mpFirstBand->mnYTop ); + if ( nBottom < mpFirstBand->mnYTop ) + pNewBand->mnYBottom = nBottom; + + // insert band into the list + pNewBand->mpNextBand = mpFirstBand; + mpFirstBand = pNewBand; + + bTopBoundaryInserted = TRUE; + } + + // insert band(s) into the list + ImplRegionBand* pBand = mpFirstBand; + while ( pBand ) + { + // Insert Bands if possible + if ( !bTopBoundaryInserted ) + bTopBoundaryInserted = InsertSingleBand( pBand, nTop - 1 ); + + if ( !bTop2BoundaryInserted ) + bTop2BoundaryInserted = InsertSingleBand( pBand, nTop ); + + if ( !bBottomBoundaryInserted && (nTop != nBottom) ) + bBottomBoundaryInserted = InsertSingleBand( pBand, nBottom ); + + // both boundaries inserted? -> nothing more to do + if ( bTopBoundaryInserted && bTop2BoundaryInserted && bBottomBoundaryInserted ) + break; + + // insert bands between two bands if neccessary + if ( pBand->mpNextBand ) + { + if ( (pBand->mnYBottom + 1) < pBand->mpNextBand->mnYTop ) + { + // copy band with list and set new boundary + pNewBand = new ImplRegionBand( pBand->mnYBottom+1, + pBand->mpNextBand->mnYTop-1 ); + + // insert band into the list + pNewBand->mpNextBand = pBand->mpNextBand; + pBand->mpNextBand = pNewBand; + } + } + + pBand = pBand->mpNextBand; + } +} + +// ----------------------------------------------------------------------- +// +// create new band and insert it into the list + +BOOL ImplRegion::InsertSingleBand( ImplRegionBand* pBand, + long nYBandPosition ) +{ + // boundary already included in band with height 1? -> nothing to do! + if ( (pBand->mnYTop == pBand->mnYBottom) && + (nYBandPosition == pBand->mnYTop) ) + return TRUE; + + // insert single height band on top? + ImplRegionBand* pNewBand; + if ( nYBandPosition == pBand->mnYTop ) + { + // copy band with list and set new boundary + pNewBand = new ImplRegionBand( *pBand ); + pNewBand->mnYTop = nYBandPosition+1; + + // insert band into the list + pNewBand->mpNextBand = pBand->mpNextBand; + pBand->mnYBottom = nYBandPosition; + pBand->mpNextBand = pNewBand; + + return TRUE; + } + + // top of new rectangle within the current band? -> insert new band and copy data + if ( (nYBandPosition > pBand->mnYTop) && + (nYBandPosition < pBand->mnYBottom) ) + { + // copy band with list and set new boundary + pNewBand = new ImplRegionBand( *pBand ); + pNewBand->mnYTop = nYBandPosition; + + // insert band into the list + pNewBand->mpNextBand = pBand->mpNextBand; + pBand->mnYBottom = nYBandPosition; + pBand->mpNextBand = pNewBand; + + // copy band with list and set new boundary + pNewBand = new ImplRegionBand( *pBand ); + pNewBand->mnYTop = nYBandPosition; + + // insert band into the list + pBand->mpNextBand->mnYTop = nYBandPosition+1; + + pNewBand->mpNextBand = pBand->mpNextBand; + pBand->mnYBottom = nYBandPosition - 1; + pBand->mpNextBand = pNewBand; + + return TRUE; + } + + // create new band behind the current in the list + if ( !pBand->mpNextBand ) + { + if ( nYBandPosition == pBand->mnYBottom ) + { + // copy band with list and set new boundary + pNewBand = new ImplRegionBand( *pBand ); + pNewBand->mnYTop = pBand->mnYBottom; + pNewBand->mnYBottom = nYBandPosition; + + pBand->mnYBottom = nYBandPosition-1; + + // append band to the list + pBand->mpNextBand = pNewBand; + return TRUE; + } + + if ( nYBandPosition > pBand->mnYBottom ) + { + // create new band + pNewBand = new ImplRegionBand( pBand->mnYBottom + 1, nYBandPosition ); + + // append band to the list + pBand->mpNextBand = pNewBand; + return TRUE; + } + } + + return FALSE; +} + +// ------------------------------------------------------------------------ + +void ImplRegion::Union( long nLeft, long nTop, long nRight, long nBottom ) +{ + DBG_ASSERT( nLeft <= nRight, "ImplRegion::Union() - nLeft > nRight" ); + DBG_ASSERT( nTop <= nBottom, "ImplRegion::Union() - nTop > nBottom" ); + + // process union + ImplRegionBand* pBand = mpFirstBand; + while ( pBand ) + { + if ( pBand->mnYTop >= nTop ) + { + if ( pBand->mnYBottom <= nBottom ) + pBand->Union( nLeft, nRight ); + else + { +#ifdef DBG_UTIL + long nCurY = pBand->mnYBottom; + pBand = pBand->mpNextBand; + while ( pBand ) + { + if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) ) + { + DBG_ERROR( "ImplRegion::Union() - Bands not sorted!" ); + } + pBand = pBand->mpNextBand; + } +#endif + break; + } + } + + pBand = pBand->mpNextBand; + } +} + +// ----------------------------------------------------------------------- + +void ImplRegion::Exclude( long nLeft, long nTop, long nRight, long nBottom ) +{ + DBG_ASSERT( nLeft <= nRight, "ImplRegion::Exclude() - nLeft > nRight" ); + DBG_ASSERT( nTop <= nBottom, "ImplRegion::Exclude() - nTop > nBottom" ); + + // process exclude + ImplRegionBand* pBand = mpFirstBand; + while ( pBand ) + { + if ( pBand->mnYTop >= nTop ) + { + if ( pBand->mnYBottom <= nBottom ) + pBand->Exclude( nLeft, nRight ); + else + { +#ifdef DBG_UTIL + long nCurY = pBand->mnYBottom; + pBand = pBand->mpNextBand; + while ( pBand ) + { + if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) ) + { + DBG_ERROR( "ImplRegion::Exclude() - Bands not sorted!" ); + } + pBand = pBand->mpNextBand; + } +#endif + break; + } + } + + pBand = pBand->mpNextBand; + } +} + +// ----------------------------------------------------------------------- + +void ImplRegion::XOr( long nLeft, long nTop, long nRight, long nBottom ) +{ + DBG_ASSERT( nLeft <= nRight, "ImplRegion::Exclude() - nLeft > nRight" ); + DBG_ASSERT( nTop <= nBottom, "ImplRegion::Exclude() - nTop > nBottom" ); + + // process xor + ImplRegionBand* pBand = mpFirstBand; + while ( pBand ) + { + if ( pBand->mnYTop >= nTop ) + { + if ( pBand->mnYBottom <= nBottom ) + pBand->XOr( nLeft, nRight ); + else + { +#ifdef DBG_UTIL + long nCurY = pBand->mnYBottom; + pBand = pBand->mpNextBand; + while ( pBand ) + { + if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) ) + { + DBG_ERROR( "ImplRegion::XOr() - Bands not sorted!" ); + } + pBand = pBand->mpNextBand; + } +#endif + break; + } + } + + pBand = pBand->mpNextBand; + } +} + +// ----------------------------------------------------------------------- +// +// remove empty bands + +BOOL ImplRegion::OptimizeBandList() +{ + DBG_ASSERT( (this != &aImplNullRegion) && (this != &aImplEmptyRegion), + "ImplRegion::OptimizeBandList() - Empty oder NULL-Region" ); + + mnRectCount = 0; + + ImplRegionBand* pPrevBand; + ImplRegionBand* pBand = mpFirstBand; + while ( pBand ) + { + const BOOL bBTEqual = pBand->mpNextBand && + (pBand->mnYBottom == pBand->mpNextBand->mnYTop); + + // no separation? -> remove! + if ( pBand->IsEmpty() || (bBTEqual && (pBand->mnYBottom == pBand->mnYTop)) ) + { + // save pointer + ImplRegionBand* pOldBand = pBand; + + // previous element of the list + if ( pBand == mpFirstBand ) + mpFirstBand = pBand->mpNextBand; + else + pPrevBand->mpNextBand = pBand->mpNextBand; + + pBand = pBand->mpNextBand; + delete pOldBand; + } + else + { + // fixup + if ( bBTEqual ) + pBand->mnYBottom = pBand->mpNextBand->mnYTop-1; + + // this and next band with equal separations? -> combine! + if ( pBand->mpNextBand && + ((pBand->mnYBottom+1) == pBand->mpNextBand->mnYTop) && + (*pBand == *pBand->mpNextBand) ) + { + // expand current height + pBand->mnYBottom = pBand->mpNextBand->mnYBottom; + + // remove next band from list + ImplRegionBand* pDeletedBand = pBand->mpNextBand; + pBand->mpNextBand = pDeletedBand->mpNextBand; + delete pDeletedBand; + + // check band again! + } + else + { + // count rectangles within band + ImplRegionBandSep* pSep = pBand->mpFirstSep; + while ( pSep ) + { + mnRectCount++; + pSep = pSep->mpNextSep; + } + + pPrevBand = pBand; + pBand = pBand->mpNextBand; + } + } + } + +#ifdef DBG_UTIL + pBand = mpFirstBand; + while ( pBand ) + { + DBG_ASSERT( pBand->mpFirstSep != NULL, + "Exiting ImplRegion::OptimizeBandList(): empty band in region!" ); + + if ( pBand->mnYBottom < pBand->mnYTop ) + DBG_ERROR( "ImplRegion::OptimizeBandList(): YBottomBoundary < YTopBoundary" ); + + if ( pBand->mpNextBand ) + { + if ( pBand->mnYBottom >= pBand->mpNextBand->mnYTop ) + DBG_ERROR( "ImplRegion::OptimizeBandList(): overlapping bands in region!" ); + } + + pBand = pBand->mpNextBand; + } +#endif + + return (mnRectCount != 0); +} + +// ======================================================================= + +void Region::ImplCopyData() +{ + mpImplRegion->mnRefCount--; + mpImplRegion = new ImplRegion( *mpImplRegion ); +} + +// ======================================================================= + +Region::Region() +{ + DBG_CTOR( Region, ImplDbgTestRegion ); + + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); +} + +// ----------------------------------------------------------------------- + +Region::Region( RegionType eType ) +{ + DBG_CTOR( Region, ImplDbgTestRegion ); + DBG_ASSERT( (eType == REGION_NULL) || (eType == REGION_EMPTY), + "Region( RegionType ) - RegionType != EMPTY/NULL" ); + + if ( eType == REGION_NULL ) + mpImplRegion = (ImplRegion*)(&aImplNullRegion); + else + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); +} + +// ----------------------------------------------------------------------- + +Region::Region( const Rectangle& rRect ) +{ + DBG_CTOR( Region, ImplDbgTestRegion ); + + ImplCreateRectRegion( rRect ); +} + +// ----------------------------------------------------------------------- + +Region::Region( const Polygon& rPolygon ) +{ + DBG_CTOR( Region, ImplDbgTestRegion ); + DBG_CHKOBJ( &rPolygon, Polygon, NULL ); + + ImplCreatePolyPolyRegion( rPolygon ); +} + +// ----------------------------------------------------------------------- + +Region::Region( const PolyPolygon& rPolyPoly ) +{ + DBG_CTOR( Region, ImplDbgTestRegion ); + DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL ); + + ImplCreatePolyPolyRegion( rPolyPoly ); +} + +// ----------------------------------------------------------------------- + +Region::Region( const Region& rRegion ) +{ + DBG_CTOR( Region, ImplDbgTestRegion ); + DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); + DBG_ASSERT( rRegion.mpImplRegion->mnRefCount < 0xFFFFFFFE, "Region: RefCount overflow" ); + + // copy pointer to instance of implementation + mpImplRegion = rRegion.mpImplRegion; + if ( mpImplRegion->mnRefCount ) + mpImplRegion->mnRefCount++; +} + +// ----------------------------------------------------------------------- + +Region::~Region() +{ + DBG_DTOR( Region, ImplDbgTestRegion ); + + // statische Object haben RefCount von 0 + if ( mpImplRegion->mnRefCount ) + { + if ( mpImplRegion->mnRefCount > 1 ) + mpImplRegion->mnRefCount--; + else + delete mpImplRegion; + } +} + +// ----------------------------------------------------------------------- + +void Region::ImplCreateRectRegion( const Rectangle& rRect ) +{ + if ( rRect.IsEmpty() ) + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + else + { + // get justified rectangle + long nTop = Min( rRect.Top(), rRect.Bottom() ); + long nBottom = Max( rRect.Top(), rRect.Bottom() ); + long nLeft = Min( rRect.Left(), rRect.Right() ); + long nRight = Max( rRect.Left(), rRect.Right() ); + + // create instance of implementation class + mpImplRegion = new ImplRegion(); + + // add band with boundaries of the rectangle + mpImplRegion->mpFirstBand = new ImplRegionBand( nTop, nBottom ); + + // Set left and right boundaries of the band + mpImplRegion->mpFirstBand->Union( nLeft, nRight ); + mpImplRegion->mnRectCount = 1; + } +} + +// ----------------------------------------------------------------------- + +void Region::ImplCreatePolyPolyRegion( const PolyPolygon& rPolyPoly ) +{ + const USHORT nPolyCount = rPolyPoly.Count(); + if ( nPolyCount ) + { + // polypolygon empty? -> empty region + const Rectangle aRect( rPolyPoly.GetBoundRect() ); + + if ( !aRect.IsEmpty() ) + { + // width OR height == 1 ? => Rectangular region + if ( (aRect.GetWidth() == 1) || (aRect.GetHeight() == 1) ) + ImplCreateRectRegion( aRect ); + else + mpImplRegion = new ImplRegion( rPolyPoly ); + } + else + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + } + else + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); +} + +// ----------------------------------------------------------------------- + +void Region::ImplPolyPolyRegionToBandRegionFunc() +{ + const PolyPolygon aPolyPoly( *mpImplRegion->mpPolyPoly ); + + if ( mpImplRegion->mnRefCount > 1 ) + mpImplRegion->mnRefCount--; + else + delete mpImplRegion; + + const USHORT nPolyCount = aPolyPoly.Count(); + if ( nPolyCount ) + { + // polypolygon empty? -> empty region + const Rectangle aRect( aPolyPoly.GetBoundRect() ); + + if ( !aRect.IsEmpty() ) + { + long nLineID = 0L; + + // initialisation and creation of Bands + mpImplRegion = new ImplRegion(); + mpImplRegion->CreateBandRange( aRect.Top(), aRect.Bottom() ); + + // insert polygons + for ( USHORT nPoly = 0; nPoly < nPolyCount; nPoly++ ) + { + // get reference to current polygon + const Polygon& aPoly = aPolyPoly.GetObject( nPoly ); + const USHORT nSize = aPoly.GetSize(); + + // not enough points ( <= 2 )? -> nothing to do! + if ( nSize <= 2 ) + continue; + + // band the polygon + for ( USHORT nPoint = 1; nPoint < nSize; nPoint++ ) + mpImplRegion->InsertLine( aPoly.GetPoint(nPoint-1), aPoly.GetPoint(nPoint), nLineID++ ); + + // close polygon with line from first point to last point, if neccesary + const Point rLastPoint = aPoly.GetPoint(nSize-1); + const Point rFirstPoint = aPoly.GetPoint(0); + if ( rLastPoint != rFirstPoint ) + mpImplRegion->InsertLine( rLastPoint, rFirstPoint, nLineID++ ); + } + + // process bands with lines + ImplRegionBand* pRegionBand = mpImplRegion->mpFirstBand; + while ( pRegionBand ) + { + // generate separations from the lines and process union + pRegionBand->ProcessPoints(); + pRegionBand = pRegionBand->mpNextBand; + } + + // cleanup + if ( !mpImplRegion->OptimizeBandList() ) + { + delete mpImplRegion; + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + } + } + else + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + } + else + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); +} + +// ----------------------------------------------------------------------- + +void Region::Move( long nHorzMove, long nVertMove ) +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + // no region data? -> nothing to do + if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + return; + + // no own instance data? -> make own copy! + if ( mpImplRegion->mnRefCount > 1 ) + ImplCopyData(); + + if ( mpImplRegion->mpPolyPoly ) + mpImplRegion->mpPolyPoly->Move( nHorzMove, nVertMove ); + else + { + ImplRegionBand* pBand = mpImplRegion->mpFirstBand; + while ( pBand ) + { + // process the vertical move + if ( nVertMove != 0) + { + pBand->mnYTop = pBand->mnYTop + nVertMove; + pBand->mnYBottom = pBand->mnYBottom + nVertMove; + } + + // process the horizontal move + if ( nHorzMove != 0) + pBand->MoveX( nHorzMove ); + + pBand = pBand->mpNextBand; + } + } +} + +// ----------------------------------------------------------------------- + +void Region::Scale( double fScaleX, double fScaleY ) +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + // no region data? -> nothing to do + if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + return; + + // no own instance data? -> make own copy! + if ( mpImplRegion->mnRefCount > 1 ) + ImplCopyData(); + + if ( mpImplRegion->mpPolyPoly ) + mpImplRegion->mpPolyPoly->Scale( fScaleX, fScaleY ); + else + { + ImplRegionBand* pBand = mpImplRegion->mpFirstBand; + while ( pBand ) + { + // process the vertical move + if ( fScaleY != 0.0 ) + { + pBand->mnYTop = FRound( pBand->mnYTop * fScaleY ); + pBand->mnYBottom = FRound( pBand->mnYBottom * fScaleY ); + } + + // process the horizontal move + if ( fScaleX != 0.0 ) + pBand->ScaleX( fScaleX ); + + pBand = pBand->mpNextBand; + } + } +} + +// ----------------------------------------------------------------------- + +BOOL Region::Union( const Rectangle& rRect ) +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + // is rectangle empty? -> nothing to do + if ( rRect.IsEmpty() ) + return TRUE; + + ImplPolyPolyRegionToBandRegion(); + + // no instance data? -> create! + if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + mpImplRegion = new ImplRegion(); + + // no own instance data? -> make own copy! + if ( mpImplRegion->mnRefCount > 1 ) + ImplCopyData(); + + // get justified rectangle + long nLeft = Min( rRect.Left(), rRect.Right() ); + long nTop = Min( rRect.Top(), rRect.Bottom() ); + long nRight = Max( rRect.Left(), rRect.Right() ); + long nBottom = Max( rRect.Top(), rRect.Bottom() ); + + // insert bands if the boundaries are not allready in the list + mpImplRegion->InsertBands( nTop, nBottom ); + + // process union + mpImplRegion->Union( nLeft, nTop, nRight, nBottom ); + + // cleanup + if ( !mpImplRegion->OptimizeBandList() ) + { + delete mpImplRegion; + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +BOOL Region::Intersect( const Rectangle& rRect ) +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + // is rectangle empty? -> nothing to do + if ( rRect.IsEmpty() ) + { + // statische Object haben RefCount von 0 + if ( mpImplRegion->mnRefCount ) + { + if ( mpImplRegion->mnRefCount > 1 ) + mpImplRegion->mnRefCount--; + else + delete mpImplRegion; + } + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + return TRUE; + } + + ImplPolyPolyRegionToBandRegion(); + + // is region empty? -> nothing to do! + if ( mpImplRegion == &aImplEmptyRegion ) + return TRUE; + + // get justified rectangle + long nLeft = Min( rRect.Left(), rRect.Right() ); + long nTop = Min( rRect.Top(), rRect.Bottom() ); + long nRight = Max( rRect.Left(), rRect.Right() ); + long nBottom = Max( rRect.Top(), rRect.Bottom() ); + + // is own region NULL-region? -> copy data! + if ( mpImplRegion == &aImplNullRegion ) + { + // create instance of implementation class + mpImplRegion = new ImplRegion(); + + // add band with boundaries of the rectangle + mpImplRegion->mpFirstBand = new ImplRegionBand( nTop, nBottom ); + + // Set left and right boundaries of the band + mpImplRegion->mpFirstBand->Union( nLeft, nRight ); + mpImplRegion->mnRectCount = 1; + + return TRUE; + } + + // no own instance data? -> make own copy! + if ( mpImplRegion->mnRefCount > 1 ) + ImplCopyData(); + + // insert bands if the boundaries are not allready in the list + mpImplRegion->InsertBands( nTop, nBottom ); + + // process intersections + ImplRegionBand* pPrevBand; + ImplRegionBand* pBand = mpImplRegion->mpFirstBand; + while ( pBand ) + { + // band within intersection boundary? -> process. otherwise remove + if ( (pBand->mnYTop >= nTop) && + (pBand->mnYBottom <= nBottom) ) + { + // process intersection + pBand->Intersect( nLeft, nRight ); + + pPrevBand = pBand; + pBand = pBand->mpNextBand; + } + else + { + ImplRegionBand* pOldBand = pBand; + if ( pBand == mpImplRegion->mpFirstBand ) + mpImplRegion->mpFirstBand = pBand->mpNextBand; + else + pPrevBand->mpNextBand = pBand->mpNextBand; + pBand = pBand->mpNextBand; + delete pOldBand; + } + } + + // cleanup + if ( !mpImplRegion->OptimizeBandList() ) + { + delete mpImplRegion; + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +BOOL Region::Exclude( const Rectangle& rRect ) +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + // is rectangle empty? -> nothing to do + if ( rRect.IsEmpty() ) + return TRUE; + + ImplPolyPolyRegionToBandRegion(); + + // no instance data? -> create! + if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + return TRUE; + + // no own instance data? -> make own copy! + if ( mpImplRegion->mnRefCount > 1 ) + ImplCopyData(); + + // get justified rectangle + long nLeft = Min( rRect.Left(), rRect.Right() ); + long nTop = Min( rRect.Top(), rRect.Bottom() ); + long nRight = Max( rRect.Left(), rRect.Right() ); + long nBottom = Max( rRect.Top(), rRect.Bottom() ); + + // insert bands if the boundaries are not allready in the list + mpImplRegion->InsertBands( nTop, nBottom ); + + // process exclude + mpImplRegion->Exclude( nLeft, nTop, nRight, nBottom ); + + // cleanup + if ( !mpImplRegion->OptimizeBandList() ) + { + delete mpImplRegion; + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +BOOL Region::XOr( const Rectangle& rRect ) +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + // is rectangle empty? -> nothing to do + if ( rRect.IsEmpty() ) + return TRUE; + + ImplPolyPolyRegionToBandRegion(); + + // no instance data? -> create! + if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + mpImplRegion = new ImplRegion(); + + // no own instance data? -> make own copy! + if ( mpImplRegion->mnRefCount > 1 ) + ImplCopyData(); + + // get justified rectangle + long nLeft = Min( rRect.Left(), rRect.Right() ); + long nTop = Min( rRect.Top(), rRect.Bottom() ); + long nRight = Max( rRect.Left(), rRect.Right() ); + long nBottom = Max( rRect.Top(), rRect.Bottom() ); + + // insert bands if the boundaries are not allready in the list + mpImplRegion->InsertBands( nTop, nBottom ); + + // process xor + mpImplRegion->XOr( nLeft, nTop, nRight, nBottom ); + + // cleanup + if ( !mpImplRegion->OptimizeBandList() ) + { + delete mpImplRegion; + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +BOOL Region::Union( const Region& rRegion ) +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + ImplPolyPolyRegionToBandRegion(); + ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion(); + + // is region empty or null? -> nothing to do + if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) ) + return TRUE; + + // no instance data? -> create! + if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + mpImplRegion = new ImplRegion(); + + // no own instance data? -> make own copy! + if ( mpImplRegion->mnRefCount > 1 ) + ImplCopyData(); + + // Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden + ImplRegionBand* pBand = rRegion.mpImplRegion->mpFirstBand; + while ( pBand ) + { + // insert bands if the boundaries are not allready in the list + mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom ); + + // process all elements of the list + ImplRegionBandSep* pSep = pBand->mpFirstSep; + while ( pSep ) + { + mpImplRegion->Union( pSep->mnXLeft, pBand->mnYTop, + pSep->mnXRight, pBand->mnYBottom ); + pSep = pSep->mpNextSep; + } + + pBand = pBand->mpNextBand; + } + + // cleanup + if ( !mpImplRegion->OptimizeBandList() ) + { + delete mpImplRegion; + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +BOOL Region::Intersect( const Region& rRegion ) +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + // same instance data? -> nothing to do! + if ( mpImplRegion == rRegion.mpImplRegion ) + return TRUE; + + ImplPolyPolyRegionToBandRegion(); + ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion(); + + if ( mpImplRegion == &aImplEmptyRegion ) + return TRUE; + + // is region null? -> nothing to do + if ( rRegion.mpImplRegion == &aImplNullRegion ) + return TRUE; + + // is rectangle empty? -> nothing to do + if ( rRegion.mpImplRegion == &aImplEmptyRegion ) + { + // statische Object haben RefCount von 0 + if ( mpImplRegion->mnRefCount ) + { + if ( mpImplRegion->mnRefCount > 1 ) + mpImplRegion->mnRefCount--; + else + delete mpImplRegion; + } + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + return TRUE; + } + + // is own region NULL-region? -> copy data! + if ( mpImplRegion == &aImplNullRegion) + { + mpImplRegion = rRegion.mpImplRegion; + rRegion.mpImplRegion->mnRefCount++; + return TRUE; + } + + // Wenn wir weniger Rechtecke haben, drehen wir den Intersect-Aufruf um + if ( mpImplRegion->mnRectCount+2 < rRegion.mpImplRegion->mnRectCount ) + { + Region aTempRegion = rRegion; + aTempRegion.Intersect( *this ); + *this = aTempRegion; + } + else + { + // no own instance data? -> make own copy! + if ( mpImplRegion->mnRefCount > 1 ) + ImplCopyData(); + + // mark all bands as untouched + ImplRegionBand* pBand = mpImplRegion->mpFirstBand; + while ( pBand ) + { + pBand->mbTouched = FALSE; + pBand = pBand->mpNextBand; + } + + pBand = rRegion.mpImplRegion->mpFirstBand; + while ( pBand ) + { + // insert bands if the boundaries are not allready in the list + mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom ); + + // process all elements of the list + ImplRegionBandSep* pSep = pBand->mpFirstSep; + while ( pSep ) + { + // left boundary? + if ( pSep == pBand->mpFirstSep ) + { + // process intersection and do not remove untouched bands + mpImplRegion->Exclude( LONG_MIN+1, pBand->mnYTop, + pSep->mnXLeft-1, pBand->mnYBottom ); + } + + // right boundary? + if ( pSep->mpNextSep == NULL ) + { + // process intersection and do not remove untouched bands + mpImplRegion->Exclude( pSep->mnXRight+1, pBand->mnYTop, + LONG_MAX-1, pBand->mnYBottom ); + } + else + { + // process intersection and do not remove untouched bands + mpImplRegion->Exclude( pSep->mnXRight+1, pBand->mnYTop, + pSep->mpNextSep->mnXLeft-1, pBand->mnYBottom ); + } + + pSep = pSep->mpNextSep; + } + + pBand = pBand->mpNextBand; + } + + // remove all untouched bands if bands allready left + ImplRegionBand* pPrevBand; + pBand = mpImplRegion->mpFirstBand; + while ( pBand ) + { + if ( !pBand->mbTouched ) + { + // save pointer + ImplRegionBand* pOldBand = pBand; + + // previous element of the list + if ( pBand == mpImplRegion->mpFirstBand ) + mpImplRegion->mpFirstBand = pBand->mpNextBand; + else + pPrevBand->mpNextBand = pBand->mpNextBand; + + pBand = pBand->mpNextBand; + delete pOldBand; + } + else + { + pPrevBand = pBand; + pBand = pBand->mpNextBand; + } + } + + // cleanup + if ( !mpImplRegion->OptimizeBandList() ) + { + delete mpImplRegion; + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + } + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +BOOL Region::Exclude( const Region& rRegion ) +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + ImplPolyPolyRegionToBandRegion(); + ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion(); + + // is region empty or null? -> nothing to do + if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) ) + return TRUE; + + // no instance data? -> nothing to do + if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + return TRUE; + + // no own instance data? -> make own copy! + if ( mpImplRegion->mnRefCount > 1 ) + ImplCopyData(); + + // Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden + ImplRegionBand* pBand = rRegion.mpImplRegion->mpFirstBand; + while ( pBand ) + { + // insert bands if the boundaries are not allready in the list + mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom ); + + // process all elements of the list + ImplRegionBandSep* pSep = pBand->mpFirstSep; + while ( pSep ) + { + mpImplRegion->Exclude( pSep->mnXLeft, pBand->mnYTop, + pSep->mnXRight, pBand->mnYBottom ); + pSep = pSep->mpNextSep; + } + + // Wir optimieren schon in der Schleife, da wir davon + // ausgehen, das wir insgesammt weniger Baender ueberpruefen + // muessen + if ( !mpImplRegion->OptimizeBandList() ) + { + delete mpImplRegion; + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + break; + } + + pBand = pBand->mpNextBand; + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +BOOL Region::XOr( const Region& rRegion ) +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + ImplPolyPolyRegionToBandRegion(); + ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion(); + + // is region empty or null? -> nothing to do + if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) ) + return TRUE; + + // no instance data? -> nothing to do + if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + return TRUE; + + // no own instance data? -> make own copy! + if ( mpImplRegion->mnRefCount > 1 ) + ImplCopyData(); + + // Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden + ImplRegionBand* pBand = rRegion.mpImplRegion->mpFirstBand; + while ( pBand ) + { + // insert bands if the boundaries are not allready in the list + mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom ); + + // process all elements of the list + ImplRegionBandSep* pSep = pBand->mpFirstSep; + while ( pSep ) + { + mpImplRegion->XOr( pSep->mnXLeft, pBand->mnYTop, + pSep->mnXRight, pBand->mnYBottom ); + pSep = pSep->mpNextSep; + } + + pBand = pBand->mpNextBand; + } + + // cleanup + if ( !mpImplRegion->OptimizeBandList() ) + { + delete mpImplRegion; + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +Rectangle Region::GetBoundRect() const +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + Rectangle aRect; + + // no internal data? -> region is empty! + if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + return aRect; + + // PolyPolygon data im Imp structure? + if ( mpImplRegion->mpPolyPoly ) + return mpImplRegion->mpPolyPoly->GetBoundRect(); + + // no band in the list? -> region is empty! + if ( !mpImplRegion->mpFirstBand ) + return aRect; + + // get the boundaries of the first band + long nYTop = mpImplRegion->mpFirstBand->mnYTop; + long nYBottom = mpImplRegion->mpFirstBand->mnYBottom; + long nXLeft = mpImplRegion->mpFirstBand->GetXLeftBoundary(); + long nXRight = mpImplRegion->mpFirstBand->GetXRightBoundary(); + + // look in the band list (don't test first band again!) + ImplRegionBand* pBand = mpImplRegion->mpFirstBand->mpNextBand; + while ( pBand ) + { + nYBottom = pBand->mnYBottom; + nXLeft = Min( nXLeft, pBand->GetXLeftBoundary() ); + nXRight = Max( nXRight, pBand->GetXRightBoundary() ); + + pBand = pBand->mpNextBand; + } + + // set rectangle + aRect = Rectangle( nXLeft, nYTop, nXRight, nYBottom ); + return aRect; +} + +// ----------------------------------------------------------------------- + +BOOL Region::ImplGetFirstRect( ImplRegionInfo& rImplRegionInfo, + long& rX, long& rY, + long& rWidth, long& rHeight ) const +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + ((Region*)this)->ImplPolyPolyRegionToBandRegion(); + + // no internal data? -> region is empty! + if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + return FALSE; + + // no band in the list? -> region is empty! + if ( mpImplRegion->mpFirstBand == NULL ) + return FALSE; + + // initialise pointer for first access + ImplRegionBand* pCurrRectBand = mpImplRegion->mpFirstBand; + ImplRegionBandSep* pCurrRectBandSep = pCurrRectBand->mpFirstSep; + + DBG_ASSERT( pCurrRectBandSep != NULL, "Erstes Band wurde nicht optimiert." ); + if ( !pCurrRectBandSep ) + return FALSE; + + // get boundaries of current rectangle + rX = pCurrRectBandSep->mnXLeft; + rY = pCurrRectBand->mnYTop; + rWidth = pCurrRectBandSep->mnXRight - pCurrRectBandSep->mnXLeft + 1; + rHeight = pCurrRectBand->mnYBottom - pCurrRectBand->mnYTop + 1; + + // save pointers + rImplRegionInfo.mpVoidCurrRectBand = (void*)pCurrRectBand; + rImplRegionInfo.mpVoidCurrRectBandSep = (void*)pCurrRectBandSep; + + return TRUE; +} + +// ----------------------------------------------------------------------- + +BOOL Region::ImplGetNextRect( ImplRegionInfo& rImplRegionInfo, + long& rX, long& rY, + long& rWidth, long& rHeight ) const +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + // no internal data? -> region is empty! + if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + return FALSE; + + // get last pointers + ImplRegionBand* pCurrRectBand = (ImplRegionBand*)rImplRegionInfo.mpVoidCurrRectBand; + ImplRegionBandSep* pCurrRectBandSep = (ImplRegionBandSep*)rImplRegionInfo.mpVoidCurrRectBandSep; + + // get next separation from current band + pCurrRectBandSep = pCurrRectBandSep->mpNextSep; + + // no separation found? -> go to next band! + if ( !pCurrRectBandSep ) + { + // get next band + pCurrRectBand = pCurrRectBand->mpNextBand; + + // no band found? -> not further rectangles! + if( !pCurrRectBand ) + return FALSE; + + // get first separation in current band + pCurrRectBandSep = pCurrRectBand->mpFirstSep; + } + + // get boundaries of current rectangle + rX = pCurrRectBandSep->mnXLeft; + rY = pCurrRectBand->mnYTop; + rWidth = pCurrRectBandSep->mnXRight - pCurrRectBandSep->mnXLeft + 1; + rHeight = pCurrRectBand->mnYBottom - pCurrRectBand->mnYTop + 1; + + // save new pointers + rImplRegionInfo.mpVoidCurrRectBand = (void*)pCurrRectBand; + rImplRegionInfo.mpVoidCurrRectBandSep = (void*)pCurrRectBandSep; + + return TRUE; +} + +// ----------------------------------------------------------------------- + +RegionType Region::GetType() const +{ + if ( mpImplRegion == &aImplEmptyRegion ) + return REGION_EMPTY; + else if ( mpImplRegion == &aImplNullRegion ) + return REGION_NULL; + else if ( mpImplRegion->mnRectCount == 1 ) + return REGION_RECTANGLE; + else + return REGION_COMPLEX; +} + +// ----------------------------------------------------------------------- + +BOOL Region::IsInside( const Point& rPoint ) const +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + // PolyPolygon data im Imp structure? + ((Region*)this)->ImplPolyPolyRegionToBandRegion(); +/* + if ( mpImplRegion->mpPolyPoly ) + return mpImplRegion->mpPolyPoly->IsInside( rPoint ); +*/ + + // no instance data? -> not inside + if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + return FALSE; + + // search band list + ImplRegionBand* pBand = mpImplRegion->mpFirstBand; + while ( pBand ) + { + // is point within band? + if ( (pBand->mnYTop <= rPoint.Y()) && + (pBand->mnYBottom >= rPoint.Y()) ) + { + // is point within separation of the band? + if ( pBand->IsInside( rPoint.X() ) ) + return TRUE; + else + return FALSE; + } + + pBand = pBand->mpNextBand; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL Region::IsInside( const Rectangle& rRect ) const +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + // is rectangle empty? -> not inside + if ( rRect.IsEmpty() ) + return FALSE; + + // no instance data? -> not inside + if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + return FALSE; + + // create region from rectangle and intersect own region + Region aRegion = rRect; + aRegion.Exclude( *this ); + + // rectangle is inside if exclusion is empty + return aRegion.IsEmpty(); +} + +// ----------------------------------------------------------------------- + +BOOL Region::IsOver( const Rectangle& rRect ) const +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + return FALSE; + + // Can we optimize this ??? - is used in StarDraw for brushes pointers + // Why we have no IsOver for Regions ??? + // create region from rectangle and intersect own region + Region aRegion = rRect; + aRegion.Intersect( *this ); + + // rectangle is over if include is not empty + return !aRegion.IsEmpty(); +} + +// ----------------------------------------------------------------------- + +void Region::SetNull() +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + // statische Object haben RefCount von 0 + if ( mpImplRegion->mnRefCount ) + { + if ( mpImplRegion->mnRefCount > 1 ) + mpImplRegion->mnRefCount--; + else + delete mpImplRegion; + } + + // set new type + mpImplRegion = (ImplRegion*)(&aImplNullRegion); +} + +// ----------------------------------------------------------------------- + +void Region::SetEmpty() +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + // statische Object haben RefCount von 0 + if ( mpImplRegion->mnRefCount ) + { + if ( mpImplRegion->mnRefCount > 1 ) + mpImplRegion->mnRefCount--; + else + delete mpImplRegion; + } + + // set new type + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); +} + +// ----------------------------------------------------------------------- + +Region& Region::operator=( const Region& rRegion ) +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); + DBG_ASSERT( rRegion.mpImplRegion->mnRefCount < 0xFFFFFFFE, "Region: RefCount overflow" ); + + // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann + // RefCount == 0 fuer statische Objekte + if ( rRegion.mpImplRegion->mnRefCount ) + rRegion.mpImplRegion->mnRefCount++; + + // statische Object haben RefCount von 0 + if ( mpImplRegion->mnRefCount ) + { + if ( mpImplRegion->mnRefCount > 1 ) + mpImplRegion->mnRefCount--; + else + delete mpImplRegion; + } + + mpImplRegion = rRegion.mpImplRegion; + return *this; +} + +// ----------------------------------------------------------------------- + +Region& Region::operator=( const Rectangle& rRect ) +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + // statische Object haben RefCount von 0 + if ( mpImplRegion->mnRefCount ) + { + if ( mpImplRegion->mnRefCount > 1 ) + mpImplRegion->mnRefCount--; + else + delete mpImplRegion; + } + + ImplCreateRectRegion( rRect ); + return *this; +} + +// ----------------------------------------------------------------------- + +BOOL Region::operator==( const Region& rRegion ) const +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); + + // reference to same object? -> equal! + if ( mpImplRegion == rRegion.mpImplRegion ) + return TRUE; + + if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + return FALSE; + + if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) ) + return FALSE; + + if ( rRegion.mpImplRegion->mpPolyPoly && mpImplRegion->mpPolyPoly ) + return *rRegion.mpImplRegion->mpPolyPoly == *mpImplRegion->mpPolyPoly; + else + { + ((Region*)this)->ImplPolyPolyRegionToBandRegion(); + ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion(); + + // Eine der beiden Regions kann jetzt Empty sein + if ( mpImplRegion == rRegion.mpImplRegion ) + return TRUE; + + if ( mpImplRegion == &aImplEmptyRegion ) + return FALSE; + + if ( rRegion.mpImplRegion == &aImplEmptyRegion ) + return FALSE; + } + + // initialise pointers + ImplRegionBand* pOwnRectBand = mpImplRegion->mpFirstBand; + ImplRegionBandSep* pOwnRectBandSep = pOwnRectBand->mpFirstSep; + ImplRegionBand* pSecondRectBand = rRegion.mpImplRegion->mpFirstBand; + ImplRegionBandSep* pSecondRectBandSep = pSecondRectBand->mpFirstSep; + while ( pOwnRectBandSep && pSecondRectBandSep ) + { + // get boundaries of current rectangle + long nOwnXLeft = pOwnRectBandSep->mnXLeft; + long nSecondXLeft = pSecondRectBandSep->mnXLeft; + if ( nOwnXLeft != nSecondXLeft ) + return FALSE; + + long nOwnYTop = pOwnRectBand->mnYTop; + long nSecondYTop = pSecondRectBand->mnYTop; + if ( nOwnYTop != nSecondYTop ) + return FALSE; + + long nOwnXRight = pOwnRectBandSep->mnXRight; + long nSecondXRight = pSecondRectBandSep->mnXRight; + if ( nOwnXRight != nSecondXRight ) + return FALSE; + + long nOwnYBottom = pOwnRectBand->mnYBottom; + long nSecondYBottom = pSecondRectBand->mnYBottom; + if ( nOwnYBottom != nSecondYBottom ) + return FALSE; + + // get next separation from current band + pOwnRectBandSep = pOwnRectBandSep->mpNextSep; + + // no separation found? -> go to next band! + if ( !pOwnRectBandSep ) + { + // get next band + pOwnRectBand = pOwnRectBand->mpNextBand; + + // get first separation in current band + if( pOwnRectBand ) + pOwnRectBandSep = pOwnRectBand->mpFirstSep; + } + + // get next separation from current band + pSecondRectBandSep = pSecondRectBandSep->mpNextSep; + + // no separation found? -> go to next band! + if ( !pSecondRectBandSep ) + { + // get next band + pSecondRectBand = pSecondRectBand->mpNextBand; + + // get first separation in current band + if( pSecondRectBand ) + pSecondRectBandSep = pSecondRectBand->mpFirstSep; + } + + if ( pOwnRectBandSep && !pSecondRectBandSep ) + return FALSE; + + if ( !pOwnRectBandSep && pSecondRectBandSep ) + return FALSE; + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +enum StreamEntryType { STREAMENTRY_BANDHEADER, STREAMENTRY_SEPARATION, STREAMENTRY_END }; + +SvStream& operator>>( SvStream& rIStrm, Region& rRegion ) +{ + DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); + + VersionCompat aCompat( rIStrm, STREAM_READ ); + UINT16 nVersion; + UINT16 nTmp16; + + // statische Object haben RefCount von 0 + if ( rRegion.mpImplRegion->mnRefCount ) + { + if ( rRegion.mpImplRegion->mnRefCount > 1 ) + rRegion.mpImplRegion->mnRefCount--; + else + delete rRegion.mpImplRegion; + } + + // get version of streamed region + rIStrm >> nVersion; + + // get type of region + rIStrm >> nTmp16; + + RegionType meStreamedType = (RegionType)nTmp16; + + switch( meStreamedType ) + { + case REGION_NULL: + rRegion.mpImplRegion = (ImplRegion*)&aImplNullRegion; + break; + + case REGION_EMPTY: + rRegion.mpImplRegion = (ImplRegion*)&aImplEmptyRegion; + break; + + default: + // create instance of implementation class + rRegion.mpImplRegion = new ImplRegion(); + + // get header from first element + rIStrm >> nTmp16; + + // get all bands + rRegion.mpImplRegion->mnRectCount = 0; + ImplRegionBand* pCurrBand = NULL; + while ( (StreamEntryType)nTmp16 != STREAMENTRY_END ) + { + // insert new band or new separation? + if ( (StreamEntryType)nTmp16 == STREAMENTRY_BANDHEADER ) + { + long nYTop; + long nYBottom; + + rIStrm >> nYTop; + rIStrm >> nYBottom; + + // create band + ImplRegionBand* pNewBand = new ImplRegionBand( nYTop, nYBottom ); + + // first element? -> set as first into the list + if ( !pCurrBand ) + rRegion.mpImplRegion->mpFirstBand = pNewBand; + else + pCurrBand->mpNextBand = pNewBand; + + // save pointer for next creation + pCurrBand = pNewBand; + } + else + { + long nXLeft; + long nXRight; + + rIStrm >> nXLeft; + rIStrm >> nXRight; + + // add separation + if ( pCurrBand ) + { + pCurrBand->Union( nXLeft, nXRight ); + rRegion.mpImplRegion->mnRectCount++; + } + } + + // get next header + rIStrm >> nTmp16; + } + break; + } + + return rIStrm; +} + +// ----------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rOStrm, const Region& rRegion ) +{ + DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); + + VersionCompat aCompat( rOStrm, STREAM_WRITE ); + UINT16 nVersion = 1; + + ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion(); + + // put version + rOStrm << nVersion; + + // put type + rOStrm << (UINT16)rRegion.GetType(); + + // put all bands if not null or empty + if ( (rRegion.mpImplRegion != &aImplEmptyRegion) && (rRegion.mpImplRegion != &aImplNullRegion) ) + { + ImplRegionBand* pBand = rRegion.mpImplRegion->mpFirstBand; + while ( pBand ) + { + // put boundaries + rOStrm << (UINT16) STREAMENTRY_BANDHEADER; + rOStrm << pBand->mnYTop; + rOStrm << pBand->mnYBottom; + + // put separations of current band + ImplRegionBandSep* pSep = pBand->mpFirstSep; + while ( pSep ) + { + // put separation + rOStrm << (UINT16) STREAMENTRY_SEPARATION; + rOStrm << pSep->mnXLeft; + rOStrm << pSep->mnXRight; + + // next separation from current band + pSep = pSep->mpNextSep; + } + + pBand = pBand->mpNextBand; + } + + // put endmarker + rOStrm << (UINT16) STREAMENTRY_END; + } + + return rOStrm; +} + +// ----------------------------------------------------------------------- + +RegionOverlapType Region::GetOverlapType( const Rectangle& rRect ) const +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + // is rectangle empty? -> not inside + if ( rRect.IsEmpty() ) + return REGION_OUTSIDE; + + ((Region*)this)->ImplPolyPolyRegionToBandRegion(); + + // no instance data? -> not inside + if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + return REGION_OUTSIDE; + + // resolve pointer + ImplRegionBand* pBand = mpImplRegion->mpFirstBand; + ImplRegionBandSep* pSep = pBand->mpFirstSep; + + // complex region? don't check for now. This may change in the future... + if ( pBand->mpNextBand || pSep->mpNextSep ) + return REGION_OVER; + + // get justified rectangle + long nLeft = Min( rRect.Left(), rRect.Right() ); + long nTop = Min( rRect.Top(), rRect.Bottom() ); + long nRight = Max( rRect.Left(), rRect.Right() ); + long nBottom = Max( rRect.Top(), rRect.Bottom() ); + + // check rectangle region + BOOL boLeft = (nLeft >= pSep->mnXLeft) && (nLeft < pSep->mnXRight); + BOOL boRight = (nRight <= pSep->mnXRight) && (nRight > pSep->mnXLeft); + BOOL boTop = (nTop >= pBand->mnYTop) && (nTop < pBand->mnYBottom); + BOOL boBottom = (nBottom <= pBand->mnYBottom) && (nBottom > pBand->mnYTop); + if ( boLeft && boRight && boTop && boBottom ) + return REGION_INSIDE; + if ( boLeft || boRight || boTop || boBottom ) + return REGION_OVER; + + return REGION_OUTSIDE; +} + +// ----------------------------------------------------------------------- + +void Region::ImplBeginAddRect() +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + // statische Object haben RefCount von 0 + if ( mpImplRegion->mnRefCount ) + { + if ( mpImplRegion->mnRefCount > 1 ) + mpImplRegion->mnRefCount--; + else + delete mpImplRegion; + } + + // create fresh region + mpImplRegion = new ImplRegion(); +} + +// ----------------------------------------------------------------------- + +BOOL Region::ImplAddRect( const Rectangle& rRect ) +{ + // Hier kein CheckThis, da nicht alle Daten auf Stand + + if ( rRect.IsEmpty() ) + return TRUE; + + // get justified rectangle + long nTop; + long nBottom; + long nLeft; + long nRight; + if ( rRect.Top() <= rRect.Bottom() ) + { + nTop = rRect.Top(); + nBottom = rRect.Bottom(); + } + else + { + nTop = rRect.Bottom(); + nBottom = rRect.Top(); + } + if ( rRect.Left() <= rRect.Right() ) + { + nLeft = rRect.Left(); + nRight = rRect.Right(); + } + else + { + nLeft = rRect.Right(); + nRight = rRect.Left(); + } + + if ( !mpImplRegion->mpLastCheckedBand ) + { + // create new band + mpImplRegion->mpLastCheckedBand = new ImplRegionBand( nTop, nBottom ); + + // set band as current + mpImplRegion->mpFirstBand = mpImplRegion->mpLastCheckedBand; + mpImplRegion->mpLastCheckedBand->Union( nLeft, nRight ); + } + else + { + DBG_ASSERT( nTop >= mpImplRegion->mpLastCheckedBand->mnYTop, + "Region::ImplAddRect() - nTopY < nLastTopY" ); + + // new band? create it! + if ( (nTop != mpImplRegion->mpLastCheckedBand->mnYTop) || + (nBottom != mpImplRegion->mpLastCheckedBand->mnYBottom) ) + { + // create new band + ImplRegionBand* pNewRegionBand = new ImplRegionBand( nTop, nBottom ); + + // append band to the end + mpImplRegion->mpLastCheckedBand->mpNextBand = pNewRegionBand; + + // skip to the new band + mpImplRegion->mpLastCheckedBand = mpImplRegion->mpLastCheckedBand->mpNextBand; + } + + // Insert Sep + mpImplRegion->mpLastCheckedBand->Union( nLeft, nRight ); + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +void Region::ImplEndAddRect() +{ + // check if we are empty + if ( !mpImplRegion->mpFirstBand ) + { + delete mpImplRegion; + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + return; + } + + // check if we have somthing to optimize + if ( !mpImplRegion->mpFirstBand->mpNextBand ) + { + // update mpImplRegion->mnRectCount, because no OptimizeBandList is called + ImplRegionBandSep* pSep = mpImplRegion->mpFirstBand->mpFirstSep; + mpImplRegion->mnRectCount = 0; + while( pSep ) + { + mpImplRegion->mnRectCount++; + pSep = pSep->mpNextSep; + } + + // Erst hier testen, da hier die Daten wieder stimmen + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + return; + } + + // have to revert list? -> do it now! + if ( mpImplRegion->mpFirstBand->mnYTop > + mpImplRegion->mpFirstBand->mpNextBand->mnYTop ) + { + ImplRegionBand * pNewFirstRegionBand; + + // initialize temp list with first element + pNewFirstRegionBand = mpImplRegion->mpFirstBand; + mpImplRegion->mpFirstBand = mpImplRegion->mpFirstBand->mpNextBand; + pNewFirstRegionBand->mpNextBand = NULL; + + // insert elements to the temp list + while ( mpImplRegion->mpFirstBand ) + { + ImplRegionBand * pSavedRegionBand = pNewFirstRegionBand; + pNewFirstRegionBand = mpImplRegion->mpFirstBand; + mpImplRegion->mpFirstBand = mpImplRegion->mpFirstBand->mpNextBand; + pNewFirstRegionBand->mpNextBand = pSavedRegionBand; + } + + // set temp list as new list + mpImplRegion->mpFirstBand = pNewFirstRegionBand; + } + + // cleanup + if ( !mpImplRegion->OptimizeBandList() ) + { + delete mpImplRegion; + mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + } + + // Erst hier testen, da hier die Daten wieder stimmen + DBG_CHKTHIS( Region, ImplDbgTestRegion ); +} + +// ----------------------------------------------------------------------- + +ULONG Region::GetRectCount() const +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + ((Region*)this)->ImplPolyPolyRegionToBandRegion(); + +#ifdef DBG_UTIL + ULONG nCount = 0; + + // all bands if not null or empty + if ( (mpImplRegion != &aImplEmptyRegion) && (mpImplRegion != &aImplNullRegion) ) + { + ImplRegionBand* pBand = mpImplRegion->mpFirstBand; + while ( pBand ) + { + ImplRegionBandSep* pSep = pBand->mpFirstSep; + while( pSep ) + { + nCount++; + pSep = pSep->mpNextSep; + } + + pBand = pBand->mpNextBand; + } + } + + DBG_ASSERT( mpImplRegion->mnRectCount == nCount, "Region: invalid mnRectCount!" ); +#endif + + return mpImplRegion->mnRectCount; +} + +// ----------------------------------------------------------------------- + +RegionHandle Region::BeginEnumRects() +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + ImplPolyPolyRegionToBandRegion(); + + // no internal data? -> region is empty! + if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + return NULL; + + // no band in the list? -> region is empty! + if ( mpImplRegion->mpFirstBand == NULL ) + { + DBG_ASSERT( mpImplRegion->mpFirstBand, "Region::BeginEnumRects() First Band is Empty!" ); + return NULL; + } + + ImplRegionHandle* pData = new ImplRegionHandle; + pData->mpRegion = new Region( *this ); + pData->mbFirst = TRUE; + + // save pointers + pData->mpCurrRectBand = pData->mpRegion->mpImplRegion->mpFirstBand; + pData->mpCurrRectBandSep = pData->mpCurrRectBand->mpFirstSep; + + return (RegionHandle)pData; +} + +// ----------------------------------------------------------------------- + +BOOL Region::GetEnumRects( RegionHandle pVoidData, Rectangle& rRect ) +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + ImplRegionHandle* pData = (ImplRegionHandle*)pVoidData; + if ( !pData ) + return FALSE; + + if ( pData->mbFirst ) + pData->mbFirst = FALSE; + else + { + // get next separation from current band + pData->mpCurrRectBandSep = pData->mpCurrRectBandSep->mpNextSep; + + // no separation found? -> go to next band! + if ( !pData->mpCurrRectBandSep ) + { + // get next band + pData->mpCurrRectBand = pData->mpCurrRectBand->mpNextBand; + + // no band found? -> not further rectangles! + if ( !pData->mpCurrRectBand ) + return FALSE; + + // get first separation in current band + pData->mpCurrRectBandSep = pData->mpCurrRectBand->mpFirstSep; + } + } + + // get boundaries of current rectangle + rRect.Top() = pData->mpCurrRectBand->mnYTop; + rRect.Bottom() = pData->mpCurrRectBand->mnYBottom; + rRect.Left() = pData->mpCurrRectBandSep->mnXLeft; + rRect.Right() = pData->mpCurrRectBandSep->mnXRight; + return TRUE; +} + +// ----------------------------------------------------------------------- + +void Region::EndEnumRects( RegionHandle pVoidData ) +{ + DBG_CHKTHIS( Region, ImplDbgTestRegion ); + + ImplRegionHandle* pData = (ImplRegionHandle*)pVoidData; + if ( !pData ) + return; + + // cleanup + delete pData->mpRegion; + delete pData; +} diff --git a/vcl/source/gdi/salmisc.cxx b/vcl/source/gdi/salmisc.cxx new file mode 100644 index 000000000000..50af07d0eda9 --- /dev/null +++ b/vcl/source/gdi/salmisc.cxx @@ -0,0 +1,497 @@ +/************************************************************************* + * + * $RCSfile: salmisc.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _RTL_MEMORY_H_ +#include <rtl/memory.h> +#endif +#include <bmpacc.hxx> +#include <salbtype.hxx> + +// ----------- +// - Defines - +// ----------- + +#define IMPL_CASE_GET_FORMAT( Format ) \ +case( BMP_FORMAT##Format ): \ + pFncGetPixel = BitmapReadAccess::GetPixelFor##Format; \ +break + +// ----------------------------------------------------------------------------- + +#define IMPL_CASE_SET_FORMAT( Format, BitCount ) \ +case( BMP_FORMAT##Format ): \ +{ \ + pFncSetPixel = BitmapReadAccess::SetPixelFor##Format; \ + pDstBuffer->mnBitCount = BitCount; \ +} \ +break + +// ----------------------------------------------------------------------------- + +#define DOUBLE_SCANLINES() \ +while( ( nActY < nHeight1 ) && ( pMapY[ nActY + 1 ] == nMapY ) ) \ +{ \ + HMEMCPY( pDstScanMap[ nActY + 1L ], pDstScan, rDstBuffer.mnScanlineSize ); \ + nActY++; \ +} + +// ----------- +// - Inlines - +// ----------- + +#define TC_TO_PAL_COLORS 4096 + +static long ImplIndexFromColor( const BitmapColor& rCol ) +{ +#if TC_TO_PAL_COLORS == 4096 + + return( ( ( (long) rCol.GetBlue() >> 4L) << 8L ) | + ( ( (long) rCol.GetGreen() >> 4L ) << 4L ) | + ( (long) rCol.GetRed() >> 4L ) ); + +#elif TC_TO_PAL_COLORS == 32768 + + return( ( ( (long) rCol.GetBlue() >> 3L) << 10L ) | + ( ( (long) rCol.GetGreen() >> 3L ) << 5L ) | + ( (long) rCol.GetRed() >> 3L ) ); + +#endif +} + + +#define COLOR_TO_INDEX( _def_rCol ) + +// ------------------------ +// - conversion functions - +// ------------------------ + +static void ImplPALToPAL( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer, + FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel, + Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY ) +{ + const long nWidth = rDstBuffer.mnWidth, nHeight = rDstBuffer.mnHeight, nHeight1 = nHeight - 1; + const ColorMask& rSrcMask = rSrcBuffer.maColorMask; + const ColorMask& rDstMask = rDstBuffer.maColorMask; + BitmapPalette aColMap( rSrcBuffer.maPalette.GetEntryCount() ); + BitmapColor* pColMapBuf = aColMap.ImplGetColorBuffer(); + BitmapColor aIndex( 0 ); + + for( USHORT i = 0, nCount = aColMap.GetEntryCount(); i < nCount; i++ ) + { + if( rSrcBuffer.maPalette[ i ] == rDstBuffer.maPalette[ i ] ) + aIndex.SetIndex( i ); + else + aIndex.SetIndex( rDstBuffer.maPalette.GetBestIndex( rSrcBuffer.maPalette[ i ] ) ); + + pColMapBuf[ i ] = aIndex; + } + + for( long nActY = 0, nMapY; nActY < nHeight; nActY++ ) + { + Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] ); + + for( long nX = 0L; nX < nWidth; nX++ ) + pFncSetPixel( pDstScan, nX, pColMapBuf[ pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ).GetIndex() ], rDstMask ); + + DOUBLE_SCANLINES(); + } +} + +// ----------------------------------------------------------------------------- + +static void ImplPALToTC( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer, + FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel, + Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY ) +{ + const long nWidth = rDstBuffer.mnWidth, nHeight = rDstBuffer.mnHeight, nHeight1 = nHeight - 1; + const ColorMask& rSrcMask = rSrcBuffer.maColorMask; + const ColorMask& rDstMask = rDstBuffer.maColorMask; + const BitmapColor* pColBuf = rSrcBuffer.maPalette.ImplGetColorBuffer(); + + if( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) == BMP_FORMAT_1BIT_MSB_PAL ) + { + const BitmapColor aCol0( pColBuf[ 0 ] ); + const BitmapColor aCol1( pColBuf[ 1 ] ); + long nMapX; + + for( long nActY = 0, nMapY; nActY < nHeight; nActY++ ) + { + Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] ); + + for( long nX = 0L; nX < nWidth; ) + { + nMapX = pMapX[ nX ]; + pFncSetPixel( pDstScan, nX++, + pSrcScan[ nMapX >> 3 ] & ( 1 << ( 7 - ( nMapX & 7 ) ) ) ? aCol1 : aCol0, + rDstMask ); + } + + DOUBLE_SCANLINES(); + } + } + else if( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) == BMP_FORMAT_4BIT_MSN_PAL ) + { + long nMapX; + + for( long nActY = 0, nMapY; nActY < nHeight; nActY++ ) + { + Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] ); + + for( long nX = 0L; nX < nWidth; ) + { + nMapX = pMapX[ nX ]; + pFncSetPixel( pDstScan, nX++, + pColBuf[ ( pSrcScan[ nMapX >> 1 ] >> ( nMapX & 1 ? 0 : 4 ) ) & 0x0f ], + rDstMask ); + } + + DOUBLE_SCANLINES(); + } + } + else if( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) == BMP_FORMAT_8BIT_PAL ) + { + for( long nActY = 0, nMapY; nActY < nHeight; nActY++ ) + { + Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] ); + + for( long nX = 0L; nX < nWidth; nX++ ) + pFncSetPixel( pDstScan, nX, pColBuf[ pSrcScan[ pMapX[ nX ] ] ], rDstMask ); + + DOUBLE_SCANLINES(); + } + } + else + { + for( long nActY = 0, nMapY; nActY < nHeight; nActY++ ) + { + Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] ); + + for( long nX = 0L; nX < nWidth; nX++ ) + pFncSetPixel( pDstScan, nX, pColBuf[ pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ).GetIndex() ], rDstMask ); + + DOUBLE_SCANLINES(); + } + } +} + +// ----------------------------------------------------------------------------- + +static void ImplTCToTC( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer, + FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel, + Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY ) +{ + const long nWidth = rDstBuffer.mnWidth, nHeight = rDstBuffer.mnHeight, nHeight1 = nHeight - 1; + const ColorMask& rSrcMask = rSrcBuffer.maColorMask; + const ColorMask& rDstMask = rDstBuffer.maColorMask; + + if( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) == BMP_FORMAT_24BIT_TC_BGR ) + { + BitmapColor aCol; + BYTE* pPixel; + + for( long nActY = 0, nMapY; nActY < nHeight; nActY++ ) + { + Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] ); + + for( long nX = 0L; nX < nWidth; nX++ ) + { + aCol.SetBlue( *( pPixel = ( pSrcScan + pMapX[ nX ] * 3 ) )++ ); + aCol.SetGreen( *pPixel++ ); + aCol.SetRed( *pPixel ); + pFncSetPixel( pDstScan, nX, aCol, rDstMask ); + } + + DOUBLE_SCANLINES() + } + } + else + { + for( long nActY = 0, nMapY; nActY < nHeight; nActY++ ) + { + Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] ); + + for( long nX = 0L; nX < nWidth; nX++ ) + pFncSetPixel( pDstScan, nX, pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ), rDstMask ); + + DOUBLE_SCANLINES(); + } + } +} + +// ----------------------------------------------------------------------------- + +static void ImplTCToPAL( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer, + FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel, + Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY ) +{ + const long nWidth = rDstBuffer.mnWidth, nHeight = rDstBuffer.mnHeight, nHeight1 = nHeight - 1; + const ColorMask& rSrcMask = rSrcBuffer.maColorMask; + const ColorMask& rDstMask = rDstBuffer.maColorMask; + BitmapPalette aColMap( rSrcBuffer.maPalette.GetEntryCount() ); + BYTE* pColToPalMap = new BYTE[ TC_TO_PAL_COLORS ]; + BitmapColor aIndex( 0 ); + + for( long nR = 0; nR < 16; nR++ ) + { + for( long nG = 0; nG < 16; nG++ ) + { + for( long nB = 0; nB < 16; nB++ ) + { + BitmapColor aCol( nR << 4, nG << 4, nB << 4 ); + pColToPalMap[ ImplIndexFromColor( aCol ) ] = (BYTE) rDstBuffer.maPalette.GetBestIndex( aCol ); + } + } + } + + for( long nActY = 0, nMapY; nActY < nHeight; nActY++ ) + { + Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] ); + + for( long nX = 0L; nX < nWidth; nX++ ) + { + aIndex.SetIndex( pColToPalMap[ ImplIndexFromColor( pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ) ) ] ); + pFncSetPixel( pDstScan, nX, aIndex, rDstMask ); + } + + DOUBLE_SCANLINES(); + } + + delete[] pColToPalMap; +} + +// --------------------- +// - StretchAndConvert - +// --------------------- + +BitmapBuffer* StretchAndConvert( const BitmapBuffer& rSrcBuffer, const SalTwoRect& rTwoRect, + ULONG nDstBitmapFormat, BitmapPalette* pDstPal, ColorMask* pDstMask ) +{ + FncGetPixel pFncGetPixel; + FncSetPixel pFncSetPixel; + BitmapBuffer* pDstBuffer = new BitmapBuffer; + const ULONG nDstScanlineFormat = BMP_SCANLINE_FORMAT( nDstBitmapFormat ); + const long nSrcX = rTwoRect.mnSrcX, nSrcY = rTwoRect.mnSrcY; + const long nSrcDX = rTwoRect.mnSrcWidth, nSrcDY = rTwoRect.mnSrcHeight; + const long nDstDX = rTwoRect.mnDestWidth, nDstDY = rTwoRect.mnDestHeight; + Scanline* pSrcScan = new Scanline[ rSrcBuffer.mnHeight ]; + Scanline* pDstScan = new Scanline[ nDstDY ]; + long* pMapX = new long[ nDstDX ]; + long* pMapY = new long[ nDstDY ]; + Scanline pTmpScan; + long i, nTmp, nOffset; + + // set function for getting pixels + switch( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) ) + { + IMPL_CASE_GET_FORMAT( _1BIT_MSB_PAL ); + IMPL_CASE_GET_FORMAT( _1BIT_LSB_PAL ); + IMPL_CASE_GET_FORMAT( _4BIT_MSN_PAL ); + IMPL_CASE_GET_FORMAT( _4BIT_LSN_PAL ); + IMPL_CASE_GET_FORMAT( _8BIT_PAL ); + IMPL_CASE_GET_FORMAT( _8BIT_TC_MASK ); + IMPL_CASE_GET_FORMAT( _16BIT_TC_MASK ); + IMPL_CASE_GET_FORMAT( _24BIT_TC_BGR ); + IMPL_CASE_GET_FORMAT( _24BIT_TC_RGB ); + IMPL_CASE_GET_FORMAT( _24BIT_TC_MASK ); + IMPL_CASE_GET_FORMAT( _32BIT_TC_ABGR ); + IMPL_CASE_GET_FORMAT( _32BIT_TC_ARGB ); + IMPL_CASE_GET_FORMAT( _32BIT_TC_BGRA ); + IMPL_CASE_GET_FORMAT( _32BIT_TC_RGBA ); + IMPL_CASE_GET_FORMAT( _32BIT_TC_MASK ); + + default: + DBG_ERROR( "unknown read format" ); + break; + } + + // set function for setting pixels + switch( nDstScanlineFormat ) + { + IMPL_CASE_SET_FORMAT( _1BIT_MSB_PAL, 1 ); + IMPL_CASE_SET_FORMAT( _1BIT_LSB_PAL, 1 ); + IMPL_CASE_SET_FORMAT( _4BIT_MSN_PAL, 1 ); + IMPL_CASE_SET_FORMAT( _4BIT_LSN_PAL, 4 ); + IMPL_CASE_SET_FORMAT( _8BIT_PAL, 8 ); + IMPL_CASE_SET_FORMAT( _8BIT_TC_MASK, 8 ); + IMPL_CASE_SET_FORMAT( _16BIT_TC_MASK, 16 ); + IMPL_CASE_SET_FORMAT( _24BIT_TC_BGR, 24 ); + IMPL_CASE_SET_FORMAT( _24BIT_TC_RGB, 24 ); + IMPL_CASE_SET_FORMAT( _24BIT_TC_MASK, 24 ); + IMPL_CASE_SET_FORMAT( _32BIT_TC_ABGR, 32 ); + IMPL_CASE_SET_FORMAT( _32BIT_TC_ARGB, 32 ); + IMPL_CASE_SET_FORMAT( _32BIT_TC_BGRA, 32 ); + IMPL_CASE_SET_FORMAT( _32BIT_TC_RGBA, 32 ); + IMPL_CASE_SET_FORMAT( _32BIT_TC_MASK, 32 ); + + default: + DBG_ERROR( "unknown write format" ); + break; + } + + // fill destination buffer + pDstBuffer->mnFormat = nDstBitmapFormat; + pDstBuffer->mnWidth = nDstDX; + pDstBuffer->mnHeight = nDstDY; + pDstBuffer->mnScanlineSize = AlignedWidth4Bytes( pDstBuffer->mnBitCount * nDstDX ); + pDstBuffer->mpBits = new BYTE[ pDstBuffer->mnScanlineSize * nDstDY ]; + rtl_zeroMemory( pDstBuffer->mpBits, pDstBuffer->mnScanlineSize * nDstDY ); + + // do we need a destination palette or color mask? + if( ( nDstScanlineFormat == BMP_FORMAT_1BIT_MSB_PAL ) || + ( nDstScanlineFormat == BMP_FORMAT_1BIT_LSB_PAL ) || + ( nDstScanlineFormat == BMP_FORMAT_4BIT_MSN_PAL ) || + ( nDstScanlineFormat == BMP_FORMAT_4BIT_LSN_PAL ) || + ( nDstScanlineFormat == BMP_FORMAT_8BIT_PAL ) ) + { + DBG_ASSERT( pDstPal, "destination buffer requires palette" ); + pDstBuffer->maPalette = *pDstPal; + } + else if( ( nDstScanlineFormat == BMP_FORMAT_8BIT_TC_MASK ) || + ( nDstScanlineFormat == BMP_FORMAT_16BIT_TC_MASK ) || + ( nDstScanlineFormat == BMP_FORMAT_24BIT_TC_MASK ) || + ( nDstScanlineFormat == BMP_FORMAT_32BIT_TC_MASK ) ) + { + DBG_ASSERT( pDstMask, "destination buffer requires color mask" ); + pDstBuffer->maColorMask = *pDstMask; + } + + // horizontal mapping table + if( nDstDX != nSrcDX ) + { + const double fFactorX = ( nDstDX > 1 ) ? (double) ( nSrcDX - 1 ) / ( nDstDX - 1 ) : 0.0; + + for( i = 0L; i < nDstDX; i++ ) + pMapX[ i ] = nSrcX + FRound( i * fFactorX ); + } + else + { + for( i = 0L, nTmp = nSrcX; i < nDstDX; i++ ) + pMapX[ i ] = nTmp++; + } + + // vertical mapping table + if( nDstDY != nSrcDY ) + { + const double fFactorY = ( nDstDY > 1 ) ? (double) ( nSrcDY - 1 ) / ( nDstDY - 1 ) : 0.0; + + for( i = 0L; i < nDstDY; i++ ) + pMapY[ i ] = nSrcY + FRound( i * fFactorY ); + } + else + { + for( i = 0L, nTmp = nSrcY; i < nDstDY; i++ ) + pMapY[ i ] = nTmp++; + } + + // source scanline buffer + if( BMP_SCANLINE_ADJUSTMENT( rSrcBuffer.mnFormat ) == BMP_FORMAT_TOP_DOWN ) + pTmpScan = rSrcBuffer.mpBits, nOffset = rSrcBuffer.mnScanlineSize; + else + { + pTmpScan = rSrcBuffer.mpBits + ( rSrcBuffer.mnHeight - 1 ) * rSrcBuffer.mnScanlineSize; + nOffset = -rSrcBuffer.mnScanlineSize; + } + + for( i = 0L; i < rSrcBuffer.mnHeight; i++, pTmpScan += nOffset ) + pSrcScan[ i ] = pTmpScan; + + // destination scanline buffer + if( BMP_SCANLINE_ADJUSTMENT( pDstBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN ) + pTmpScan = pDstBuffer->mpBits, nOffset = pDstBuffer->mnScanlineSize; + else + { + pTmpScan = pDstBuffer->mpBits + ( nDstDY - 1 ) * pDstBuffer->mnScanlineSize; + nOffset = -pDstBuffer->mnScanlineSize; + } + + for( i = 0L; i < nDstDY; i++, pTmpScan += nOffset ) + pDstScan[ i ] = pTmpScan; + + // do buffer scaling and conversion + if( rSrcBuffer.mnBitCount <= 8 && pDstBuffer->mnBitCount <= 8 ) + { + ImplPALToPAL( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel, + pSrcScan, pDstScan, pMapX, pMapY ); + } + else if( rSrcBuffer.mnBitCount <= 8 && pDstBuffer->mnBitCount > 8 ) + { + ImplPALToTC( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel, + pSrcScan, pDstScan, pMapX, pMapY ); + } + else if( rSrcBuffer.mnBitCount > 8 && pDstBuffer->mnBitCount > 8 ) + { + ImplTCToTC( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel, + pSrcScan, pDstScan, pMapX, pMapY ); + } + else + { + ImplTCToPAL( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel, + pSrcScan, pDstScan, pMapX, pMapY ); + } + + // cleanup + delete[] pSrcScan; + delete[] pDstScan; + delete[] pMapX; + delete[] pMapY; + + return pDstBuffer; +} diff --git a/vcl/source/gdi/svcompat.cxx b/vcl/source/gdi/svcompat.cxx new file mode 100644 index 000000000000..dc037185e064 --- /dev/null +++ b/vcl/source/gdi/svcompat.cxx @@ -0,0 +1,117 @@ +/************************************************************************* + * + * $RCSfile: svcompat.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_COMPAT_CXX + +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif + +#ifndef _SV_SVCOMPAT_HXX +#include <svcompat.hxx> +#endif + +// -------------- +// - ImplCompat - +// -------------- + +ImplCompat::ImplCompat( SvStream& rStm, USHORT nStreamMode, USHORT nVersion ) : + mpRWStm ( &rStm ), + mnStmMode ( nStreamMode ), + mnVersion ( nVersion ) +{ + if( !mpRWStm->GetError() ) + { + if( STREAM_WRITE == mnStmMode ) + { + *mpRWStm << mnVersion; + mnTotalSize = ( mnCompatPos = mpRWStm->Tell() ) + 4UL; + mpRWStm->SeekRel( 4L ); + } + else + { + *mpRWStm >> mnVersion; + *mpRWStm >> mnTotalSize; + mnCompatPos = mpRWStm->Tell(); + } + } +} + +// ------------------------------------------------------------------------ + +ImplCompat::~ImplCompat() +{ + if( STREAM_WRITE == mnStmMode ) + { + const UINT32 nEndPos = mpRWStm->Tell(); + + mpRWStm->Seek( mnCompatPos ); + *mpRWStm << ( nEndPos - mnTotalSize ); + mpRWStm->Seek( nEndPos ); + } + else + { + const UINT32 nReadSize = mpRWStm->Tell() - mnCompatPos; + + if( mnTotalSize > nReadSize ) + mpRWStm->SeekRel( mnTotalSize - nReadSize ); + } +} diff --git a/vcl/source/gdi/virdev.cxx b/vcl/source/gdi/virdev.cxx new file mode 100644 index 000000000000..ff8c7268c9fe --- /dev/null +++ b/vcl/source/gdi/virdev.cxx @@ -0,0 +1,442 @@ +/************************************************************************* + * + * $RCSfile: virdev.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_VIRDEV_CXX + +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif + +#ifndef REMOTE_APPSERVER +#ifndef _SV_SALINST_HXX +#include <salinst.hxx> +#endif +#ifndef _SV_SALGDI_HXX +#include <salgdi.hxx> +#endif +#ifndef _SV_SALFRAME_HXX +#include <salframe.hxx> +#endif +#ifndef _SV_SALVD_HXX +#include <salvd.hxx> +#endif +#endif + +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _SV_SVDATA_HXX +#include <svdata.hxx> +#endif +#ifndef _SV_SETTINGS_HXX +#include <settings.hxx> +#endif +#ifndef _SV_SVAPP_HXX +#include <svapp.hxx> +#endif +#ifndef _SV_WRKWIN_HXX +#include <wrkwin.hxx> +#endif +#ifndef _SV_OUTDEV_H +#include <outdev.h> +#endif +#ifndef _SV_VIRDEV_HXX +#include <virdev.hxx> +#endif + +using namespace ::com::sun::star::uno; + +// appserver +#ifdef REMOTE_APPSERVER +#ifndef _SV_RMOUTDEV_HXX +#include <rmoutdev.hxx> +#endif +#ifndef _SV_RMVIRDEV_HXX +#include <rmvirdev.hxx> +#endif +#ifndef _VCL_RMCACHE_HXX_ +#include <rmcache.hxx> +#endif +#endif + +// ======================================================================= + +// interface cache +#ifdef REMOTE_APPSERVER + +static ::vcl::InterfacePairCache< ::com::sun::star::portal::client::XRmVirtualDevice, ::com::sun::star::portal::client::XRmOutputDevice >* pRemoteVirdevCache = NULL; + +typedef ::std::pair< ::com::sun::star::uno::Reference< ::com::sun::star::portal::client::XRmVirtualDevice >, ::com::sun::star::uno::Reference< ::com::sun::star::portal::client::XRmOutputDevice > > virdevInterfacePair; + +void eraseRemoteVirdevCache() +{ + if( pRemoteVirdevCache ) + { + delete pRemoteVirdevCache; + pRemoteVirdevCache = NULL; + } +} + +#endif + +// ======================================================================= + +void VirtualDevice::ImplInitVirDev( const OutputDevice* pOutDev, + long nDX, long nDY, USHORT nBitCount ) +{ + DBG_ASSERT( nBitCount <= 1, + "VirtualDevice::VirtualDevice(): Only 0 or 1 is for BitCount allowed" ); + + if ( nDX < 1 ) + nDX = 1; + + if ( nDY < 1 ) + nDY = 1; + + ImplSVData* pSVData = ImplGetSVData(); + + if ( !pOutDev ) + pOutDev = ImplGetDefaultWindow(); + +#ifndef REMOTE_APPSERVER + SalGraphics* pGraphics; + if ( !pOutDev->mpGraphics ) + ((OutputDevice*)pOutDev)->ImplGetGraphics(); + pGraphics = pOutDev->mpGraphics; + if ( pGraphics ) + mpVirDev = pSVData->mpDefInst->CreateVirtualDevice( pGraphics, nDX, nDY, nBitCount ); + else + mpVirDev = NULL; + if ( !mpVirDev ) + GetpApp()->Exception( EXC_SYSOBJNOTCREATED ); +#else + if( ! pRemoteVirdevCache ) + { + ImplSVData* pSVData = ImplGetSVData(); + pRemoteVirdevCache = new ::vcl::InterfacePairCache< ::com::sun::star::portal::client::XRmVirtualDevice, ::com::sun::star::portal::client::XRmOutputDevice >( + pSVData->mxMultiFactory, + ::rtl::OUString::createFromAscii( "OfficeVirtualDevice.stardiv.de" ), + 20, 10, 40 ); + } + + if( pOutDev->GetOutDevType() == OUTDEV_PRINTER || ! mpVirDev ) + { + virdevInterfacePair aPair = pRemoteVirdevCache->takeInterface(); + if( aPair.first.is() && aPair.second.is() ) + { + if( ! mpVirDev ) + mpVirDev = new RmVirtualDevice; + mpVirDev->SetInterface( aPair.first ); + mpVirDev->Create( (ULONG) pOutDev, nDX, nDY, nBitCount ); + + if( ! mpGraphics ) + mpGraphics = new ImplServerGraphics(); + mpGraphics->SetInterface( aPair.second ); + } + } + else + { + // this was done in ImpGetServerGraphics before + // and is now here because of interface caching + if( mpGraphics && mpGraphics->GetInterface().is() ) + { + try + { + mpGraphics->GetInterface()->SetFillColor( mpGraphics->maFillColor.GetColor() ); + } + catch (...) + { + if( mpGraphics ) + delete mpGraphics, mpGraphics = NULL; + + if( mpVirDev ) + { + virdevInterfacePair aPair = pRemoteVirdevCache->takeInterface(); + if( aPair.first.is() && aPair.second.is() ) + { + mpVirDev->SetInterface( aPair.first ); + mpVirDev->Create( (ULONG)NULL, mnOutWidth, mnOutHeight, mnBitCount ); + mpGraphics = new ImplServerGraphics(); + mpGraphics->SetInterface( aPair.second ); + } + else + mpVirDev->SetInterface( REF( NMSP_CLIENT::XRmVirtualDevice )() ); + } + } + } + ImplGetServerGraphics( TRUE ); + } +#endif + + mnBitCount = ( nBitCount ? nBitCount : pOutDev->GetBitCount() ); + mnOutWidth = nDX; + mnOutHeight = nDY; + mbScreenComp = TRUE; + + if ( pOutDev->GetOutDevType() == OUTDEV_PRINTER ) + mbScreenComp = FALSE; + else if ( pOutDev->GetOutDevType() == OUTDEV_VIRDEV ) + mbScreenComp = ((VirtualDevice*)pOutDev)->mbScreenComp; + + meOutDevType = OUTDEV_VIRDEV; + mbDevOutput = TRUE; + mpFontList = pSVData->maGDIData.mpScreenFontList; + mpFontCache = pSVData->maGDIData.mpScreenFontCache; + mnDPIX = pOutDev->mnDPIX; + mnDPIY = pOutDev->mnDPIY; + maFont = pOutDev->maFont; + + // Virtuelle Devices haben defaultmaessig einen weissen Hintergrund + SetBackground( Wallpaper( Color( COL_WHITE ) ) ); + Erase(); + + // VirDev in Liste eintragen + mpNext = pSVData->maGDIData.mpFirstVirDev; + mpPrev = NULL; + if ( mpNext ) + mpNext->mpPrev = this; + else + pSVData->maGDIData.mpLastVirDev = this; + pSVData->maGDIData.mpFirstVirDev = this; +} + +// ----------------------------------------------------------------------- + +VirtualDevice::VirtualDevice( USHORT nBitCount ) + : mpVirDev( NULL ) +{ + DBG_TRACE1( "VirtualDevice::VirtualDevice( %hu )", nBitCount ); + + ImplInitVirDev( Application::GetDefaultDevice(), 1, 1, nBitCount ); +} + +// ----------------------------------------------------------------------- + +VirtualDevice::VirtualDevice( const OutputDevice& rCompDev, USHORT nBitCount ) + : mpVirDev( NULL ) +{ + DBG_TRACE1( "VirtualDevice::VirtualDevice( %hu )", nBitCount ); + + ImplInitVirDev( &rCompDev, 1, 1, nBitCount ); +} + +// ----------------------------------------------------------------------- + +VirtualDevice::~VirtualDevice() +{ + DBG_TRACE( "VirtualDevice::~VirtualDevice()" ); + + ImplSVData* pSVData = ImplGetSVData(); + +#ifndef REMOTE_APPSERVER + ImplReleaseGraphics(); + + if ( mpVirDev ) + pSVData->mpDefInst->DestroyVirtualDevice( mpVirDev ); +#else + if ( pRemoteVirdevCache && mpVirDev && mpGraphics ) + { + virdevInterfacePair aPair( mpVirDev->GetInterface(), mpGraphics->GetInterface() ); + aPair.first->Create( 0, 0, 0, 0 ); + pRemoteVirdevCache->putInterface( aPair ); + } + + mpGraphics->SetInterface( REF( NMSP_CLIENT::XRmOutputDevice )() ); + ImplReleaseServerGraphics(); + delete mpVirDev; + delete mpGraphics; +#endif + + // VirDev aus der Liste eintragen + if( mpPrev ) + mpPrev->mpNext = mpNext; + else + pSVData->maGDIData.mpFirstVirDev = mpNext; + + if( mpNext ) + mpNext->mpPrev = mpPrev; + else + pSVData->maGDIData.mpLastVirDev = mpPrev; +} + +// ----------------------------------------------------------------------- + +BOOL VirtualDevice::SetOutputSizePixel( const Size& rNewSize, BOOL bErase ) +{ + DBG_TRACE3( "VirtualDevice::SetOutputSizePixel( %ld, %ld, %d )", rNewSize.Width(), rNewSize.Height(), (int)bErase ); + + if ( !mpVirDev ) + return FALSE; + else if ( rNewSize == GetOutputSizePixel() ) + { + if ( bErase ) + Erase(); + return TRUE; + } + +#ifdef REMOTE_APPSERVER + long nOldWidth = mnOutWidth, nOldHeight = mnOutHeight; + + try + { + mnOutWidth = rNewSize.Width(); + mnOutHeight = rNewSize.Height(); + mpVirDev->ResizeOutputSizePixel( mnOutWidth, mnOutHeight ); + } + catch (...) + { + delete mpVirDev, mpVirDev = NULL; + ImplInitVirDev( NULL, mnOutWidth, mnOutHeight, mnBitCount ); + } + + if( bErase ) + Erase(); + else + { + if ( nOldWidth < mnOutWidth ) + Erase( Rectangle( Point( nOldWidth, 0 ), Size( mnOutWidth-nOldWidth, Max( nOldHeight, mnOutHeight ) ) ) ); + if ( nOldHeight< mnOutHeight ) + Erase( Rectangle( Point( 0, nOldHeight ), Size( Max( nOldWidth, mnOutWidth ), mnOutHeight-nOldHeight ) ) ); + } + + return TRUE; +#else + BOOL bRet; + long nNewWidth = rNewSize.Width(), nNewHeight = rNewSize.Height(); + + if ( nNewWidth < 1 ) + nNewWidth = 1; + + if ( nNewHeight < 1 ) + nNewHeight = 1; + + if ( bErase ) + { + bRet = mpVirDev->SetSize( nNewWidth, nNewHeight ); + + if ( bRet ) + { + mnOutWidth = rNewSize.Width(); + mnOutHeight = rNewSize.Height(); + Erase(); + } + } + else + { + SalVirtualDevice* pNewVirDev; + ImplSVData* pSVData = ImplGetSVData(); + + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return FALSE; + } + + pNewVirDev = pSVData->mpDefInst->CreateVirtualDevice( mpGraphics, nNewWidth, nNewHeight, mnBitCount ); + if ( pNewVirDev ) + { + SalGraphics* pGraphics = pNewVirDev->GetGraphics(); + if ( pGraphics ) + { + SalTwoRect aPosAry; + long nWidth; + long nHeight; + if ( mnOutWidth < nNewWidth ) + nWidth = mnOutWidth; + else + nWidth = nNewWidth; + if ( mnOutHeight < nNewHeight ) + nHeight = mnOutHeight; + else + nHeight = nNewHeight; + aPosAry.mnSrcX = 0; + aPosAry.mnSrcY = 0; + aPosAry.mnSrcWidth = nWidth; + aPosAry.mnSrcHeight = nHeight; + aPosAry.mnDestX = 0; + aPosAry.mnDestY = 0; + aPosAry.mnDestWidth = nWidth; + aPosAry.mnDestHeight = nHeight; + + pGraphics->CopyBits( &aPosAry, mpGraphics ); + pNewVirDev->ReleaseGraphics( pGraphics ); + ImplReleaseGraphics(); + pSVData->mpDefInst->DestroyVirtualDevice( mpVirDev ); + mpVirDev = pNewVirDev; + mnOutWidth = rNewSize.Width(); + mnOutHeight = rNewSize.Height(); + bRet = TRUE; + } + else + { + bRet = FALSE; + pSVData->mpDefInst->DestroyVirtualDevice( pNewVirDev ); + } + } + else + bRet = FALSE; + } + + return bRet; +#endif +} + diff --git a/vcl/source/gdi/wall.cxx b/vcl/source/gdi/wall.cxx new file mode 100644 index 000000000000..64eb82b23585 --- /dev/null +++ b/vcl/source/gdi/wall.cxx @@ -0,0 +1,616 @@ +/************************************************************************* + * + * $RCSfile: wall.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:05:39 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SV_WALL_CXX + +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif +#ifndef _VCOMPAT_HXX +#include <tools/vcompat.hxx> +#endif +#ifndef _DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _SV_BITMAPEX_HXX +#include <bitmapex.hxx> +#endif +#ifndef _SV_GRADIENT_HXX +#include <gradient.hxx> +#endif +#ifndef _SV_WALL_HXX +#include <wall.hxx> +#endif + +// ======================================================================= + +DBG_NAME( Wallpaper ); + +// ----------------------------------------------------------------------- + +ImplWallpaper::ImplWallpaper() : + maColor( COL_TRANSPARENT ) +{ + mnRefCount = 1; + mpBitmap = NULL; + mpCache = NULL; + mpGradient = NULL; + mpRect = NULL; + meStyle = WALLPAPER_NULL; +} + +// ----------------------------------------------------------------------- + +ImplWallpaper::ImplWallpaper( const ImplWallpaper& rImplWallpaper ) : + maColor( rImplWallpaper.maColor ) +{ + mnRefCount = 1; + meStyle = rImplWallpaper.meStyle; + + if ( rImplWallpaper.mpBitmap ) + mpBitmap = new BitmapEx( *rImplWallpaper.mpBitmap ); + else + mpBitmap = NULL; + if( rImplWallpaper.mpCache ) + mpCache = new BitmapEx( *rImplWallpaper.mpCache ); + else + mpCache = NULL; + if ( rImplWallpaper.mpGradient ) + mpGradient = new Gradient( *rImplWallpaper.mpGradient ); + else + mpGradient = NULL; + if ( rImplWallpaper.mpRect ) + mpRect = new Rectangle( *rImplWallpaper.mpRect ); + else + mpRect = NULL; +} + +// ----------------------------------------------------------------------- + +ImplWallpaper::~ImplWallpaper() +{ + delete mpBitmap; + delete mpCache; + delete mpGradient; + delete mpRect; +} + +// ----------------------------------------------------------------------- + +void ImplWallpaper::ImplSetCachedBitmap( BitmapEx& rBmp ) +{ + if( !mpCache ) + mpCache = new BitmapEx( rBmp ); + else + *mpCache = rBmp; +} + +// ----------------------------------------------------------------------- + +void ImplWallpaper::ImplReleaseCachedBitmap() +{ + delete mpCache; + mpCache = NULL; +} + +// ----------------------------------------------------------------------- + +SvStream& operator>>( SvStream& rIStm, ImplWallpaper& rImplWallpaper ) +{ + VersionCompat aCompat( rIStm, STREAM_READ ); + UINT16 nTmp16; + + delete rImplWallpaper.mpRect; + rImplWallpaper.mpRect = NULL; + + delete rImplWallpaper.mpGradient; + rImplWallpaper.mpGradient = NULL; + + delete rImplWallpaper.mpBitmap; + rImplWallpaper.mpBitmap = NULL; + + // version 1 + rIStm >> rImplWallpaper.maColor; + rIStm >> nTmp16; rImplWallpaper.meStyle = (WallpaperStyle) nTmp16; + + // version 2 + if( aCompat.GetVersion() >= 2 ) + { + BOOL bRect, bGrad, bBmp, bDummy; + + rIStm >> bRect >> bGrad >> bBmp >> bDummy >> bDummy >> bDummy; + + if( bRect ) + { + rImplWallpaper.mpRect = new Rectangle; + rIStm >> *rImplWallpaper.mpRect; + } + + if( bGrad ) + { + rImplWallpaper.mpGradient = new Gradient; + rIStm >> *rImplWallpaper.mpGradient; + } + + if( bBmp ) + { + rImplWallpaper.mpBitmap = new BitmapEx; + rIStm >> *rImplWallpaper.mpBitmap; + } + + // version 3 (new color format) + if( aCompat.GetVersion() >= 3 ) + { + rImplWallpaper.maColor.Read( rIStm, TRUE ); + } + } + + return rIStm; +} + +// ----------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rOStm, const ImplWallpaper& rImplWallpaper ) +{ + VersionCompat aCompat( rOStm, STREAM_WRITE, 3 ); + BOOL bRect = ( rImplWallpaper.mpRect != NULL ); + BOOL bGrad = ( rImplWallpaper.mpGradient != NULL ); + BOOL bBmp = ( rImplWallpaper.mpBitmap != NULL ); + BOOL bDummy = FALSE; + + // version 1 + rOStm << rImplWallpaper.maColor << (UINT16) rImplWallpaper.meStyle; + + // version 2 + rOStm << bRect << bGrad << bBmp << bDummy << bDummy << bDummy; + + if( bRect ) + rOStm << *rImplWallpaper.mpRect; + + if( bGrad ) + rOStm << *rImplWallpaper.mpGradient; + + if( bBmp ) + rOStm << *rImplWallpaper.mpBitmap; + + // version 3 (new color format) + ( (Color&) rImplWallpaper.maColor ).Write( rOStm, TRUE ); + + return rOStm; +} + +// ----------------------------------------------------------------------- + +inline void Wallpaper::ImplMakeUnique( BOOL bReleaseCache ) +{ + // Falls noch andere Referenzen bestehen, dann kopieren + if ( mpImplWallpaper->mnRefCount != 1 ) + { + if ( mpImplWallpaper->mnRefCount ) + mpImplWallpaper->mnRefCount--; + mpImplWallpaper = new ImplWallpaper( *(mpImplWallpaper) ); + } + + if( bReleaseCache ) + mpImplWallpaper->ImplReleaseCachedBitmap(); +} + +// ----------------------------------------------------------------------- + +Wallpaper::Wallpaper() +{ + DBG_CTOR( Wallpaper, NULL ); + +#ifdef WIN + static ImplWallpaper _near aStaticImplWallpaper; +#else + static ImplWallpaper aStaticImplWallpaper; +#endif + + aStaticImplWallpaper.mnRefCount = 0; + mpImplWallpaper = &aStaticImplWallpaper; +} + +// ----------------------------------------------------------------------- + +Wallpaper::Wallpaper( const Wallpaper& rWallpaper ) +{ + DBG_CTOR( Wallpaper, NULL ); + DBG_CHKOBJ( &rWallpaper, Wallpaper, NULL ); + DBG_ASSERT( rWallpaper.mpImplWallpaper->mnRefCount < 0xFFFE, "Wallpaper: RefCount overflow" ); + + // Instance Daten uebernehmen und Referenzcounter erhoehen + mpImplWallpaper = rWallpaper.mpImplWallpaper; + // RefCount == 0 fuer statische Objekte + if ( mpImplWallpaper->mnRefCount ) + mpImplWallpaper->mnRefCount++; +} + +// ----------------------------------------------------------------------- + +Wallpaper::Wallpaper( const Color& rColor ) +{ + DBG_CTOR( Wallpaper, NULL ); + + mpImplWallpaper = new ImplWallpaper; + mpImplWallpaper->maColor = rColor; + mpImplWallpaper->meStyle = WALLPAPER_TILE; +} + +// ----------------------------------------------------------------------- + +Wallpaper::Wallpaper( const BitmapEx& rBmpEx ) +{ + DBG_CTOR( Wallpaper, NULL ); + + mpImplWallpaper = new ImplWallpaper; + mpImplWallpaper->mpBitmap = new BitmapEx( rBmpEx ); + mpImplWallpaper->meStyle = WALLPAPER_TILE; +} + +// ----------------------------------------------------------------------- + +Wallpaper::Wallpaper( const Gradient& rGradient ) +{ + DBG_CTOR( Wallpaper, NULL ); + + mpImplWallpaper = new ImplWallpaper; + mpImplWallpaper->mpGradient = new Gradient( rGradient ); + mpImplWallpaper->meStyle = WALLPAPER_TILE; +} + +// ----------------------------------------------------------------------- + +Wallpaper::~Wallpaper() +{ + DBG_DTOR( Wallpaper, NULL ); + + // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es + // die letzte Referenz ist, sonst Referenzcounter decrementieren + if ( mpImplWallpaper->mnRefCount ) + { + if ( mpImplWallpaper->mnRefCount == 1 ) + delete mpImplWallpaper; + else + mpImplWallpaper->mnRefCount--; + } +} + +// ----------------------------------------------------------------------- + +void Wallpaper::SetColor( const Color& rColor ) +{ + DBG_CHKTHIS( Wallpaper, NULL ); + + ImplMakeUnique(); + mpImplWallpaper->maColor = rColor; + + if( WALLPAPER_NULL == mpImplWallpaper->meStyle ) + mpImplWallpaper->meStyle = WALLPAPER_TILE; +} + +// ----------------------------------------------------------------------- + +void Wallpaper::SetStyle( WallpaperStyle eStyle ) +{ + DBG_CHKTHIS( Wallpaper, NULL ); + + ImplMakeUnique( FALSE ); + mpImplWallpaper->meStyle = eStyle; +} + +// ----------------------------------------------------------------------- + +void Wallpaper::SetBitmap( const BitmapEx& rBitmap ) +{ + DBG_CHKTHIS( Wallpaper, NULL ); + + if ( !rBitmap ) + { + if ( mpImplWallpaper->mpBitmap ) + { + ImplMakeUnique(); + delete mpImplWallpaper->mpBitmap; + mpImplWallpaper->mpBitmap = NULL; + } + } + else + { + ImplMakeUnique(); + if ( mpImplWallpaper->mpBitmap ) + *(mpImplWallpaper->mpBitmap) = rBitmap; + else + mpImplWallpaper->mpBitmap = new BitmapEx( rBitmap ); + } + + if( WALLPAPER_NULL == mpImplWallpaper->meStyle ) + mpImplWallpaper->meStyle = WALLPAPER_TILE; +} + +// ----------------------------------------------------------------------- + +void Wallpaper::SetBitmap() +{ + DBG_CHKTHIS( Wallpaper, NULL ); + + if ( mpImplWallpaper->mpBitmap ) + { + ImplMakeUnique(); + delete mpImplWallpaper->mpBitmap; + mpImplWallpaper->mpBitmap = NULL; + } +} + +// ----------------------------------------------------------------------- + +BitmapEx Wallpaper::GetBitmap() const +{ + DBG_CHKTHIS( Wallpaper, NULL ); + + if ( mpImplWallpaper->mpBitmap ) + return *(mpImplWallpaper->mpBitmap); + else + { + BitmapEx aBmp; + return aBmp; + } +} + +// ----------------------------------------------------------------------- + +void Wallpaper::SetGradient( const Gradient& rGradient ) +{ + DBG_CHKTHIS( Wallpaper, NULL ); + + ImplMakeUnique(); + + if ( mpImplWallpaper->mpGradient ) + *(mpImplWallpaper->mpGradient) = rGradient; + else + mpImplWallpaper->mpGradient = new Gradient( rGradient ); + + if( WALLPAPER_NULL == mpImplWallpaper->meStyle ) + mpImplWallpaper->meStyle = WALLPAPER_TILE; +} + +// ----------------------------------------------------------------------- + +void Wallpaper::SetGradient() +{ + DBG_CHKTHIS( Wallpaper, NULL ); + + if ( mpImplWallpaper->mpGradient ) + { + ImplMakeUnique(); + delete mpImplWallpaper->mpGradient; + mpImplWallpaper->mpGradient = NULL; + } +} + +// ----------------------------------------------------------------------- + +Gradient Wallpaper::GetGradient() const +{ + DBG_CHKTHIS( Wallpaper, NULL ); + + if ( mpImplWallpaper->mpGradient ) + return *(mpImplWallpaper->mpGradient); + else + { + Gradient aGradient; + return aGradient; + } +} + +// ----------------------------------------------------------------------- + +void Wallpaper::SetRect( const Rectangle& rRect ) +{ + DBG_CHKTHIS( Wallpaper, NULL ); + + ImplMakeUnique( FALSE ); + + if ( rRect.IsEmpty() ) + { + if ( mpImplWallpaper->mpRect ) + { + delete mpImplWallpaper->mpRect; + mpImplWallpaper->mpRect = NULL; + } + } + else + { + if ( mpImplWallpaper->mpRect ) + *(mpImplWallpaper->mpRect) = rRect; + else + mpImplWallpaper->mpRect = new Rectangle( rRect ); + } +} + +// ----------------------------------------------------------------------- + +void Wallpaper::SetRect() +{ + DBG_CHKTHIS( Wallpaper, NULL ); + + if ( mpImplWallpaper->mpRect ) + { + ImplMakeUnique( FALSE ); + delete mpImplWallpaper->mpRect; + mpImplWallpaper->mpRect = NULL; + } +} + +// ----------------------------------------------------------------------- + +Rectangle Wallpaper::GetRect() const +{ + DBG_CHKTHIS( Wallpaper, NULL ); + + if ( mpImplWallpaper->mpRect ) + return *(mpImplWallpaper->mpRect); + else + { + Rectangle aRect; + return aRect; + } +} + +// ----------------------------------------------------------------------- + +BOOL Wallpaper::IsFixed() const +{ + if ( mpImplWallpaper->meStyle == WALLPAPER_NULL ) + return FALSE; + else + return (!mpImplWallpaper->mpBitmap && !mpImplWallpaper->mpGradient); +} + +// ----------------------------------------------------------------------- + +BOOL Wallpaper::IsScrollable() const +{ + if ( mpImplWallpaper->meStyle == WALLPAPER_NULL ) + return FALSE; + else if ( !mpImplWallpaper->mpBitmap && !mpImplWallpaper->mpGradient ) + return TRUE; + else if ( mpImplWallpaper->mpBitmap ) + return (mpImplWallpaper->meStyle == WALLPAPER_TILE); + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +Wallpaper& Wallpaper::operator=( const Wallpaper& rWallpaper ) +{ + DBG_CHKTHIS( Wallpaper, NULL ); + DBG_CHKOBJ( &rWallpaper, Wallpaper, NULL ); + DBG_ASSERT( rWallpaper.mpImplWallpaper->mnRefCount < 0xFFFE, "Wallpaper: RefCount overflow" ); + + // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann + if ( rWallpaper.mpImplWallpaper->mnRefCount ) + rWallpaper.mpImplWallpaper->mnRefCount++; + + // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es + // die letzte Referenz ist, sonst Referenzcounter decrementieren + if ( mpImplWallpaper->mnRefCount ) + { + if ( mpImplWallpaper->mnRefCount == 1 ) + delete mpImplWallpaper; + else + mpImplWallpaper->mnRefCount--; + } + + mpImplWallpaper = rWallpaper.mpImplWallpaper; + + return *this; +} + +// ----------------------------------------------------------------------- + +BOOL Wallpaper::operator==( const Wallpaper& rWallpaper ) const +{ + DBG_CHKTHIS( Wallpaper, NULL ); + DBG_CHKOBJ( &rWallpaper, Wallpaper, NULL ); + + if ( mpImplWallpaper == rWallpaper.mpImplWallpaper ) + return TRUE; + + if ( ( mpImplWallpaper->meStyle != rWallpaper.mpImplWallpaper->meStyle ) || + ( mpImplWallpaper->maColor != rWallpaper.mpImplWallpaper->maColor ) ) + return FALSE; + + if ( mpImplWallpaper->mpRect != rWallpaper.mpImplWallpaper->mpRect + && ( !mpImplWallpaper->mpRect + || !rWallpaper.mpImplWallpaper->mpRect + || *(mpImplWallpaper->mpRect) != *(rWallpaper.mpImplWallpaper->mpRect) ) ) + return FALSE; + + if ( mpImplWallpaper->mpBitmap != rWallpaper.mpImplWallpaper->mpBitmap + && ( !mpImplWallpaper->mpBitmap + || !rWallpaper.mpImplWallpaper->mpBitmap + || *(mpImplWallpaper->mpBitmap) != *(rWallpaper.mpImplWallpaper->mpBitmap) ) ) + return FALSE; + + if ( mpImplWallpaper->mpGradient != rWallpaper.mpImplWallpaper->mpGradient + && ( !mpImplWallpaper->mpGradient + || !rWallpaper.mpImplWallpaper->mpGradient + || *(mpImplWallpaper->mpGradient) != *(rWallpaper.mpImplWallpaper->mpGradient) ) ) + return FALSE; + + return TRUE; +} + +// ----------------------------------------------------------------------- + +SvStream& operator>>( SvStream& rIStm, Wallpaper& rWallpaper ) +{ + rWallpaper.ImplMakeUnique(); + return( rIStm >> *rWallpaper.mpImplWallpaper ); +} + +// ----------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rOStm, const Wallpaper& rWallpaper ) +{ + return( rOStm << *rWallpaper.mpImplWallpaper ); +} |