diff options
Diffstat (limited to 'svtools/source/filter.vcl/wmf')
-rw-r--r-- | svtools/source/filter.vcl/wmf/emfwr.cxx | 1415 | ||||
-rw-r--r-- | svtools/source/filter.vcl/wmf/emfwr.hxx | 100 | ||||
-rw-r--r-- | svtools/source/filter.vcl/wmf/enhwmf.cxx | 1343 | ||||
-rw-r--r-- | svtools/source/filter.vcl/wmf/makefile.mk | 50 | ||||
-rw-r--r-- | svtools/source/filter.vcl/wmf/winmtf.cxx | 2199 | ||||
-rw-r--r-- | svtools/source/filter.vcl/wmf/winmtf.hxx | 776 | ||||
-rw-r--r-- | svtools/source/filter.vcl/wmf/winwmf.cxx | 1426 | ||||
-rw-r--r-- | svtools/source/filter.vcl/wmf/wmf.cxx | 114 | ||||
-rw-r--r-- | svtools/source/filter.vcl/wmf/wmfwr.cxx | 2096 | ||||
-rw-r--r-- | svtools/source/filter.vcl/wmf/wmfwr.hxx | 229 |
10 files changed, 9748 insertions, 0 deletions
diff --git a/svtools/source/filter.vcl/wmf/emfwr.cxx b/svtools/source/filter.vcl/wmf/emfwr.cxx new file mode 100644 index 000000000000..f31fd4439e9f --- /dev/null +++ b/svtools/source/filter.vcl/wmf/emfwr.cxx @@ -0,0 +1,1415 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +#include "emfwr.hxx" +#include <vcl/salbtype.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <vcl/lineinfo.hxx> + +// ----------- +// - Defines - +// ----------- + +#define WIN_EMR_HEADER 1 +#define WIN_EMR_POLYBEZIER 2 +#define WIN_EMR_POLYGON 3 +#define WIN_EMR_POLYLINE 4 +#define WIN_EMR_POLYBEZIERTO 5 +#define WIN_EMR_POLYLINETO 6 +#define WIN_EMR_POLYPOLYLINE 7 +#define WIN_EMR_POLYPOLYGON 8 +#define WIN_EMR_SETWINDOWEXTEX 9 +#define WIN_EMR_SETWINDOWORGEX 10 +#define WIN_EMR_SETVIEWPORTEXTEX 11 +#define WIN_EMR_SETVIEWPORTORGEX 12 +#define WIN_EMR_SETBRUSHORGEX 13 +#define WIN_EMR_EOF 14 +#define WIN_EMR_SETPIXELV 15 +#define WIN_EMR_SETMAPPERFLAGS 16 +#define WIN_EMR_SETMAPMODE 17 +#define WIN_EMR_SETBKMODE 18 +#define WIN_EMR_SETPOLYFILLMODE 19 +#define WIN_EMR_SETROP2 20 +#define WIN_EMR_SETSTRETCHBLTMODE 21 +#define WIN_EMR_SETTEXTALIGN 22 +#define WIN_EMR_SETCOLORADJUSTMENT 23 +#define WIN_EMR_SETTEXTCOLOR 24 +#define WIN_EMR_SETBKCOLOR 25 +#define WIN_EMR_OFFSETCLIPRGN 26 +#define WIN_EMR_MOVETOEX 27 +#define WIN_EMR_SETMETARGN 28 +#define WIN_EMR_EXCLUDECLIPRECT 29 +#define WIN_EMR_INTERSECTCLIPRECT 30 +#define WIN_EMR_SCALEVIEWPORTEXTEX 31 +#define WIN_EMR_SCALEWINDOWEXTEX 32 +#define WIN_EMR_SAVEDC 33 +#define WIN_EMR_RESTOREDC 34 +#define WIN_EMR_SETWORLDTRANSFORM 35 +#define WIN_EMR_MODIFYWORLDTRANSFORM 36 +#define WIN_EMR_SELECTOBJECT 37 +#define WIN_EMR_CREATEPEN 38 +#define WIN_EMR_CREATEBRUSHINDIRECT 39 +#define WIN_EMR_DELETEOBJECT 40 +#define WIN_EMR_ANGLEARC 41 +#define WIN_EMR_ELLIPSE 42 +#define WIN_EMR_RECTANGLE 43 +#define WIN_EMR_ROUNDRECT 44 +#define WIN_EMR_ARC 45 +#define WIN_EMR_CHORD 46 +#define WIN_EMR_PIE 47 +#define WIN_EMR_SELECTPALETTE 48 +#define WIN_EMR_CREATEPALETTE 49 +#define WIN_EMR_SETPALETTEENTRIES 50 +#define WIN_EMR_RESIZEPALETTE 51 +#define WIN_EMR_REALIZEPALETTE 52 +#define WIN_EMR_EXTFLOODFILL 53 +#define WIN_EMR_LINETO 54 +#define WIN_EMR_ARCTO 55 +#define WIN_EMR_POLYDRAW 56 +#define WIN_EMR_SETARCDIRECTION 57 +#define WIN_EMR_SETMITERLIMIT 58 +#define WIN_EMR_BEGINPATH 59 +#define WIN_EMR_ENDPATH 60 +#define WIN_EMR_CLOSEFIGURE 61 +#define WIN_EMR_FILLPATH 62 +#define WIN_EMR_STROKEANDFILLPATH 63 +#define WIN_EMR_STROKEPATH 64 +#define WIN_EMR_FLATTENPATH 65 +#define WIN_EMR_WIDENPATH 66 +#define WIN_EMR_SELECTCLIPPATH 67 +#define WIN_EMR_ABORTPATH 68 + +#define WIN_EMR_GDICOMMENT 70 +#define WIN_EMR_FILLRGN 71 +#define WIN_EMR_FRAMERGN 72 +#define WIN_EMR_INVERTRGN 73 +#define WIN_EMR_PAINTRGN 74 +#define WIN_EMR_EXTSELECTCLIPRGN 75 +#define WIN_EMR_BITBLT 76 +#define WIN_EMR_STRETCHBLT 77 +#define WIN_EMR_MASKBLT 78 +#define WIN_EMR_PLGBLT 79 +#define WIN_EMR_SETDIBITSTODEVICE 80 +#define WIN_EMR_STRETCHDIBITS 81 +#define WIN_EMR_EXTCREATEFONTINDIRECTW 82 +#define WIN_EMR_EXTTEXTOUTA 83 +#define WIN_EMR_EXTTEXTOUTW 84 +#define WIN_EMR_POLYBEZIER16 85 +#define WIN_EMR_POLYGON16 86 +#define WIN_EMR_POLYLINE16 87 +#define WIN_EMR_POLYBEZIERTO16 88 +#define WIN_EMR_POLYLINETO16 89 +#define WIN_EMR_POLYPOLYLINE16 90 +#define WIN_EMR_POLYPOLYGON16 91 +#define WIN_EMR_POLYDRAW16 92 +#define WIN_EMR_CREATEMONOBRUSH 93 +#define WIN_EMR_CREATEDIBPATTERNBRUSHPT 94 +#define WIN_EMR_EXTCREATEPEN 95 +#define WIN_EMR_POLYTEXTOUTA 96 +#define WIN_EMR_POLYTEXTOUTW 97 + +#define WIN_SRCCOPY 0x00CC0020L +#define WIN_SRCPAINT 0x00EE0086L +#define WIN_SRCAND 0x008800C6L +#define WIN_SRCINVERT 0x00660046L + +#define HANDLE_INVALID 0xffffffff +#define MAXHANDLES 65000 + +#define LINE_SELECT 0x00000001 +#define FILL_SELECT 0x00000002 +#define TEXT_SELECT 0x00000004 + +/* Text Alignment Options */ +#define TA_NOUPDATECP 0 +#define TA_UPDATECP 1 + +#define TA_LEFT 0 +#define TA_RIGHT 2 +#define TA_CENTER 6 + +#define TA_TOP 0 +#define TA_BOTTOM 8 +#define TA_BASELINE 24 +#define TA_RTLREADING 256 +#define TA_MASK (TA_BASELINE+TA_CENTER+TA_UPDATECP+TA_RTLREADING) + +#define MM_ANISOTROPIC 8 + +// ------------- +// - EMFWriter - +// ------------- + +BOOL EMFWriter::WriteEMF( const GDIMetaFile& rMtf, SvStream& rOStm, FilterConfigItem* pFilterConfigItem ) +{ + const ULONG nHeaderPos = rOStm.Tell(); + + mpHandlesUsed = new BOOL[ MAXHANDLES ]; + memset( mpHandlesUsed, 0, MAXHANDLES * sizeof( BOOL ) ); + mnHorTextAlign = mnHandleCount = mnLastPercent = mnRecordPos = mnRecordCount = 0; + mnLineHandle = mnFillHandle = mnTextHandle = HANDLE_INVALID; + mbRecordOpen = FALSE; + + mpStm = &rOStm; + maVDev.EnableOutput( FALSE ); + maVDev.SetMapMode( rMtf.GetPrefMapMode() ); + mpFilterConfigItem = pFilterConfigItem; + + // don't work with pixel as destination map mode -> higher resolution preferrable + maDestMapMode.SetMapUnit( MAP_100TH_MM ); + + const Size aMtfSizePix( maVDev.LogicToPixel( rMtf.GetPrefSize(), rMtf.GetPrefMapMode() ) ); + const Size aMtfSizeLog( maVDev.LogicToLogic( rMtf.GetPrefSize(), rMtf.GetPrefMapMode(), MAP_100TH_MM ) ); + + // seek over header + // use [MS-EMF 2.2.11] HeaderExtension2 Object, otherwise resulting EMF cannot be converted with GetWinMetaFileBits() + rOStm.SeekRel( 108 ); + + // write initial values + + // set 100th mm map mode in EMF + ImplBeginRecord( WIN_EMR_SETMAPMODE ); + (*mpStm) << (INT32) MM_ANISOTROPIC; + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SETVIEWPORTEXTEX ); + (*mpStm) << (INT32) maVDev.ImplGetDPIX() << (INT32) maVDev.ImplGetDPIY(); + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SETWINDOWEXTEX ); + (*mpStm) << (INT32) 2540 << (INT32) 2540; + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SETVIEWPORTORGEX ); + (*mpStm) << (INT32) 0 << (INT32) 0; + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SETWINDOWORGEX ); + (*mpStm) << (INT32) 0 << (INT32) 0; + ImplEndRecord(); + + ImplWriteRasterOp( ROP_OVERPAINT ); + + ImplBeginRecord( WIN_EMR_SETBKMODE ); + (*mpStm) << (UINT32) 1; // TRANSPARENT + ImplEndRecord(); + + // write emf data + ImplWrite( rMtf ); + + ImplBeginRecord( WIN_EMR_EOF ); + (*mpStm)<< (sal_uInt32)0 // nPalEntries + << (sal_uInt32)0x10 // offPalEntries + << (sal_uInt32)0x14; // nSizeLast + ImplEndRecord(); + + + // write header + const ULONG nEndPos = mpStm->Tell(); mpStm->Seek( nHeaderPos ); + + (*mpStm) << (UINT32) 0x00000001 << (UINT32) 108 //use [MS-EMF 2.2.11] HeaderExtension2 Object + << (INT32) 0 << (INT32) 0 << (INT32) ( aMtfSizePix.Width() - 1 ) << (INT32) ( aMtfSizePix.Height() - 1 ) + << (INT32) 0 << (INT32) 0 << (INT32) ( aMtfSizeLog.Width() - 1 ) << (INT32) ( aMtfSizeLog.Height() - 1 ) + << (UINT32) 0x464d4520 << (UINT32) 0x10000 << (UINT32) ( nEndPos - nHeaderPos ) + << (UINT32) mnRecordCount << (UINT16) ( mnHandleCount + 1 ) << (UINT16) 0 << (UINT32) 0 << (UINT32) 0 << (UINT32) 0 + << (INT32) aMtfSizePix.Width() << (INT32) aMtfSizePix.Height() + << (INT32) ( aMtfSizeLog.Width() / 100 ) << (INT32) ( aMtfSizeLog.Height() / 100 ) + << (UINT32) 0 << (UINT32) 0 << (UINT32) 0 + << (INT32) ( aMtfSizeLog.Width() * 10 ) << (INT32) ( aMtfSizeLog.Height() * 10 ); //use [MS-EMF 2.2.11] HeaderExtension2 Object + + mpStm->Seek( nEndPos ); + delete[] mpHandlesUsed; + + return( mpStm->GetError() == ERRCODE_NONE ); +} + +// ----------------------------------------------------------------------------- + +ULONG EMFWriter::ImplAcquireHandle() +{ + ULONG nHandle = HANDLE_INVALID; + + for( ULONG i = 0; i < MAXHANDLES && ( HANDLE_INVALID == nHandle ); i++ ) + { + if( !mpHandlesUsed[ i ] ) + { + mpHandlesUsed[ i ] = TRUE; + + if( ( nHandle = i ) == mnHandleCount ) + mnHandleCount++; + } + } + + DBG_ASSERT( nHandle != HANDLE_INVALID, "No more handles available" ); + return( nHandle != HANDLE_INVALID ? nHandle + 1 : HANDLE_INVALID ); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplReleaseHandle( ULONG nHandle ) +{ + DBG_ASSERT( nHandle && ( nHandle < MAXHANDLES ), "Handle out of range" ); + mpHandlesUsed[ nHandle - 1 ] = FALSE; +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplBeginRecord( sal_uInt32 nType ) +{ + DBG_ASSERT( !mbRecordOpen, "Another record is already opened!" ); + + if( !mbRecordOpen ) + { + mbRecordOpen = TRUE; + mnRecordPos = mpStm->Tell(); + + (*mpStm) << nType; + mpStm->SeekRel( 4 ); + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplEndRecord() +{ + DBG_ASSERT( mbRecordOpen, "Record was not opened!" ); + + if( mbRecordOpen ) + { + sal_Int32 nFillBytes, nActPos = mpStm->Tell(); + mpStm->Seek( mnRecordPos + 4 ); + nFillBytes = nActPos - mnRecordPos; + nFillBytes += 3; // each record has to be dword aligned + nFillBytes ^= 3; + nFillBytes &= 3; + *mpStm << (sal_uInt32)( ( nActPos - mnRecordPos ) + nFillBytes ); + mpStm->Seek( nActPos ); + while( nFillBytes-- ) + *mpStm << (sal_uInt8)0; + mnRecordCount++; + mbRecordOpen = FALSE; + } +} + +// ----------------------------------------------------------------------------- + +BOOL EMFWriter::ImplPrepareHandleSelect( sal_uInt32& rHandle, ULONG nSelectType ) +{ + if( rHandle != HANDLE_INVALID ) + { + UINT32 nStockObject = 0x80000000; + + if( LINE_SELECT == nSelectType ) + nStockObject |= 0x00000007; + else if( FILL_SELECT == nSelectType ) + nStockObject |= 0x00000001; + else if( TEXT_SELECT == nSelectType ) + nStockObject |= 0x0000000a; + + // select stock object first + ImplBeginRecord( WIN_EMR_SELECTOBJECT ); + ( *mpStm ) << nStockObject; + ImplEndRecord(); + + // destroy handle of created object + ImplBeginRecord( WIN_EMR_DELETEOBJECT ); + ( *mpStm ) << rHandle; + ImplEndRecord(); + + // mark handle as free + ImplReleaseHandle( rHandle ); + } + + rHandle = ImplAcquireHandle(); + + return( HANDLE_INVALID != rHandle ); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplCheckLineAttr() +{ + if( mbLineChanged && ImplPrepareHandleSelect( mnLineHandle, LINE_SELECT ) ) + { + sal_uInt32 nStyle = maVDev.IsLineColor() ? 0 : 5; + sal_uInt32 nWidth = 0, nHeight = 0; + + ImplBeginRecord( WIN_EMR_CREATEPEN ); + (*mpStm) << mnLineHandle << nStyle << nWidth << nHeight; + ImplWriteColor( maVDev.GetLineColor() ); + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SELECTOBJECT ); + (*mpStm) << mnLineHandle; + ImplEndRecord(); + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplCheckFillAttr() +{ + if( mbFillChanged && ImplPrepareHandleSelect( mnFillHandle, FILL_SELECT ) ) + { + sal_uInt32 nStyle = maVDev.IsFillColor() ? 0 : 1; + sal_uInt32 nPatternStyle = 0; + + ImplBeginRecord( WIN_EMR_CREATEBRUSHINDIRECT ); + (*mpStm) << mnFillHandle << nStyle; + ImplWriteColor( maVDev.GetFillColor() ); + (*mpStm) << nPatternStyle; + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SELECTOBJECT ); + (*mpStm) << mnFillHandle; + ImplEndRecord(); + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplCheckTextAttr() +{ + if( mbTextChanged && ImplPrepareHandleSelect( mnTextHandle, TEXT_SELECT ) ) + { + const Font& rFont = maVDev.GetFont(); + String aFontName( rFont.GetName() ); + sal_Int32 nWeight; + sal_uInt16 i; + sal_uInt8 nPitchAndFamily; + + ImplBeginRecord( WIN_EMR_EXTCREATEFONTINDIRECTW ); + (*mpStm) << mnTextHandle; + ImplWriteExtent( -rFont.GetSize().Height() ); + ImplWriteExtent( rFont.GetSize().Width() ); + (*mpStm) << (INT32) rFont.GetOrientation() << (INT32) rFont.GetOrientation(); + + switch( rFont.GetWeight() ) + { + case WEIGHT_THIN: nWeight = 100; break; + case WEIGHT_ULTRALIGHT: nWeight = 200; break; + case WEIGHT_LIGHT: nWeight = 300; break; + case WEIGHT_SEMILIGHT: nWeight = 300; break; + case WEIGHT_NORMAL: nWeight = 400; break; + case WEIGHT_MEDIUM: nWeight = 500; break; + case WEIGHT_SEMIBOLD: nWeight = 600; break; + case WEIGHT_BOLD: nWeight = 700; break; + case WEIGHT_ULTRABOLD: nWeight = 800; break; + case WEIGHT_BLACK: nWeight = 900; break; + default: nWeight = 0; break; + } + + (*mpStm) << nWeight; + (*mpStm) << (BYTE) ( ( ITALIC_NONE == rFont.GetItalic() ) ? 0 : 1 ); + (*mpStm) << (BYTE) ( ( UNDERLINE_NONE == rFont.GetUnderline() ) ? 0 : 1 ); + (*mpStm) << (BYTE) ( ( STRIKEOUT_NONE == rFont.GetStrikeout() ) ? 0 : 1 ); + (*mpStm) << (BYTE) ( ( RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet() ) ? 2 : 0 ); + (*mpStm) << (BYTE) 0 << (BYTE) 0 << (BYTE) 0; + + switch( rFont.GetPitch() ) + { + case PITCH_FIXED: nPitchAndFamily = 0x01; break; + case PITCH_VARIABLE: nPitchAndFamily = 0x02; break; + default: nPitchAndFamily = 0x00; break; + } + + switch( rFont.GetFamily() ) + { + case FAMILY_DECORATIVE: nPitchAndFamily |= 0x50; break; + case FAMILY_MODERN: nPitchAndFamily |= 0x30; break; + case FAMILY_ROMAN: nPitchAndFamily |= 0x10; break; + case FAMILY_SCRIPT: nPitchAndFamily |= 0x40; break; + case FAMILY_SWISS: nPitchAndFamily |= 0x20; break; + default: break; + } + + (*mpStm) << nPitchAndFamily; + + for( i = 0; i < 32; i++ ) + (*mpStm) << (sal_Unicode) ( ( i < aFontName.Len() ) ? aFontName.GetChar( i ) : 0 ); + + // dummy elfFullName + for( i = 0; i < 64; i++ ) + (*mpStm) << (sal_Unicode) 0; + + // dummy elfStyle + for( i = 0; i < 32; i++ ) + (*mpStm) << (sal_Unicode) 0; + + // dummy elfVersion, elfStyleSize, elfMatch, elfReserved + (*mpStm) << (UINT32) 0 << (UINT32) 0 << (UINT32) 0 << (UINT32) 0 ; + + // dummy elfVendorId + (*mpStm) << (UINT32) 0; + + // dummy elfCulture + (*mpStm) << (UINT32) 0; + + // dummy elfPanose + (*mpStm) << (BYTE) 0 << (BYTE) 0 << (BYTE) 0 << (BYTE) 0 << (BYTE) 0 << (BYTE) 0 << (BYTE) 0 << (BYTE) 0 << (BYTE) 0 << (BYTE) 0; + + // fill record to get a record size divideable by 4 + (*mpStm) << (UINT16) 0; + + ImplEndRecord(); + + // TextAlign + UINT32 nTextAlign; + + switch( rFont.GetAlign() ) + { + case ALIGN_TOP: nTextAlign = TA_TOP; break; + case ALIGN_BOTTOM: nTextAlign = TA_BOTTOM; break; + default: nTextAlign = TA_BASELINE; break; + } + nTextAlign |= mnHorTextAlign; + + ImplBeginRecord( WIN_EMR_SETTEXTALIGN ); + (*mpStm) << nTextAlign; + ImplEndRecord(); + + // Text color + ImplBeginRecord( WIN_EMR_SETTEXTCOLOR ); + ImplWriteColor( maVDev.GetTextColor() ); + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SELECTOBJECT ); + (*mpStm) << mnTextHandle; + ImplEndRecord(); + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteColor( const Color& rColor ) +{ + UINT32 nCol = rColor.GetRed(); + + nCol |= ( (UINT32) rColor.GetGreen() ) << 8; + nCol |= ( (UINT32) rColor.GetBlue() ) << 16; + + (*mpStm) << nCol; +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteRasterOp( RasterOp eRop ) +{ + UINT32 nROP2; + + switch( eRop ) + { + case ROP_INVERT: nROP2 = 6; break; + case ROP_XOR: nROP2 = 7; break; + default: nROP2 = 13;break; + } + + ImplBeginRecord( WIN_EMR_SETROP2 ); + (*mpStm) << nROP2; + ImplEndRecord(); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteExtent( long nExtent ) +{ + nExtent = maVDev.LogicToLogic( Size( nExtent, 0 ), maVDev.GetMapMode(), maDestMapMode ).Width(); + (*mpStm) << (INT32) nExtent; +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWritePoint( const Point& rPoint ) +{ + const Point aPoint( maVDev.LogicToLogic( rPoint, maVDev.GetMapMode(), maDestMapMode )); + (*mpStm) << (INT32) aPoint.X() << (INT32) aPoint.Y(); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteSize( const Size& rSize) +{ + const Size aSize( maVDev.LogicToLogic( rSize, maVDev.GetMapMode(), maDestMapMode )); + (*mpStm) << (INT32) aSize.Width() << (INT32) aSize.Height(); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteRect( const Rectangle& rRect ) +{ + const Rectangle aRect( maVDev.LogicToLogic ( rRect, maVDev.GetMapMode(), maDestMapMode )); + (*mpStm) << aRect.Left() << aRect.Top() << aRect.Right() << aRect.Bottom(); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWritePolygonRecord( const Polygon& rPoly, BOOL bClose ) +{ + if( rPoly.GetSize() ) + { + if( rPoly.HasFlags() ) + ImplWritePath( rPoly, bClose ); + else + { + if( bClose ) + ImplCheckFillAttr(); + + ImplCheckLineAttr(); + + ImplBeginRecord( bClose ? WIN_EMR_POLYGON : WIN_EMR_POLYLINE ); + ImplWriteRect( rPoly.GetBoundRect() ); + (*mpStm) << (UINT32) rPoly.GetSize(); + + for( USHORT i = 0; i < rPoly.GetSize(); i++ ) + ImplWritePoint( rPoly[ i ] ); + + ImplEndRecord(); + } + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWritePolyPolygonRecord( const PolyPolygon& rPolyPoly ) +{ + sal_uInt16 n, i, nPolyCount = rPolyPoly.Count(); + + if( nPolyCount ) + { + if( 1 == nPolyCount ) + ImplWritePolygonRecord( rPolyPoly[ 0 ], TRUE ); + else + { + sal_Bool bHasFlags = sal_False; + sal_uInt32 nTotalPoints = 0; + + for( i = 0; i < nPolyCount; i++ ) + { + nTotalPoints += rPolyPoly[ i ].GetSize(); + if ( rPolyPoly[ i ].HasFlags() ) + bHasFlags = sal_True; + } + if( nTotalPoints ) + { + if ( bHasFlags ) + ImplWritePath( rPolyPoly, sal_True ); + else + { + ImplCheckFillAttr(); + ImplCheckLineAttr(); + + ImplBeginRecord( WIN_EMR_POLYPOLYGON ); + ImplWriteRect( rPolyPoly.GetBoundRect() ); + (*mpStm) << (sal_uInt32)nPolyCount << nTotalPoints; + + for( i = 0; i < nPolyCount; i++ ) + (*mpStm) << (sal_uInt32)rPolyPoly[ i ].GetSize(); + + for( i = 0; i < nPolyCount; i++ ) + { + const Polygon& rPoly = rPolyPoly[ i ]; + + for( n = 0; n < rPoly.GetSize(); n++ ) + ImplWritePoint( rPoly[ n ] ); + } + ImplEndRecord(); + } + } + } + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWritePath( const PolyPolygon& rPolyPoly, sal_Bool bClosed ) +{ + if ( bClosed ) + ImplCheckFillAttr(); + ImplCheckLineAttr(); + + ImplBeginRecord( WIN_EMR_BEGINPATH ); + ImplEndRecord(); + + sal_uInt16 i, n, o, nPolyCount = rPolyPoly.Count(); + for ( i = 0; i < nPolyCount; i++ ) + { + n = 0; + const Polygon& rPoly = rPolyPoly[ i ]; + while ( n < rPoly.GetSize() ) + { + if( n == 0 ) + { + ImplBeginRecord( WIN_EMR_MOVETOEX ); + ImplWritePoint( rPoly[ 0 ] ); + ImplEndRecord(); + n++; + continue; + } + + sal_uInt16 nBezPoints = 0; + + while ( ( ( nBezPoints + n + 2 ) < rPoly.GetSize() ) && ( rPoly.GetFlags( nBezPoints + n ) == POLY_CONTROL ) ) + nBezPoints += 3; + + if ( nBezPoints ) + { + ImplBeginRecord( WIN_EMR_POLYBEZIERTO ); + Polygon aNewPoly( nBezPoints + 1 ); + aNewPoly[ 0 ] = rPoly[ n - 1 ]; + for ( o = 0; o < nBezPoints; o++ ) + aNewPoly[ o + 1 ] = rPoly[ n + o ]; + ImplWriteRect( aNewPoly.GetBoundRect() ); + (*mpStm) << (sal_uInt32)nBezPoints; + for( o = 1; o < aNewPoly.GetSize(); o++ ) + ImplWritePoint( aNewPoly[ o ] ); + ImplEndRecord(); + n = n + nBezPoints; + } + else + { + sal_uInt16 nPoints = 1; + while( ( nPoints + n ) < rPoly.GetSize() && ( rPoly.GetFlags( nPoints + n ) != POLY_CONTROL ) ) + nPoints++; + + if ( nPoints > 1 ) + { + ImplBeginRecord( WIN_EMR_POLYLINETO ); + Polygon aNewPoly( nPoints + 1 ); + aNewPoly[ 0 ] = rPoly[ n - 1]; + for ( o = 1; o <= nPoints; o++ ) + aNewPoly[ o ] = rPoly[ n - 1 + o ]; + ImplWriteRect( aNewPoly.GetBoundRect() ); + (*mpStm) << (sal_uInt32)( nPoints ); + for( o = 1; o < aNewPoly.GetSize(); o++ ) + ImplWritePoint( aNewPoly[ o ] ); + ImplEndRecord(); + } + else + { + ImplBeginRecord( WIN_EMR_LINETO ); + ImplWritePoint( rPoly[ n ] ); + ImplEndRecord(); + } + n = n + nPoints; + } + if ( bClosed && ( n == rPoly.GetSize() ) ) + { + ImplBeginRecord( WIN_EMR_CLOSEFIGURE ); + ImplEndRecord(); + } + } + } + ImplBeginRecord( WIN_EMR_ENDPATH ); + ImplEndRecord(); + ImplBeginRecord( bClosed ? WIN_EMR_FILLPATH : WIN_EMR_STROKEPATH ); + ImplWriteRect( rPolyPoly.GetBoundRect() ); + ImplEndRecord(); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteBmpRecord( const Bitmap& rBmp, const Point& rPt, + const Size& rSz, UINT32 nROP ) +{ + if( !!rBmp ) + { + SvMemoryStream aMemStm( 65535, 65535 ); + const Size aBmpSizePixel( rBmp.GetSizePixel() ); + + ImplBeginRecord( WIN_EMR_STRETCHDIBITS ); + ImplWriteRect( Rectangle( rPt, rSz ) ); + ImplWritePoint( rPt ); + (*mpStm) << (INT32) 0 << (INT32) 0 << (INT32) aBmpSizePixel.Width() << (INT32) aBmpSizePixel.Height(); + + // write offset positions and sizes later + const ULONG nOffPos = mpStm->Tell(); + mpStm->SeekRel( 16 ); + + (*mpStm) << (UINT32) 0 << ( ( ROP_XOR == maVDev.GetRasterOp() && WIN_SRCCOPY == nROP ) ? WIN_SRCINVERT : nROP ); + ImplWriteSize( rSz ); + + rBmp.Write( aMemStm, TRUE, FALSE ); + + UINT32 nDIBSize = aMemStm.Tell(), nHeaderSize, nCompression, nColsUsed, nPalCount, nImageSize; + UINT16 nBitCount; + + // get DIB parameters + aMemStm.Seek( 0 ); + aMemStm >> nHeaderSize; + aMemStm.SeekRel( 10 ); + aMemStm >> nBitCount >> nCompression >> nImageSize; + aMemStm.SeekRel( 8 ); + aMemStm >> nColsUsed; + + nPalCount = ( nBitCount <= 8 ) ? ( nColsUsed ? nColsUsed : ( 1 << (UINT32) nBitCount ) ) : + ( ( 3 == nCompression ) ? 12 : 0 ); + + mpStm->Write( aMemStm.GetData(), nDIBSize ); + + const ULONG nEndPos = mpStm->Tell(); + mpStm->Seek( nOffPos ); + (*mpStm) << (UINT32) 80 << (UINT32)( nHeaderSize + ( nPalCount << 2 ) ); + (*mpStm) << (UINT32)( 80 + ( nHeaderSize + ( nPalCount << 2 ) ) ) << nImageSize; + mpStm->Seek( nEndPos ); + + ImplEndRecord(); + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteTextRecord( const Point& rPos, const String rText, const sal_Int32* pDXArray, sal_uInt32 nWidth ) +{ + xub_StrLen nLen = rText.Len(), i; + + if( nLen ) + { + sal_uInt32 nNormWidth; + sal_Int32* pOwnArray; + sal_Int32* pDX; + + // get text sizes + if( pDXArray ) + { + pOwnArray = NULL; + nNormWidth = maVDev.GetTextWidth( rText ); + pDX = (sal_Int32*) pDXArray; + } + else + { + pOwnArray = new sal_Int32[ nLen ]; + nNormWidth = maVDev.GetTextArray( rText, pOwnArray ); + pDX = pOwnArray; + } + + if( nLen > 1 ) + { + nNormWidth = pDX[ nLen - 2 ] + maVDev.GetTextWidth( rText.GetChar( nLen - 1 ) ); + + if( nWidth && nNormWidth && ( nWidth != nNormWidth ) ) + { + const double fFactor = (double) nWidth / nNormWidth; + + for( i = 0; i < ( nLen - 1 ); i++ ) + pDX[ i ] = FRound( pDX[ i ] * fFactor ); + } + } + + // write text record + ImplBeginRecord( WIN_EMR_EXTTEXTOUTW ); + + ImplWriteRect( Rectangle( rPos, Size( nNormWidth, maVDev.GetTextHeight() ) ) ); + (*mpStm) << (UINT32)1; + (*mpStm) << (INT32) 0 << (INT32) 0; + ImplWritePoint( rPos ); + (*mpStm) << (UINT32) nLen << (UINT32) 76 << (UINT32) 2; + (*mpStm) << (INT32) 0 << (INT32) 0 << (INT32) 0 << (INT32) 0; + (*mpStm) << (UINT32) ( 76 + ( nLen << 1 ) + ( (nLen & 1 ) ? 2 : 0 ) ); + + // write text + for( i = 0; i < nLen; i++ ) + (*mpStm) << (sal_Unicode)rText.GetChar( i ); + + // padding word + if( nLen & 1 ) + (*mpStm) << (UINT16) 0; + + // write DX array + ImplWriteExtent( pDX[ 0 ] ); + + if( nLen > 1 ) + { + for( i = 1; i < ( nLen - 1 ); i++ ) + ImplWriteExtent( pDX[ i ] - pDX[ i - 1 ] ); + + ImplWriteExtent( pDX[ nLen - 2 ] / ( nLen - 1 ) ); + } + + ImplEndRecord(); + delete[] pOwnArray; + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::Impl_handleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon) +{ + if(rLinePolygon.count()) + { + basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon); + basegfx::B2DPolyPolygon aFillPolyPolygon; + + rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon); + + if(aLinePolyPolygon.count()) + { + for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++) + { + const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a)); + ImplWritePolygonRecord( Polygon(aCandidate), FALSE ); + } + } + + if(aFillPolyPolygon.count()) + { + const Color aOldLineColor(maVDev.GetLineColor()); + const Color aOldFillColor(maVDev.GetFillColor()); + + maVDev.SetLineColor(); + maVDev.SetFillColor(aOldLineColor); + + for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++) + { + const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a)); + ImplWritePolyPolygonRecord(PolyPolygon(Polygon(aPolygon))); + } + + maVDev.SetLineColor(aOldLineColor); + maVDev.SetFillColor(aOldFillColor); + } + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWrite( const GDIMetaFile& rMtf ) +{ + for( ULONG j = 0, nActionCount = rMtf.GetActionCount(); j < nActionCount; j++ ) + { + const MetaAction* pAction = rMtf.GetAction( j ); + const USHORT nType = pAction->GetType(); + + switch( nType ) + { + case( META_PIXEL_ACTION ): + { + const MetaPixelAction* pA = (const MetaPixelAction*) pAction; + + ImplCheckLineAttr(); + ImplBeginRecord( WIN_EMR_SETPIXELV ); + ImplWritePoint( pA->GetPoint() ); + ImplWriteColor( pA->GetColor() ); + ImplEndRecord(); + } + break; + + case( META_POINT_ACTION ): + { + if( maVDev.IsLineColor() ) + { + const MetaPointAction* pA = (const MetaPointAction*) pAction; + + ImplCheckLineAttr(); + ImplBeginRecord( WIN_EMR_SETPIXELV ); + ImplWritePoint( pA->GetPoint() ); + ImplWriteColor( maVDev.GetLineColor() ); + ImplEndRecord(); + } + } + break; + + case( META_LINE_ACTION ): + { + if( maVDev.IsLineColor() ) + { + const MetaLineAction* pA = (const MetaLineAction*) pAction; + + if(pA->GetLineInfo().IsDefault()) + { + ImplCheckLineAttr(); + + ImplBeginRecord( WIN_EMR_MOVETOEX ); + ImplWritePoint( pA->GetStartPoint() ); + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_LINETO ); + ImplWritePoint( pA->GetEndPoint() ); + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SETPIXELV ); + ImplWritePoint( pA->GetEndPoint() ); + ImplWriteColor( maVDev.GetLineColor() ); + ImplEndRecord(); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + basegfx::B2DPolygon aPolygon; + aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y())); + aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y())); + Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon); + } + } + } + break; + + case( META_RECT_ACTION ): + { + if( maVDev.IsLineColor() || maVDev.IsFillColor() ) + { + const MetaRectAction* pA = (const MetaRectAction*) pAction; + + ImplCheckFillAttr(); + ImplCheckLineAttr(); + + ImplBeginRecord( WIN_EMR_RECTANGLE ); + ImplWriteRect( pA->GetRect() ); + ImplEndRecord(); + } + } + break; + + case( META_ROUNDRECT_ACTION ): + { + if( maVDev.IsLineColor() || maVDev.IsFillColor() ) + { + const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pAction; + + ImplCheckFillAttr(); + ImplCheckLineAttr(); + + ImplBeginRecord( WIN_EMR_ROUNDRECT ); + ImplWriteRect( pA->GetRect() ); + ImplWriteSize( Size( pA->GetHorzRound(), pA->GetVertRound() ) ); + ImplEndRecord(); + } + } + break; + + case( META_ELLIPSE_ACTION ): + { + if( maVDev.IsLineColor() || maVDev.IsFillColor() ) + { + const MetaEllipseAction* pA = (const MetaEllipseAction*) pAction; + + ImplCheckFillAttr(); + ImplCheckLineAttr(); + + ImplBeginRecord( WIN_EMR_ELLIPSE ); + ImplWriteRect( pA->GetRect() ); + ImplEndRecord(); + } + } + break; + + case( META_ARC_ACTION ): + case( META_PIE_ACTION ): + case( META_CHORD_ACTION ): + case( META_POLYGON_ACTION ): + { + if( maVDev.IsLineColor() || maVDev.IsFillColor() ) + { + Polygon aPoly; + + switch( nType ) + { + case( META_ARC_ACTION ): + { + const MetaArcAction* pA = (const MetaArcAction*) pAction; + aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_ARC ); + } + break; + + case( META_PIE_ACTION ): + { + const MetaPieAction* pA = (const MetaPieAction*) pAction; + aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_PIE ); + } + break; + + case( META_CHORD_ACTION ): + { + const MetaChordAction* pA = (const MetaChordAction*) pAction; + aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_CHORD ); + } + break; + + case( META_POLYGON_ACTION ): + aPoly = ( (const MetaPolygonAction*) pAction )->GetPolygon(); + break; + } + + ImplWritePolygonRecord( aPoly, nType != META_ARC_ACTION ); + } + } + break; + + case( META_POLYLINE_ACTION ): + { + if( maVDev.IsLineColor() ) + { + const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pAction; + const Polygon& rPoly = pA->GetPolygon(); + + if( rPoly.GetSize() ) + { + if(pA->GetLineInfo().IsDefault()) + { + ImplWritePolygonRecord( rPoly, FALSE ); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon()); + } + } + } + } + break; + + case( META_POLYPOLYGON_ACTION ): + { + if( maVDev.IsLineColor() || maVDev.IsFillColor() ) + ImplWritePolyPolygonRecord( ( (const MetaPolyPolygonAction*) pAction )->GetPolyPolygon() ); + } + break; + + case( META_GRADIENT_ACTION ): + { + const MetaGradientAction* pA = (const MetaGradientAction*) pAction; + GDIMetaFile aTmpMtf; + + maVDev.AddGradientActions( pA->GetRect(), pA->GetGradient(), aTmpMtf ); + ImplWrite( aTmpMtf ); + } + break; + + case META_HATCH_ACTION: + { + const MetaHatchAction* pA = (const MetaHatchAction*) pAction; + GDIMetaFile aTmpMtf; + + maVDev.AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf ); + ImplWrite( aTmpMtf ); + } + break; + + case META_TRANSPARENT_ACTION: + { + ImplCheckFillAttr(); + ImplCheckLineAttr(); + ImplWritePolyPolygonRecord( ( (MetaTransparentAction*) pAction )->GetPolyPolygon() ); + } + break; + + case META_FLOATTRANSPARENT_ACTION: + { + const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*) pAction; + + GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() ); + Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() ); + const Size aSrcSize( aTmpMtf.GetPrefSize() ); + const Point aDestPt( pA->GetPoint() ); + const Size aDestSize( pA->GetSize() ); + const double fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0; + const double fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0; + long nMoveX, nMoveY; + + if( fScaleX != 1.0 || fScaleY != 1.0 ) + { + aTmpMtf.Scale( fScaleX, fScaleY ); + aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY ); + } + + nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y(); + + if( nMoveX || nMoveY ) + aTmpMtf.Move( nMoveX, nMoveY ); + + ImplCheckFillAttr(); + ImplCheckLineAttr(); + ImplCheckTextAttr(); + ImplWrite( aTmpMtf ); + } + break; + + case( META_EPS_ACTION ): + { + const MetaEPSAction* pA = (const MetaEPSAction*) pAction; + const GDIMetaFile aSubstitute( pA->GetSubstitute() ); + + for( ULONG i = 0, nCount = aSubstitute.GetActionCount(); i < nCount; i++ ) + { + const MetaAction* pSubstAct = aSubstitute.GetAction( i ); + if( pSubstAct->GetType() == META_BMPSCALE_ACTION ) + { + maVDev.Push( PUSH_ALL ); + ImplBeginRecord( WIN_EMR_SAVEDC ); + ImplEndRecord(); + + MapMode aMapMode( aSubstitute.GetPrefMapMode() ); + Size aOutSize( maVDev.LogicToLogic( pA->GetSize(), maVDev.GetMapMode(), aMapMode ) ); + aMapMode.SetScaleX( Fraction( aOutSize.Width(), aSubstitute.GetPrefSize().Width() ) ); + aMapMode.SetScaleY( Fraction( aOutSize.Height(), aSubstitute.GetPrefSize().Height() ) ); + aMapMode.SetOrigin( maVDev.LogicToLogic( pA->GetPoint(), maVDev.GetMapMode(), aMapMode ) ); + maVDev.SetMapMode( aMapMode ); + ImplWrite( aSubstitute ); + + maVDev.Pop(); + ImplBeginRecord( WIN_EMR_RESTOREDC ); + (*mpStm) << (INT32) -1; + ImplEndRecord(); + break; + } + } + } + break; + + case META_BMP_ACTION: + { + const MetaBmpAction* pA = (const MetaBmpAction *) pAction; + ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), pA->GetBitmap().GetSizePixel(), WIN_SRCCOPY ); + } + break; + + case META_BMPSCALE_ACTION: + { + const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pAction; + ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY ); + } + break; + + case META_BMPSCALEPART_ACTION: + { + const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*) pAction; + Bitmap aTmp( pA->GetBitmap() ); + + if( aTmp.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ) ) + ImplWriteBmpRecord( aTmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCCOPY ); + } + break; + + case META_BMPEX_ACTION: + { + const MetaBmpExAction* pA = (const MetaBmpExAction *) pAction; + Bitmap aBmp( pA->GetBitmapEx().GetBitmap() ); + Bitmap aMsk( pA->GetBitmapEx().GetMask() ); + + if( !!aMsk ) + { + aBmp.Replace( aMsk, COL_WHITE ); + aMsk.Invert(); + ImplWriteBmpRecord( aMsk, pA->GetPoint(), aMsk.GetSizePixel(), WIN_SRCPAINT ); + ImplWriteBmpRecord( aBmp, pA->GetPoint(), aBmp.GetSizePixel(), WIN_SRCAND ); + } + else + ImplWriteBmpRecord( aBmp, pA->GetPoint(), aBmp.GetSizePixel(), WIN_SRCCOPY ); + } + break; + + case META_BMPEXSCALE_ACTION: + { + const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pAction; + Bitmap aBmp( pA->GetBitmapEx().GetBitmap() ); + Bitmap aMsk( pA->GetBitmapEx().GetMask() ); + + if( !!aMsk ) + { + aBmp.Replace( aMsk, COL_WHITE ); + aMsk.Invert(); + ImplWriteBmpRecord( aMsk, pA->GetPoint(), pA->GetSize(), WIN_SRCPAINT ); + ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCAND ); + } + else + ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY ); + } + break; + + case META_BMPEXSCALEPART_ACTION: + { + const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*) pAction; + BitmapEx aBmpEx( pA->GetBitmapEx() ); + aBmpEx.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ); + Bitmap aBmp( aBmpEx.GetBitmap() ); + Bitmap aMsk( aBmpEx.GetMask() ); + + if( !!aMsk ) + { + aBmp.Replace( aMsk, COL_WHITE ); + aMsk.Invert(); + ImplWriteBmpRecord( aMsk, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCPAINT ); + ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCAND ); + } + else + ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCCOPY ); + } + break; + + case META_TEXT_ACTION: + { + const MetaTextAction* pA = (const MetaTextAction*) pAction; + const String aText( pA->GetText(), pA->GetIndex(), pA->GetLen() ); + + ImplCheckTextAttr(); + ImplWriteTextRecord( pA->GetPoint(), aText, NULL, 0 ); + } + break; + + case META_TEXTRECT_ACTION: + { + const MetaTextRectAction* pA = (const MetaTextRectAction*) pAction; + const String aText( pA->GetText() ); + + ImplCheckTextAttr(); + ImplWriteTextRecord( pA->GetRect().TopLeft(), aText, NULL, 0 ); + } + break; + + case META_TEXTARRAY_ACTION: + { + const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pAction; + const String aText( pA->GetText(), pA->GetIndex(), pA->GetLen() ); + + ImplCheckTextAttr(); + ImplWriteTextRecord( pA->GetPoint(), aText, pA->GetDXArray(), 0 ); + } + break; + + case META_STRETCHTEXT_ACTION: + { + const MetaStretchTextAction* pA = (const MetaStretchTextAction*) pAction; + const String aText( pA->GetText(), pA->GetIndex(), pA->GetLen() ); + + ImplCheckTextAttr(); + ImplWriteTextRecord( pA->GetPoint(), aText, NULL, pA->GetWidth() ); + } + break; + + case( META_LINECOLOR_ACTION ): + { + ( (MetaAction*) pAction )->Execute( &maVDev ); + mbLineChanged = TRUE; + } + break; + + case( META_FILLCOLOR_ACTION ): + { + ( (MetaAction*) pAction )->Execute( &maVDev ); + mbFillChanged = TRUE; + } + break; + + case( META_TEXTCOLOR_ACTION ): + case( META_TEXTLINECOLOR_ACTION ): + case( META_TEXTFILLCOLOR_ACTION ): + case( META_TEXTALIGN_ACTION ): + case( META_FONT_ACTION ): + { + ( (MetaAction*) pAction )->Execute( &maVDev ); + mbTextChanged = TRUE; + } + break; + + case( META_ISECTRECTCLIPREGION_ACTION ): + { + ( (MetaAction*) pAction )->Execute( &maVDev ); + + ImplBeginRecord( WIN_EMR_INTERSECTCLIPRECT ); + ImplWriteRect( ( (MetaISectRectClipRegionAction*) pAction )->GetRect() ); + ImplEndRecord(); + } + break; + + case( META_CLIPREGION_ACTION ): + case( META_ISECTREGIONCLIPREGION_ACTION ): + case( META_MOVECLIPREGION_ACTION ): + { + ( (MetaAction*) pAction )->Execute( &maVDev ); + } + break; + + case( META_REFPOINT_ACTION ): + case( META_MAPMODE_ACTION ): + ( (MetaAction*) pAction )->Execute( &maVDev ); + break; + + case( META_PUSH_ACTION ): + { + ( (MetaAction*) pAction )->Execute( &maVDev ); + + ImplBeginRecord( WIN_EMR_SAVEDC ); + ImplEndRecord(); + } + break; + + case( META_POP_ACTION ): + { + ( (MetaAction*) pAction )->Execute( &maVDev ); + + ImplBeginRecord( WIN_EMR_RESTOREDC ); + (*mpStm) << (INT32) -1; + ImplEndRecord(); + + ImplWriteRasterOp( maVDev.GetRasterOp() ); + mbLineChanged = mbFillChanged = mbTextChanged = TRUE; + } + break; + + case( META_RASTEROP_ACTION ): + { + ( (MetaAction*) pAction )->Execute( &maVDev ); + ImplWriteRasterOp( ( (MetaRasterOpAction*) pAction )->GetRasterOp() ); + } + break; + + case( META_LAYOUTMODE_ACTION ): + { + sal_uInt32 nLayoutMode = ( (MetaLayoutModeAction*) pAction )->GetLayoutMode(); + mnHorTextAlign = 0; + if (nLayoutMode & TEXT_LAYOUT_BIDI_RTL) + { + mnHorTextAlign = TA_RIGHT | TA_RTLREADING; + } + if (nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_RIGHT) + mnHorTextAlign |= TA_RIGHT; + else if (nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT) + mnHorTextAlign &= ~TA_RIGHT; + break; + } + + case( META_MASK_ACTION ): + case( META_MASKSCALE_ACTION ): + case( META_MASKSCALEPART_ACTION ): + case( META_WALLPAPER_ACTION ): + case( META_TEXTLINE_ACTION ): + case( META_COMMENT_ACTION ): + case( META_GRADIENTEX_ACTION ): + { + // !!! >>> we don't want to support these actions + } + break; + + default: + DBG_ERROR( ( ByteString( "EMFWriter::ImplWriteActions: unsupported MetaAction #" ) += ByteString::CreateFromInt32( nType ) ).GetBuffer() ); + break; + } + } +} diff --git a/svtools/source/filter.vcl/wmf/emfwr.hxx b/svtools/source/filter.vcl/wmf/emfwr.hxx new file mode 100644 index 000000000000..6334b5dfe16f --- /dev/null +++ b/svtools/source/filter.vcl/wmf/emfwr.hxx @@ -0,0 +1,100 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EMFWR_HXX +#define _EMFWR_HXX + +#include <tools/debug.hxx> +#include <vcl/metaact.hxx> +#include <vcl/graph.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/virdev.hxx> +#include <svtools/fltcall.hxx> + +// ------------- +// - EMFWriter - +// ------------- + +class LineInfo; +namespace basegfx { class B2DPolygon; } + +class EMFWriter +{ +private: + + VirtualDevice maVDev; + MapMode maDestMapMode; + FilterConfigItem* mpFilterConfigItem; + SvStream* mpStm; + BOOL* mpHandlesUsed; + ULONG mnHandleCount; + ULONG mnLastPercent; + ULONG mnRecordCount; + ULONG mnRecordPos; + BOOL mbRecordOpen; + BOOL mbLineChanged; + sal_uInt32 mnLineHandle; + BOOL mbFillChanged; + sal_uInt32 mnFillHandle; + BOOL mbTextChanged; + sal_uInt32 mnTextHandle; + sal_uInt32 mnHorTextAlign; + + void ImplBeginRecord( sal_uInt32 nType ); + void ImplEndRecord(); + + ULONG ImplAcquireHandle(); + void ImplReleaseHandle( ULONG nHandle ); + + BOOL ImplPrepareHandleSelect( sal_uInt32& rHandle, ULONG nSelectType ); + void ImplCheckLineAttr(); + void ImplCheckFillAttr(); + void ImplCheckTextAttr(); + + void ImplWriteColor( const Color& rColor ); + void ImplWriteRasterOp( RasterOp eRop ); + void ImplWriteExtent( long nExtent ); + void ImplWritePoint( const Point& rPoint ); + void ImplWriteSize( const Size& rSize); + void ImplWriteRect( const Rectangle& rRect ); + void ImplWritePath( const PolyPolygon& rPolyPoly, sal_Bool bClose ); + void ImplWritePolygonRecord( const Polygon& rPoly, BOOL bClose ); + void ImplWritePolyPolygonRecord( const PolyPolygon& rPolyPoly ); + void ImplWriteBmpRecord( const Bitmap& rBmp, const Point& rPt, const Size& rSz, UINT32 nROP ); + void ImplWriteTextRecord( const Point& rPos, const String rText, const sal_Int32* pDXArray, sal_uInt32 nWidth ); + + void Impl_handleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon); + void ImplWrite( const GDIMetaFile& rMtf ); + +public: + + EMFWriter() {} + + BOOL WriteEMF( const GDIMetaFile& rMtf, SvStream& rOStm, FilterConfigItem* pConfigItem = NULL ); +}; + +#endif // _EMFWR_HXX diff --git a/svtools/source/filter.vcl/wmf/enhwmf.cxx b/svtools/source/filter.vcl/wmf/enhwmf.cxx new file mode 100644 index 000000000000..1e49e0d61446 --- /dev/null +++ b/svtools/source/filter.vcl/wmf/enhwmf.cxx @@ -0,0 +1,1343 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +#include "winmtf.hxx" +#include <osl/endian.h> + +//=========================== GDI-Array =================================== + +#define EMR_HEADER 1 +#define EMR_POLYBEZIER 2 +#define EMR_POLYGON 3 +#define EMR_POLYLINE 4 +#define EMR_POLYBEZIERTO 5 +#define EMR_POLYLINETO 6 +#define EMR_POLYPOLYLINE 7 +#define EMR_POLYPOLYGON 8 +#define EMR_SETWINDOWEXTEX 9 +#define EMR_SETWINDOWORGEX 10 +#define EMR_SETVIEWPORTEXTEX 11 +#define EMR_SETVIEWPORTORGEX 12 +#define EMR_SETBRUSHORGEX 13 +#define EMR_EOF 14 +#define EMR_SETPIXELV 15 +#define EMR_SETMAPPERFLAGS 16 +#define EMR_SETMAPMODE 17 +#define EMR_SETBKMODE 18 +#define EMR_SETPOLYFILLMODE 19 +#define EMR_SETROP2 20 +#define EMR_SETSTRETCHBLTMODE 21 +#define EMR_SETTEXTALIGN 22 +#define EMR_SETCOLORADJUSTMENT 23 +#define EMR_SETTEXTCOLOR 24 +#define EMR_SETBKCOLOR 25 +#define EMR_OFFSETCLIPRGN 26 +#define EMR_MOVETOEX 27 +#define EMR_SETMETARGN 28 +#define EMR_EXCLUDECLIPRECT 29 +#define EMR_INTERSECTCLIPRECT 30 +#define EMR_SCALEVIEWPORTEXTEX 31 +#define EMR_SCALEWINDOWEXTEX 32 +#define EMR_SAVEDC 33 +#define EMR_RESTOREDC 34 +#define EMR_SETWORLDTRANSFORM 35 +#define EMR_MODIFYWORLDTRANSFORM 36 +#define EMR_SELECTOBJECT 37 +#define EMR_CREATEPEN 38 +#define EMR_CREATEBRUSHINDIRECT 39 +#define EMR_DELETEOBJECT 40 +#define EMR_ANGLEARC 41 +#define EMR_ELLIPSE 42 +#define EMR_RECTANGLE 43 +#define EMR_ROUNDRECT 44 +#define EMR_ARC 45 +#define EMR_CHORD 46 +#define EMR_PIE 47 +#define EMR_SELECTPALETTE 48 +#define EMR_CREATEPALETTE 49 +#define EMR_SETPALETTEENTRIES 50 +#define EMR_RESIZEPALETTE 51 +#define EMR_REALIZEPALETTE 52 +#define EMR_EXTFLOODFILL 53 +#define EMR_LINETO 54 +#define EMR_ARCTO 55 +#define EMR_POLYDRAW 56 +#define EMR_SETARCDIRECTION 57 +#define EMR_SETMITERLIMIT 58 +#define EMR_BEGINPATH 59 +#define EMR_ENDPATH 60 +#define EMR_CLOSEFIGURE 61 +#define EMR_FILLPATH 62 +#define EMR_STROKEANDFILLPATH 63 +#define EMR_STROKEPATH 64 +#define EMR_FLATTENPATH 65 +#define EMR_WIDENPATH 66 +#define EMR_SELECTCLIPPATH 67 +#define EMR_ABORTPATH 68 + +#define EMR_GDICOMMENT 70 +#define EMR_FILLRGN 71 +#define EMR_FRAMERGN 72 +#define EMR_INVERTRGN 73 +#define EMR_PAINTRGN 74 +#define EMR_EXTSELECTCLIPRGN 75 +#define EMR_BITBLT 76 +#define EMR_STRETCHBLT 77 +#define EMR_MASKBLT 78 +#define EMR_PLGBLT 79 +#define EMR_SETDIBITSTODEVICE 80 +#define EMR_STRETCHDIBITS 81 +#define EMR_EXTCREATEFONTINDIRECTW 82 +#define EMR_EXTTEXTOUTA 83 +#define EMR_EXTTEXTOUTW 84 +#define EMR_POLYBEZIER16 85 +#define EMR_POLYGON16 86 +#define EMR_POLYLINE16 87 +#define EMR_POLYBEZIERTO16 88 +#define EMR_POLYLINETO16 89 +#define EMR_POLYPOLYLINE16 90 +#define EMR_POLYPOLYGON16 91 +#define EMR_POLYDRAW16 92 +#define EMR_CREATEMONOBRUSH 93 +#define EMR_CREATEDIBPATTERNBRUSHPT 94 +#define EMR_EXTCREATEPEN 95 +#define EMR_POLYTEXTOUTA 96 +#define EMR_POLYTEXTOUTW 97 + +// WINDOWS VERSION >= 0x400 +#define EMR_SETICMMODE 98 +#define EMR_CREATECOLORSPACE 99 +#define EMR_SETCOLORSPACE 100 +#define EMR_DELETECOLORSPACE 101 +#define EMR_GLSRECORD 102 +#define EMR_GLSBOUNDEDRECORD 103 +#define EMR_PIXELFORMAT 104 + +// WINDOWS VERSION >= 0x500 +#define EMR_DRAWESCAPE 105 +#define EMR_EXTESCAPE 106 +#define EMR_STARTDOC 107 +#define EMR_SMALLTEXTOUT 108 +#define EMR_FORCEUFIMAPPING 109 +#define EMR_NAMEDESCAPE 110 +#define EMR_COLORCORRECTPALETTE 111 +#define EMR_SETICMPROFILEA 112 +#define EMR_SETICMPROFILEW 113 +#define EMR_ALPHABLEND 114 +#define EMR_ALPHADIBBLEND 115 +#define EMR_TRANSPARENTBLT 116 +#define EMR_TRANSPARENTDIB 117 +#define EMR_GRADIENTFILL 118 +#define EMR_SETLINKEDUFIS 119 +#define EMR_SETTEXTJUSTIFICATION 120 + + +//----------------------------------------------------------------------------------- + +#ifdef OSL_BIGENDIAN +// currently unused +static float GetSwapFloat( SvStream& rSt ) +{ + float fTmp; + sal_Int8* pPtr = (sal_Int8*)&fTmp; + rSt >> pPtr[3] >> pPtr[2] >> pPtr[1] >> pPtr[0]; // Little Endian <-> Big Endian switch + return fTmp; +} +#endif + +SvStream& operator>>( SvStream& rIn, XForm& rXForm ) +{ + if ( sizeof( float ) != 4 ) + { + DBG_ERROR( "EnhWMFReader::sizeof( float ) != 4" ); + rXForm = XForm(); + } + else + { +#ifdef OSL_BIGENDIAN + rXForm.eM11 = GetSwapFloat( rIn ); + rXForm.eM12 = GetSwapFloat( rIn ); + rXForm.eM21 = GetSwapFloat( rIn ); + rXForm.eM22 = GetSwapFloat( rIn ); + rXForm.eDx = GetSwapFloat( rIn ); + rXForm.eDy = GetSwapFloat( rIn ); +#else + rIn >> rXForm.eM11 >> rXForm.eM12 >> rXForm.eM21 >> rXForm.eM22 + >> rXForm.eDx >> rXForm.eDy; +#endif + } + return rIn; +} + +static sal_Bool ImplReadRegion( PolyPolygon& rPolyPoly, SvStream& rSt, sal_uInt32 nLen ) +{ + sal_Bool bOk = sal_False; + if ( nLen ) + { + sal_uInt32 nHdSize, nType, nCount, nRgnSize, i; + rSt >> nHdSize + >> nType + >> nCount + >> nRgnSize; + + if ( nCount && ( nType == RDH_RECTANGLES ) && + ( nLen >= ( ( nCount << 4 ) + ( nHdSize - 16 ) ) ) ) + { + sal_Int32 nx1, ny1, nx2, ny2; + + for ( i = 0; i < nCount; i++ ) + { + rSt >> nx1 >> ny1 >> nx2 >> ny2; + + Rectangle aRect( Point( nx1, ny1 ), Point( nx2, ny2 ) ); + Polygon aPolygon( aRect ); + PolyPolygon aPolyPolyOr1( aPolygon ); + PolyPolygon aPolyPolyOr2( rPolyPoly ); + rPolyPoly.GetUnion( aPolyPolyOr1, aPolyPolyOr2 ); + rPolyPoly = aPolyPolyOr2; + } + bOk = sal_True; + } + } + return bOk; +} + +BOOL EnhWMFReader::ReadEnhWMF() +{ + sal_uInt32 nStretchBltMode = 0; + sal_uInt32 nRecType, nRecSize, nNextPos, + nW, nH, nPoints, nColor, nIndex, + nDat32, nNom1, nDen1, nNom2, nDen2; + sal_Int32 nX32, nY32, nx32, ny32; + sal_Int16 nX16, nY16; + + sal_Bool bFlag, bStatus = ReadHeader(); + + while( bStatus && nRecordCount-- ) + { + *pWMF >> nRecType >> nRecSize; + + if ( ( nRecSize < 8 ) || ( nRecSize & 3 ) ) // Parameter sind immer durch 4 teilbar + { + bStatus = FALSE; + break; + } + + nNextPos = pWMF->Tell() + ( nRecSize - 8 ); + + if ( nNextPos > nEndPos ) + { + bStatus = FALSE; + break; + } + + if( aBmpSaveList.Count() && ( nRecType != EMR_STRETCHBLT ) && ( nRecType != EMR_STRETCHDIBITS ) ) + pOut->ResolveBitmapActions( aBmpSaveList ); + + bFlag = sal_False; + + switch( nRecType ) + { + case EMR_POLYBEZIERTO : + bFlag = sal_True; + case EMR_POLYBEZIER : + { + pWMF->SeekRel( 16 ); + *pWMF >> nPoints; + sal_uInt16 i = 0; + if ( bFlag ) + { + i++; + nPoints++; + } + Polygon aPoly( (sal_uInt16)nPoints ); + for( ; i < (sal_uInt16)nPoints; i++ ) + { + *pWMF >> nX32 >> nY32; + aPoly[ i ] = Point( nX32, nY32 ); + } + pOut->DrawPolyBezier( aPoly, bFlag, bRecordPath ); + } + break; + + case EMR_POLYGON : + { + pWMF->SeekRel( 16 ); + *pWMF >> nPoints; + Polygon aPoly( (UINT16)nPoints ); + for( UINT16 k = 0; k < (UINT16)nPoints; k++ ) + { + *pWMF >> nX32 >> nY32; + aPoly[ k ] = Point( nX32, nY32 ); + } + pOut->DrawPolygon( aPoly, bRecordPath ); + } + break; + + case EMR_POLYLINETO : + bFlag = sal_True; + case EMR_POLYLINE : + { + pWMF->SeekRel( 0x10 ); + *pWMF >> nPoints; + UINT16 i = 0; + if ( bFlag ) + { + i++; + nPoints++; + } + Polygon aPolygon( (UINT16)nPoints ); + for ( ; i < (UINT16)nPoints; i++ ) + { + *pWMF >> nX32 >> nY32; + aPolygon[ i ] = Point( nX32, nY32 ); + } + pOut->DrawPolyLine( aPolygon, bFlag, bRecordPath ); + } + break; + + case EMR_POLYPOLYLINE : + { + UINT16* pnPoints; + + INT32 i, nPoly; + pWMF->SeekRel( 0x10 ); + + // Anzahl der Polygone: + *pWMF >> nPoly >> i; + + // taking the amount of points of each polygon, retrieving the total number of points + if ( static_cast< sal_uInt32 >(nPoly) < SAL_MAX_UINT32 / sizeof(UINT16) ) + { + if ( ( static_cast< sal_uInt32 >( nPoly ) * sizeof(UINT16) ) <= ( nEndPos - pWMF->Tell() ) ) + { + pnPoints = new UINT16[ nPoly ]; + + for ( i = 0; i < nPoly; i++ ) + { + *pWMF >> nPoints; + pnPoints[ i ] = (UINT16)nPoints; + } + + // Polygonpunkte holen: + + for ( i = 0; ( i < nPoly ) && !pWMF->IsEof(); i++ ) + { + Polygon aPoly( pnPoints[ i ] ); + for( UINT16 k = 0; k < pnPoints[ i ]; k++ ) + { + *pWMF >> nX32 >> nY32; + aPoly[ k ] = Point( nX32, nY32 ); + } + pOut->DrawPolyLine( aPoly, sal_False, bRecordPath ); + } + delete[] pnPoints; + } + } + } + break; + + case EMR_POLYPOLYGON : + { + UINT16* pnPoints; + Point* pPtAry; + + UINT32 i, nPoly, nGesPoints; + pWMF->SeekRel( 0x10 ); + + // Anzahl der Polygone: + *pWMF >> nPoly >> nGesPoints; + + if ( ( nGesPoints < SAL_MAX_UINT32 / sizeof(Point) ) && ( nPoly < SAL_MAX_UINT32 / sizeof(UINT16) ) ) + { + if ( ( nPoly * sizeof(UINT16) ) <= ( nEndPos - pWMF->Tell() ) ) + { + pnPoints = new UINT16[ nPoly ]; + + for ( i = 0; i < nPoly; i++ ) + { + *pWMF >> nPoints; + pnPoints[ i ] = (UINT16)nPoints; + } + + if ( ( nGesPoints * (sizeof(sal_uInt32)+sizeof(sal_uInt32)) ) <= ( nEndPos - pWMF->Tell() ) ) + { + // Polygonpunkte holen: + pPtAry = new Point[ nGesPoints ]; + + for ( i = 0; i < nGesPoints; i++ ) + { + *pWMF >> nX32 >> nY32; + pPtAry[ i ] = Point( nX32, nY32 ); + } + // PolyPolygon Actions erzeugen + PolyPolygon aPolyPoly( (UINT16)nPoly, pnPoints, pPtAry ); + pOut->DrawPolyPolygon( aPolyPoly, bRecordPath ); + delete[] pPtAry; + } + delete[] pnPoints; + } + } + } + break; + + case EMR_SETWINDOWEXTEX : + { // #75383# + *pWMF >> nW >> nH; + pOut->SetWinExt( Size( nW, nH ) ); + } + break; + + case EMR_SETWINDOWORGEX : + { + *pWMF >> nX32 >> nY32; + pOut->SetWinOrg( Point( nX32, nY32 ) ); + } + break; + + case EMR_SCALEWINDOWEXTEX : + { + *pWMF >> nNom1 >> nDen1 >> nNom2 >> nDen2; + pOut->ScaleWinExt( (double)nNom1 / nDen1, (double)nNom2 / nDen2 ); + } + break; + + case EMR_SETVIEWPORTORGEX : + { + *pWMF >> nX32 >> nY32; + pOut->SetDevOrg( Point( nX32, nY32 ) ); + } + break; + + case EMR_SCALEVIEWPORTEXTEX : + { + *pWMF >> nNom1 >> nDen1 >> nNom2 >> nDen2; + pOut->ScaleDevExt( (double)nNom1 / nDen1, (double)nNom2 / nDen2 ); + } + break; + + case EMR_SETVIEWPORTEXTEX : + { + *pWMF >> nW >> nH; + pOut->SetDevExt( Size( nW, nH ) ); + } + break; + + case EMR_EOF : + nRecordCount = 0; // #76846# + break; + + case EMR_SETPIXELV : + { + *pWMF >> nX32 >> nY32; + pOut->DrawPixel( Point( nX32, nY32 ), ReadColor() ); + } + break; + + case EMR_SETMAPMODE : + { + sal_uInt32 nMapMode; + *pWMF >> nMapMode; + pOut->SetMapMode( nMapMode ); + } + break; + + case EMR_SETBKMODE : + { + *pWMF >> nDat32; + pOut->SetBkMode( nDat32 ); + } + break; + + case EMR_SETPOLYFILLMODE : + break; + + case EMR_SETROP2 : + { + *pWMF >> nDat32; + pOut->SetRasterOp( nDat32 ); + } + break; + + case EMR_SETSTRETCHBLTMODE : + { + *pWMF >> nStretchBltMode; + } + break; + + case EMR_SETTEXTALIGN : + { + *pWMF >> nDat32; + pOut->SetTextAlign( nDat32 ); + } + break; + + case EMR_SETTEXTCOLOR : + { + pOut->SetTextColor( ReadColor() ); + } + break; + + case EMR_SETBKCOLOR : + { + pOut->SetBkColor( ReadColor() ); + } + break; + + case EMR_OFFSETCLIPRGN : + { + *pWMF >> nX32 >> nY32; + pOut->MoveClipRegion( Size( nX32, nY32 ) ); + } + break; + + case EMR_MOVETOEX : + { + *pWMF >> nX32 >> nY32; + pOut->MoveTo( Point( nX32, nY32 ), bRecordPath ); + } + break; + + case EMR_INTERSECTCLIPRECT : + { + *pWMF >> nX32 >> nY32 >> nx32 >> ny32; + pOut->IntersectClipRect( ReadRectangle( nX32, nY32, nx32, ny32 ) ); + } + break; + + case EMR_SAVEDC : + { + pOut->Push(); + } + break; + + case EMR_RESTOREDC : + { + pOut->Pop(); + } + break; + + case EMR_SETWORLDTRANSFORM : + { + XForm aTempXForm; + *pWMF >> aTempXForm; + pOut->SetWorldTransform( aTempXForm ); + } + break; + + case EMR_MODIFYWORLDTRANSFORM : + { + UINT32 nMode; + XForm aTempXForm; + *pWMF >> aTempXForm >> nMode; + pOut->ModifyWorldTransform( aTempXForm, nMode ); + } + break; + + case EMR_SELECTOBJECT : + { + *pWMF >> nIndex; + pOut->SelectObject( nIndex ); + } + break; + + case EMR_CREATEPEN : + { + *pWMF >> nIndex; + if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) + { + + LineInfo aLineInfo; + UINT32 nStyle; + Size aSize; + + *pWMF >> nStyle >> aSize.Width() >> aSize.Height(); + + if ( aSize.Width() ) + aLineInfo.SetWidth( aSize.Width() ); + + BOOL bTransparent = FALSE; + UINT16 nDashCount = 0; + UINT16 nDotCount = 0; + switch( nStyle ) + { + case PS_DASHDOTDOT : + nDotCount++; + case PS_DASHDOT : + nDashCount++; + case PS_DOT : + nDotCount++; + break; + case PS_DASH : + nDashCount++; + break; + case PS_NULL : + bTransparent = TRUE; + aLineInfo.SetStyle( LINE_NONE ); + break; + default : + case PS_INSIDEFRAME : + case PS_SOLID : + aLineInfo.SetStyle( LINE_SOLID ); + } + if ( nDashCount | nDotCount ) + { + aLineInfo.SetStyle( LINE_DASH ); + aLineInfo.SetDashCount( nDashCount ); + aLineInfo.SetDotCount( nDotCount ); + } + pOut->CreateObject( nIndex, GDI_PEN, new WinMtfLineStyle( ReadColor(), aLineInfo, bTransparent ) ); + } + } + break; + + case EMR_EXTCREATEPEN : + { + sal_Int32 elpHatch; + sal_uInt32 offBmi, cbBmi, offBits, cbBits, nStyle, nWidth, nBrushStyle, elpNumEntries; + Color aColorRef; + + *pWMF >> nIndex; + if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) + { + *pWMF >> offBmi >> cbBmi >> offBits >> cbBits >> nStyle >> nWidth >> nBrushStyle; + aColorRef = ReadColor(); + *pWMF >> elpHatch >> elpNumEntries; + + LineInfo aLineInfo; + if ( nWidth ) + aLineInfo.SetWidth( nWidth ); + + sal_Bool bTransparent = sal_False; + sal_uInt16 nDashCount = 0; + sal_uInt16 nDotCount = 0; + + switch( nStyle & PS_STYLE_MASK ) + { + case PS_DASHDOTDOT : + nDotCount++; + case PS_DASHDOT : + nDashCount++; + case PS_DOT : + nDotCount++; + break; + case PS_DASH : + nDashCount++; + break; + case PS_NULL : + bTransparent = sal_True; + aLineInfo.SetStyle( LINE_NONE ); + break; + + default : + case PS_INSIDEFRAME : + case PS_SOLID : + aLineInfo.SetStyle( LINE_SOLID ); + } + if ( nDashCount | nDotCount ) + { + aLineInfo.SetStyle( LINE_DASH ); + aLineInfo.SetDashCount( nDashCount ); + aLineInfo.SetDotCount( nDotCount ); + } + pOut->CreateObject( nIndex, GDI_PEN, new WinMtfLineStyle( aColorRef, aLineInfo, bTransparent ) ); + } + } + break; + + case EMR_CREATEBRUSHINDIRECT : + { + UINT32 nStyle; + *pWMF >> nIndex; + if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) + { + *pWMF >> nStyle; + pOut->CreateObject( nIndex, GDI_BRUSH, new WinMtfFillStyle( ReadColor(), ( nStyle == BS_HOLLOW ) ? TRUE : FALSE ) ); + } + } + break; + + case EMR_DELETEOBJECT : + { + *pWMF >> nIndex; + if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) + pOut->DeleteObject( nIndex ); + } + break; + + case EMR_ELLIPSE : + { + *pWMF >> nX32 >> nY32 >> nx32 >> ny32; + pOut->DrawEllipse( ReadRectangle( nX32, nY32, nx32, ny32 ) ); + } + break; + + case EMR_RECTANGLE : + { + *pWMF >> nX32 >> nY32 >> nx32 >> ny32; + pOut->DrawRect( ReadRectangle( nX32, nY32, nx32, ny32 ) ); + } + break; + + case EMR_ROUNDRECT : + { + *pWMF >> nX32 >> nY32 >> nx32 >> ny32 >> nW >> nH; + Size aSize( Size( nW, nH ) ); + pOut->DrawRoundRect( ReadRectangle( nX32, nY32, nx32, ny32 ), aSize ); + } + break; + + case EMR_ARC : + { + UINT32 nStartX, nStartY, nEndX, nEndY; + *pWMF >> nX32 >> nY32 >> nx32 >> ny32 >> nStartX >> nStartY >> nEndX >> nEndY; + pOut->DrawArc( ReadRectangle( nX32, nY32, nx32, ny32 ), Point( nStartX, nStartY ), Point( nEndX, nEndY ) ); + } + break; + + case EMR_CHORD : + { + UINT32 nStartX, nStartY, nEndX, nEndY; + *pWMF >> nX32 >> nY32 >> nx32 >> ny32 >> nStartX >> nStartY >> nEndX >> nEndY; + pOut->DrawChord( ReadRectangle( nX32, nY32, nx32, ny32 ), Point( nStartX, nStartY ), Point( nEndX, nEndY ) ); + } + break; + + case EMR_PIE : + { + UINT32 nStartX, nStartY, nEndX, nEndY; + *pWMF >> nX32 >> nY32 >> nx32 >> ny32 >> nStartX >> nStartY >> nEndX >> nEndY; + const Rectangle aRect( ReadRectangle( nX32, nY32, nx32, ny32 )); + + // #i73608# OutputDevice deviates from WMF + // semantics. start==end means full ellipse here. + if( nStartX == nEndX && nStartY == nEndY ) + pOut->DrawEllipse( aRect ); + else + pOut->DrawPie( aRect, Point( nStartX, nStartY ), Point( nEndX, nEndY ) ); + } + break; + + case EMR_LINETO : + { + *pWMF >> nX32 >> nY32; + pOut->LineTo( Point( nX32, nY32 ), bRecordPath ); + } + break; + + case EMR_ARCTO : + { + UINT32 nStartX, nStartY, nEndX, nEndY; + *pWMF >> nX32 >> nY32 >> nx32 >> ny32 >> nStartX >> nStartY >> nEndX >> nEndY; + pOut->DrawArc( ReadRectangle( nX32, nY32, nx32, ny32 ), Point( nStartX, nStartY ), Point( nEndX, nEndY ), TRUE ); + } + break; + + case EMR_BEGINPATH : + { + pOut->ClearPath(); + bRecordPath = sal_True; + } + break; + + case EMR_ABORTPATH : + pOut->ClearPath(); + case EMR_ENDPATH : + bRecordPath = sal_False; + break; + + case EMR_CLOSEFIGURE : + pOut->ClosePath(); + break; + + case EMR_FILLPATH : + pOut->StrokeAndFillPath( sal_False, sal_True ); + break; + + case EMR_STROKEANDFILLPATH : + pOut->StrokeAndFillPath( sal_True, sal_True ); + break; + + case EMR_STROKEPATH : + pOut->StrokeAndFillPath( sal_True, sal_False ); + break; + + case EMR_SELECTCLIPPATH : + { + sal_Int32 nClippingMode; + *pWMF >> nClippingMode; + pOut->SetClipPath( pOut->GetPathObj(), nClippingMode, sal_True ); + } + break; + + case EMR_EXTSELECTCLIPRGN : + { + sal_Int32 iMode, cbRgnData; + *pWMF >> cbRgnData + >> iMode; + + PolyPolygon aPolyPoly; + if ( cbRgnData ) + ImplReadRegion( aPolyPoly, *pWMF, nRecSize ); + pOut->SetClipPath( aPolyPoly, iMode, sal_False ); + } + break; + + case EMR_BITBLT : // PASSTHROUGH INTENDED + case EMR_STRETCHBLT : + { + INT32 xDest, yDest, cxDest, cyDest, xSrc, ySrc, cxSrc, cySrc; + UINT32 dwRop, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc; + XForm xformSrc; + + UINT32 nStart = pWMF->Tell() - 8; + + pWMF->SeekRel( 0x10 ); + *pWMF >> xDest >> yDest >> cxDest >> cyDest >> dwRop >> xSrc >> ySrc + >> xformSrc >> nColor >> iUsageSrc >> offBmiSrc >> cbBmiSrc + >> offBitsSrc >> cbBitsSrc; + + if ( nRecType == EMR_STRETCHBLT ) + *pWMF >> cxSrc >> cySrc; + else + cxSrc = cySrc = 0; + + Bitmap aBitmap; + Rectangle aRect( Point( xDest, yDest ), Size( cxDest+1, cyDest+1 ) ); + + cxDest = abs( (int)cxDest ); // sj: i37894, size can be negative + cyDest = abs( (int)cyDest ); // and also 122889 + + if ( (cbBitsSrc > (SAL_MAX_UINT32 - 14)) || ((SAL_MAX_UINT32 - 14) - cbBitsSrc < cbBmiSrc) ) + bStatus = FALSE; + else + { + UINT32 nSize = cbBmiSrc + cbBitsSrc + 14; + if ( nSize <= ( nEndPos - nStartPos ) ) + { + char* pBuf = new char[ nSize ]; + SvMemoryStream aTmp( pBuf, nSize, STREAM_READ | STREAM_WRITE ); + aTmp.ObjectOwnsMemory( TRUE ); + aTmp << (BYTE)'B' + << (BYTE)'M' + << (UINT32)cbBitsSrc + << (UINT16)0 + << (UINT16)0 + << (UINT32)cbBmiSrc + 14; + pWMF->Seek( nStart + offBmiSrc ); + pWMF->Read( pBuf + 14, cbBmiSrc ); + pWMF->Seek( nStart + offBitsSrc ); + pWMF->Read( pBuf + 14 + cbBmiSrc, cbBitsSrc ); + aTmp.Seek( 0 ); + aBitmap.Read( aTmp, TRUE ); + + // test if it is sensible to crop + if ( ( cxSrc > 0 ) && ( cySrc > 0 ) && + ( xSrc >= 0 ) && ( ySrc >= 0 ) && + ( xSrc + cxSrc <= aBitmap.GetSizePixel().Width() ) && + ( ySrc + cySrc <= aBitmap.GetSizePixel().Height() ) ) + { + Rectangle aCropRect( Point( xSrc, ySrc ), Size( cxSrc, cySrc ) ); + aBitmap.Crop( aCropRect ); + } + aBmpSaveList.Insert( new BSaveStruct( aBitmap, aRect, dwRop ), LIST_APPEND ); + } + } + } + break; + + case EMR_STRETCHDIBITS : + { + INT32 xDest, yDest, xSrc, ySrc, cxSrc, cySrc, cxDest, cyDest; + UINT32 offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, iUsageSrc, dwRop; + UINT32 nStart = pWMF->Tell() - 8; + + pWMF->SeekRel( 0x10 ); + *pWMF >> xDest >> yDest >> xSrc >> ySrc >> cxSrc >> cySrc >> offBmiSrc >> cbBmiSrc >> offBitsSrc + >> cbBitsSrc >> iUsageSrc >> dwRop >> cxDest >> cyDest; + + Bitmap aBitmap; + Rectangle aRect( Point( xDest, yDest ), Size( cxDest+1, cyDest+1 ) ); + + cxDest = abs( (int)cxDest ); // sj: i37894, size can be negative + cyDest = abs( (int)cyDest ); // and also 122889 + + if ( (cbBitsSrc > (SAL_MAX_UINT32 - 14)) || ((SAL_MAX_UINT32 - 14) - cbBitsSrc < cbBmiSrc) ) + bStatus = FALSE; + else + { + UINT32 nSize = cbBmiSrc + cbBitsSrc + 14; + if ( nSize <= ( nEndPos - nStartPos ) ) + { + char* pBuf = new char[ nSize ]; + SvMemoryStream aTmp( pBuf, nSize, STREAM_READ | STREAM_WRITE ); + aTmp.ObjectOwnsMemory( TRUE ); + aTmp << (BYTE)'B' + << (BYTE)'M' + << (UINT32)cbBitsSrc + << (UINT16)0 + << (UINT16)0 + << (UINT32)cbBmiSrc + 14; + pWMF->Seek( nStart + offBmiSrc ); + pWMF->Read( pBuf + 14, cbBmiSrc ); + pWMF->Seek( nStart + offBitsSrc ); + pWMF->Read( pBuf + 14 + cbBmiSrc, cbBitsSrc ); + aTmp.Seek( 0 ); + aBitmap.Read( aTmp, TRUE ); + + // test if it is sensible to crop + if ( ( cxSrc > 0 ) && ( cySrc > 0 ) && + ( xSrc >= 0 ) && ( ySrc >= 0 ) && + ( xSrc + cxSrc <= aBitmap.GetSizePixel().Width() ) && + ( ySrc + cySrc <= aBitmap.GetSizePixel().Height() ) ) + { + Rectangle aCropRect( Point( xSrc, ySrc ), Size( cxSrc, cySrc ) ); + aBitmap.Crop( aCropRect ); + } + aBmpSaveList.Insert( new BSaveStruct( aBitmap, aRect, dwRop ), LIST_APPEND ); + } + } + } + break; + + case EMR_EXTCREATEFONTINDIRECTW : + { + *pWMF >> nIndex; + if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) + { + LOGFONTW aLogFont; + *pWMF >> aLogFont.lfHeight >> aLogFont.lfWidth >> aLogFont.lfEscapement >> aLogFont.lfOrientation >> aLogFont.lfWeight >> aLogFont.lfItalic + >> aLogFont.lfUnderline >> aLogFont.lfStrikeOut >> aLogFont.lfCharSet >> aLogFont.lfOutPrecision >> aLogFont.lfClipPrecision + >> aLogFont.lfQuality >> aLogFont.lfPitchAndFamily; + + sal_Unicode lfFaceName[ LF_FACESIZE ]; + + for ( int i = 0; i < LF_FACESIZE; i++ ) + { + UINT16 nChar; + *pWMF >> nChar; + lfFaceName[ i ] = nChar; + } + aLogFont.alfFaceName = UniString( lfFaceName ); + pOut->CreateObject( nIndex, GDI_FONT, new WinMtfFontStyle( aLogFont ) ); + } + } + break; + + case EMR_EXTTEXTOUTA : + bFlag = sal_True; + case EMR_EXTTEXTOUTW : + { + sal_Int32 nLeft, nTop, nRight, nBottom, ptlReferenceX, ptlReferenceY, nGfxMode, nXScale, nYScale; + sal_uInt32 nCurPos, nLen, nOffString, nOptions, offDx; + sal_Int32* pDX = NULL; + + nCurPos = pWMF->Tell() - 8; + + *pWMF >> nLeft >> nTop >> nRight >> nBottom >> nGfxMode >> nXScale >> nYScale + >> ptlReferenceX >> ptlReferenceY >> nLen >> nOffString >> nOptions; + + pWMF->SeekRel( 0x10 ); + *pWMF >> offDx; + + sal_Int32 nTextLayoutMode = TEXT_LAYOUT_DEFAULT; + if ( nOptions & ETO_RTLREADING ) + nTextLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT; + pOut->SetTextLayoutMode( nTextLayoutMode ); + DBG_ASSERT( ( nOptions & ( ETO_PDY | ETO_GLYPH_INDEX ) ) == 0, "SJ: ETO_PDY || ETO_GLYPH_INDEX in EMF" ); + + Point aPos( ptlReferenceX, ptlReferenceY ); + if ( nLen && ( nLen < SAL_MAX_UINT32 / sizeof(sal_Int32) ) ) + { + if ( offDx && (( nCurPos + offDx + nLen * 4 ) <= nNextPos ) ) + { + pWMF->Seek( nCurPos + offDx ); + if ( ( nLen * sizeof(sal_uInt32) ) <= ( nEndPos - pWMF->Tell() ) ) + { + pDX = new sal_Int32[ nLen ]; + sal_uInt32 i; + for ( i = 0; i < nLen; i++ ) + *pWMF >> pDX[ i ]; + } + } + pWMF->Seek( nCurPos + nOffString ); + String aText; + if ( bFlag ) + { + if ( nLen <= ( nEndPos - pWMF->Tell() ) ) + { + sal_Char* pBuf = new sal_Char[ nLen ]; + pWMF->Read( pBuf, nLen ); + aText = String( pBuf, (sal_uInt16)nLen, pOut->GetCharSet() ); + delete[] pBuf; + + if ( aText.Len() != nLen ) + { + sal_uInt16 i, j, k; + sal_Int32* pOldDx = pDX; + pDX = new sal_Int32[ aText.Len() ]; + for ( i = 0, j = 0; i < aText.Len(); i++ ) + { + ByteString aCharacter( aText.GetChar( i ), pOut->GetCharSet() ); + pDX[ i ] = 0; + for ( k = 0; ( k < aCharacter.Len() ) && ( j < nLen ) && ( i < aText.Len() ); k++ ) + pDX[ i ] += pOldDx[ j++ ]; + } + delete[] pOldDx; + } + } + } + else + { + if ( ( nLen * sizeof(sal_Unicode) ) <= ( nEndPos - pWMF->Tell() ) ) + { + sal_Unicode* pBuf = new sal_Unicode[ nLen ]; + pWMF->Read( pBuf, nLen << 1 ); +#ifdef OSL_BIGENDIAN + sal_Char nTmp, *pTmp = (sal_Char*)( pBuf + nLen ); + while ( pTmp-- != (sal_Char*)pBuf ) + { + nTmp = *pTmp--; + pTmp[ 1 ] = *pTmp; + *pTmp = nTmp; + } +#endif + aText = String( pBuf, (xub_StrLen)nLen ); + delete[] pBuf; + } + } + pOut->DrawText( aPos, aText, pDX, bRecordPath, nGfxMode ); + } + delete[] pDX; + } + break; + + case EMR_POLYBEZIERTO16 : + bFlag = sal_True; + case EMR_POLYBEZIER16 : + { + pWMF->SeekRel( 16 ); + *pWMF >> nPoints; + UINT16 i = 0; + if ( bFlag ) + { + i++; + nPoints++; + } + Polygon aPoly( (UINT16)nPoints ); + for( ; i < (UINT16)nPoints; i++ ) + { + *pWMF >> nX16 >> nY16; + aPoly[ i ] = Point( nX16, nY16 ); + } + pOut->DrawPolyBezier( aPoly, bFlag, bRecordPath ); // Line( aPoly, bFlag ); + } + break; + + case EMR_POLYGON16 : + { + pWMF->SeekRel( 16 ); + *pWMF >> nPoints; + Polygon aPoly( (UINT16)nPoints ); + for( UINT16 k = 0; k < (UINT16)nPoints; k++ ) + { + *pWMF >> nX16 >> nY16; + aPoly[ k ] = Point( nX16, nY16 ); + } + pOut->DrawPolygon( aPoly, bRecordPath ); + } + break; + + case EMR_POLYLINETO16 : + bFlag = sal_True; + case EMR_POLYLINE16 : + { + pWMF->SeekRel( 16 ); + *pWMF >> nPoints; + UINT16 i = 0; + if ( bFlag ) + { + i++; + nPoints++; + } + + Polygon aPoly( (UINT16)nPoints ); + for( ; i < (UINT16)nPoints; i++ ) + { + *pWMF >> nX16 >> nY16; + aPoly[ i ] = Point( nX16, nY16 ); + } + pOut->DrawPolyLine( aPoly, bFlag, bRecordPath ); + } + break; + + case EMR_POLYPOLYLINE16 : + { + UINT16* pnPoints; + + INT32 i, nPoly, nGesPoints; + pWMF->SeekRel( 0x10 ); + // Anzahl der Polygone: + *pWMF >> nPoly >> nGesPoints; + + // taking the amount of points of each polygon, retrieving the total number of points + if ( static_cast< sal_uInt32 >(nPoly) < SAL_MAX_UINT32 / sizeof(UINT16) ) + { + if ( ( static_cast< sal_uInt32 >( nPoly ) * sizeof(UINT16) ) <= ( nEndPos - pWMF->Tell() ) ) + { + pnPoints = new UINT16[ nPoly ]; + for ( i = 0; i < nPoly; i++ ) + { + *pWMF >> nPoints; + pnPoints[ i ] = (UINT16)nPoints; + } + // Polygonpunkte holen: + for ( i = 0; ( i < nPoly ) && !pWMF->IsEof(); i++ ) + { + Polygon aPolygon( pnPoints[ i ] ); + for ( UINT16 k = 0; k < pnPoints[ i ]; k++ ) + { + *pWMF >> nX16 >> nY16; + aPolygon[ k ] = Point( nX16, nY16 ); + } + pOut->DrawPolyLine( aPolygon, sal_False, bRecordPath ); + } + delete[] pnPoints; + } + } + } + break; + + case EMR_POLYPOLYGON16 : + { + UINT16* pnPoints; + Point* pPtAry; + + UINT32 i, nPoly, nGesPoints; + pWMF->SeekRel( 0x10 ); + // Anzahl der Polygone: + *pWMF >> nPoly >> nGesPoints; + if ( ( nGesPoints < SAL_MAX_UINT32 / sizeof(Point) ) && ( nPoly < SAL_MAX_UINT32 / sizeof(UINT16) ) ) + { + if ( ( static_cast< sal_uInt32 >( nPoly ) * sizeof( UINT16 ) ) <= ( nEndPos - pWMF->Tell() ) ) + { + pnPoints = new UINT16[ nPoly ]; + for ( i = 0; i < nPoly; i++ ) + { + *pWMF >> nPoints; + pnPoints[ i ] = (UINT16)nPoints; + } + if ( ( nGesPoints * (sizeof(sal_uInt16)+sizeof(sal_uInt16)) ) <= ( nEndPos - pWMF->Tell() ) ) + { + // Polygonpunkte holen: + pPtAry = new Point[ nGesPoints ]; + for ( i = 0; i < nGesPoints; i++ ) + { + *pWMF >> nX16 >> nY16; + pPtAry[ i ] = Point( nX16, nY16 ); + } + + // PolyPolygon Actions erzeugen + PolyPolygon aPolyPoly( (UINT16)nPoly, pnPoints, pPtAry ); + pOut->DrawPolyPolygon( aPolyPoly, bRecordPath ); + delete[] pPtAry; + } + delete[] pnPoints; + } + } + } + break; + + case EMR_FILLRGN : + { + sal_uInt32 nLen; + PolyPolygon aPolyPoly; + pWMF->SeekRel( 0x10 ); + *pWMF >> nLen >> nIndex; + + if ( ImplReadRegion( aPolyPoly, *pWMF, nRecSize ) ) + { + pOut->Push(); + pOut->SelectObject( nIndex ); + pOut->DrawPolyPolygon( aPolyPoly, sal_False ); + pOut->Pop(); + } + } + break; + + +#ifdef WIN_MTF_ASSERT + default : WinMtfAssertHandler( "Unknown Meta Action" ); break; + case EMR_MASKBLT : WinMtfAssertHandler( "MaskBlt" ); break; + case EMR_PLGBLT : WinMtfAssertHandler( "PlgBlt" ); break; + case EMR_SETDIBITSTODEVICE : WinMtfAssertHandler( "SetDIBitsToDevice" ); break; + case EMR_FRAMERGN : WinMtfAssertHandler( "FrameRgn" ); break; + case EMR_INVERTRGN : WinMtfAssertHandler( "InvertRgn" ); break; + case EMR_PAINTRGN : WinMtfAssertHandler( "PaintRgn" ); break; + case EMR_FLATTENPATH : WinMtfAssertHandler( "FlattenPath" ); break; + case EMR_WIDENPATH : WinMtfAssertHandler( "WidenPath" ); break; + case EMR_POLYDRAW : WinMtfAssertHandler( "Polydraw" ); break; + case EMR_SETARCDIRECTION : WinMtfAssertHandler( "SetArcDirection" ); break; + case EMR_SETPALETTEENTRIES : WinMtfAssertHandler( "SetPaletteEntries" ); break; + case EMR_RESIZEPALETTE : WinMtfAssertHandler( "ResizePalette" ); break; + case EMR_EXTFLOODFILL : WinMtfAssertHandler( "ExtFloodFill" ); break; + case EMR_ANGLEARC : WinMtfAssertHandler( "AngleArc" ); break; + case EMR_SETCOLORADJUSTMENT : WinMtfAssertHandler( "SetColorAdjustment" ); break; + case EMR_POLYDRAW16 : WinMtfAssertHandler( "PolyDraw16" ); break; + case EMR_CREATEDIBPATTERNBRUSHPT : WinMtfAssertHandler( "CreateDibPatternBrushPt" ); break; + case EMR_POLYTEXTOUTA : WinMtfAssertHandler( "PolyTextOutA" ); break; + case EMR_POLYTEXTOUTW : WinMtfAssertHandler( "PolyTextOutW" ); break; + case EMR_CREATECOLORSPACE : WinMtfAssertHandler( "CreateColorSpace" ); break; + case EMR_SETCOLORSPACE : WinMtfAssertHandler( "SetColorSpace" ); break; + case EMR_DELETECOLORSPACE : WinMtfAssertHandler( "DeleteColorSpace" ); break; + case EMR_GLSRECORD : WinMtfAssertHandler( "GlsRecord" ); break; + case EMR_GLSBOUNDEDRECORD : WinMtfAssertHandler( "GlsBoundRecord" ); break; + case EMR_PIXELFORMAT : WinMtfAssertHandler( "PixelFormat" ); break; + case EMR_DRAWESCAPE : WinMtfAssertHandler( "DrawEscape" ); break; + case EMR_EXTESCAPE : WinMtfAssertHandler( "ExtEscape" ); break; + case EMR_STARTDOC : WinMtfAssertHandler( "StartDoc" ); break; + case EMR_SMALLTEXTOUT : WinMtfAssertHandler( "SmallTextOut" ); break; + case EMR_FORCEUFIMAPPING : WinMtfAssertHandler( "ForceUFIMapping" ); break; + case EMR_NAMEDESCAPE : WinMtfAssertHandler( "NamedEscape" ); break; + case EMR_COLORCORRECTPALETTE : WinMtfAssertHandler( "ColorCorrectPalette" ); break; + case EMR_SETICMPROFILEA : WinMtfAssertHandler( "SetICMProfileA" ); break; + case EMR_SETICMPROFILEW : WinMtfAssertHandler( "SetICMProfileW" ); break; + case EMR_ALPHABLEND : WinMtfAssertHandler( "Alphablend" ); break; + case EMR_TRANSPARENTBLT : WinMtfAssertHandler( "TransparenBlt" ); break; + case EMR_TRANSPARENTDIB : WinMtfAssertHandler( "TransparenDib" ); break; + case EMR_GRADIENTFILL : WinMtfAssertHandler( "GradientFill" ); break; + case EMR_SETLINKEDUFIS : WinMtfAssertHandler( "SetLinkedUFIS" ); break; + + case EMR_SETMAPPERFLAGS : WinMtfAssertHandler( "SetMapperFlags", 0 ); break; + case EMR_SETICMMODE : WinMtfAssertHandler( "SetICMMode", 0 ); break; + case EMR_CREATEMONOBRUSH : WinMtfAssertHandler( "CreateMonoBrush", 0 ); break; + case EMR_SETBRUSHORGEX : WinMtfAssertHandler( "SetBrushOrgEx", 0 ); break; + case EMR_SETMETARGN : WinMtfAssertHandler( "SetMetArgn", 0 ); break; + case EMR_SETMITERLIMIT : WinMtfAssertHandler( "SetMiterLimit", 0 ); break; + case EMR_EXCLUDECLIPRECT : WinMtfAssertHandler( "ExcludeClipRect", 0 ); break; + case EMR_REALIZEPALETTE : WinMtfAssertHandler( "RealizePalette", 0 ); break; + case EMR_SELECTPALETTE : WinMtfAssertHandler( "SelectPalette", 0 ); break; + case EMR_CREATEPALETTE : WinMtfAssertHandler( "CreatePalette", 0 ); break; + case EMR_ALPHADIBBLEND : WinMtfAssertHandler( "AlphaDibBlend", 0 ); break; + case EMR_SETTEXTJUSTIFICATION : WinMtfAssertHandler( "SetTextJustification", 0 ); break; + + case EMR_GDICOMMENT : + case EMR_HEADER : // has already been read at ReadHeader() + break; +#endif + } + pWMF->Seek( nNextPos ); + } + if( aBmpSaveList.Count() ) + pOut->ResolveBitmapActions( aBmpSaveList ); + + if ( bStatus ) + pWMF->Seek(nEndPos); + + return bStatus; +}; + +//----------------------------------------------------------------------------------- + +BOOL EnhWMFReader::ReadHeader() +{ + UINT32 nUINT32, nHeaderSize, nPalEntries; + INT32 nLeft, nTop, nRight, nBottom; + + // METAFILEHEADER SPARE ICH MIR HIER + // Einlesen des METAHEADER + *pWMF >> nUINT32 >> nHeaderSize; + if ( nUINT32 != 1 ) // Typ + return FALSE; + + // bound size + Rectangle rclBounds; // rectangle in logical units 1/100th mm + *pWMF >> nLeft >> nTop >> nRight >> nBottom; + rclBounds.Left() = nLeft; + rclBounds.Top() = nTop; + rclBounds.Right() = nRight; + rclBounds.Bottom() = nBottom; + + // picture frame size + Rectangle rclFrame; // rectangle in device units + *pWMF >> nLeft >> nTop >> nRight >> nBottom; + rclFrame.Left() = nLeft; + rclFrame.Top() = nTop; + rclFrame.Right() = nRight; + rclFrame.Bottom() = nBottom; + + *pWMF >> nUINT32; // signature + + if ( nUINT32 != 0x464d4520 ) + return FALSE; + + *pWMF >> nUINT32; // nVersion + *pWMF >> nEndPos; // size of metafile + nEndPos += nStartPos; + + sal_uInt32 nStrmPos = pWMF->Tell(); // checking if nEndPos is valid + pWMF->Seek( STREAM_SEEK_TO_END ); + if ( pWMF->Tell() < nEndPos ) + nEndPos = pWMF->Tell(); + pWMF->Seek( nStrmPos ); + + *pWMF >> nRecordCount; + + if ( !nRecordCount ) + return FALSE; + + pWMF->SeekRel( 0xc ); + + sal_Int32 nPixX, nPixY, nMillX, nMillY; + *pWMF >> nPalEntries >> nPixX >> nPixY >> nMillX >> nMillY; + + pOut->SetrclFrame( rclFrame ); + pOut->SetrclBounds( rclBounds ); + pOut->SetRefPix( Size( nPixX, nPixY ) ); + pOut->SetRefMill( Size( nMillX, nMillY ) ); + + pWMF->Seek( nStartPos + nHeaderSize ); + return TRUE; +} + +//----------------------------------------------------------------------------------- + +Rectangle EnhWMFReader::ReadRectangle( INT32 x1, INT32 y1, INT32 x2, INT32 y2 ) +{ + Point aTL ( Point( x1, y1 ) ); + Point aBR( Point( --x2, --y2 ) ); + return Rectangle( aTL, aBR ); +} + +EnhWMFReader::~EnhWMFReader() +{ + +}; + diff --git a/svtools/source/filter.vcl/wmf/makefile.mk b/svtools/source/filter.vcl/wmf/makefile.mk new file mode 100644 index 000000000000..5c9412bc8387 --- /dev/null +++ b/svtools/source/filter.vcl/wmf/makefile.mk @@ -0,0 +1,50 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=svtools +TARGET=wmf +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/svt.pmk + +# --- Files -------------------------------------------------------- + +SLOFILES= $(SLO)$/wmf.obj \ + $(SLO)$/winmtf.obj \ + $(SLO)$/winwmf.obj \ + $(SLO)$/enhwmf.obj \ + $(SLO)$/emfwr.obj \ + $(SLO)$/wmfwr.obj + +# --- Targets ------------------------------------------------------- + +.INCLUDE : target.mk diff --git a/svtools/source/filter.vcl/wmf/winmtf.cxx b/svtools/source/filter.vcl/wmf/winmtf.cxx new file mode 100644 index 000000000000..21f6e69c8d9e --- /dev/null +++ b/svtools/source/filter.vcl/wmf/winmtf.cxx @@ -0,0 +1,2199 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + + +#include "winmtf.hxx" +#include <vcl/metaact.hxx> +#include <vcl/metric.hxx> +#include <rtl/tencinfo.h> + +// ------------------------------------------------------------------------ + +#define WIN_MTF_MAX_POLYPOLYCOUNT 16 + +void WinMtfClipPath::ImpUpdateType() +{ + if ( !aPolyPoly.Count() ) + eType = EMPTY; + else if ( aPolyPoly.IsRect() ) + eType = RECTANGLE; + else + eType = COMPLEX; + + bNeedsUpdate = sal_True; +} + +void WinMtfClipPath::IntersectClipRect( const Rectangle& rRect ) +{ + if ( !aPolyPoly.Count() ) + aPolyPoly = Polygon( rRect ); + else if ( aPolyPoly.Count() < WIN_MTF_MAX_POLYPOLYCOUNT ) + { + Polygon aPolygon( rRect ); + PolyPolygon aIntersection; + PolyPolygon aPolyPolyRect( aPolygon ); + aPolyPoly.GetIntersection( aPolyPolyRect, aIntersection ); + aPolyPoly = aIntersection; + } + ImpUpdateType(); +} + +void WinMtfClipPath::ExcludeClipRect( const Rectangle& rRect ) +{ + if ( aPolyPoly.Count() && ( aPolyPoly.Count() < WIN_MTF_MAX_POLYPOLYCOUNT ) ) + { + Polygon aPolygon( rRect ); + PolyPolygon aPolyPolyRect( aPolygon ); + PolyPolygon aDifference; + aPolyPoly.GetDifference( aPolyPolyRect, aDifference ); + aPolyPoly = aDifference; + } + ImpUpdateType(); +} + +void WinMtfClipPath::SetClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode ) +{ + if ( !rPolyPolygon.Count() ) + aPolyPoly = rPolyPolygon; + else if ( rPolyPolygon.Count() < WIN_MTF_MAX_POLYPOLYCOUNT ) + { + PolyPolygon aNewClipPath; + + // #115345# Watch out for empty aPolyPoly here - conceptually, + // an empty clip path is a rectangle of infinite size, but it + // is represented by an empty aPolyPoly. When intersecting + // rPolyPolygon with this _empty_ aPolyPoly, set algebra + // guarantees wrong results. + switch ( nClippingMode ) + { + case RGN_OR : + // #115345# clip stays empty, when ORing an arbitrary + // rPolyPolygon. Thus, we can save us the unnecessary + // clipper call. + if( aPolyPoly.Count() ) + aPolyPoly.GetUnion( rPolyPolygon, aNewClipPath ); + break; + case RGN_XOR : + // TODO: + // #115345# Cannot handle this case, for the time being + aPolyPoly.GetXOR( rPolyPolygon, aNewClipPath ); + break; + case RGN_DIFF : + // TODO: + // #115345# Cannot handle this case, for the time being + aPolyPoly.GetDifference( rPolyPolygon, aNewClipPath ); + break; + case RGN_AND : + // #115345# Clip becomes rPolyPolygon, when ANDing + // with an arbitrary rPolyPolygon + if( aPolyPoly.Count() ) + aPolyPoly.GetIntersection( rPolyPolygon, aNewClipPath ); + else + aNewClipPath = rPolyPolygon; + break; + case RGN_COPY : + aNewClipPath = rPolyPolygon; + break; + } + aPolyPoly = aNewClipPath; + } + ImpUpdateType(); +} + +void WinMtfClipPath::MoveClipRegion( const Size& rSize ) +{ + aPolyPoly.Move( rSize.Width(), rSize.Height() ); + bNeedsUpdate = sal_True; +} + +// ------------------------------------------------------------------------ + +void WinMtfPathObj::AddPoint( const Point& rPoint ) +{ + if ( bClosed ) + Insert( Polygon(), POLYPOLY_APPEND ); + Polygon& rPoly = ((PolyPolygon&)*this)[ Count() - 1 ]; + rPoly.Insert( rPoly.GetSize(), rPoint, POLY_NORMAL ); + bClosed = sal_False; +} + +void WinMtfPathObj::AddPolyLine( const Polygon& rPolyLine ) +{ + if ( bClosed ) + Insert( Polygon(), POLYPOLY_APPEND ); + Polygon& rPoly = ((PolyPolygon&)*this)[ Count() - 1 ]; + rPoly.Insert( rPoly.GetSize(), rPolyLine ); + bClosed = sal_False; +} + +void WinMtfPathObj::AddPolygon( const Polygon& rPoly ) +{ + Insert( rPoly, POLYPOLY_APPEND ); + bClosed = sal_True; +} + +void WinMtfPathObj::AddPolyPolygon( const PolyPolygon& rPolyPoly ) +{ + sal_uInt16 i, nCount = rPolyPoly.Count(); + for ( i = 0; i < nCount; i++ ) + Insert( rPolyPoly[ i ], POLYPOLY_APPEND ); + bClosed = sal_True; +} + +void WinMtfPathObj::ClosePath() +{ + if ( Count() ) + { + Polygon& rPoly = ((PolyPolygon&)*this)[ Count() - 1 ]; + if ( rPoly.GetSize() > 2 ) + { + Point aFirst( rPoly[ 0 ] ); + if ( aFirst != rPoly[ rPoly.GetSize() - 1 ] ) + rPoly.Insert( rPoly.GetSize(), aFirst, POLY_NORMAL ); + } + } + bClosed = sal_True; +} + +// ------------------------------------------------------------------------ + +WinMtfFontStyle::WinMtfFontStyle( LOGFONTW& rFont ) +{ + CharSet eCharSet; + if ( ( rFont.lfCharSet == OEM_CHARSET ) || ( rFont.lfCharSet == DEFAULT_CHARSET ) ) + eCharSet = gsl_getSystemTextEncoding(); + else + eCharSet = rtl_getTextEncodingFromWindowsCharset( rFont.lfCharSet ); + if ( eCharSet == RTL_TEXTENCODING_DONTKNOW ) + eCharSet = gsl_getSystemTextEncoding(); + aFont.SetCharSet( eCharSet ); + aFont.SetName( rFont.alfFaceName ); + FontFamily eFamily; + switch ( rFont.lfPitchAndFamily & 0xf0 ) + { + case FF_ROMAN: + eFamily = FAMILY_ROMAN; + break; + + case FF_SWISS: + eFamily = FAMILY_SWISS; + break; + + case FF_MODERN: + eFamily = FAMILY_MODERN; + break; + + case FF_SCRIPT: + eFamily = FAMILY_SCRIPT; + break; + + case FF_DECORATIVE: + eFamily = FAMILY_DECORATIVE; + break; + + default: + eFamily = FAMILY_DONTKNOW; + break; + } + aFont.SetFamily( eFamily ); + + FontPitch ePitch; + switch ( rFont.lfPitchAndFamily & 0x0f ) + { + case FIXED_PITCH: + ePitch = PITCH_FIXED; + break; + + case DEFAULT_PITCH: + case VARIABLE_PITCH: + default: + ePitch = PITCH_VARIABLE; + break; + } + aFont.SetPitch( ePitch ); + + FontWeight eWeight; + if( rFont.lfWeight <= FW_THIN ) + eWeight = WEIGHT_THIN; + else if( rFont.lfWeight <= FW_ULTRALIGHT ) + eWeight = WEIGHT_ULTRALIGHT; + else if( rFont.lfWeight <= FW_LIGHT ) + eWeight = WEIGHT_LIGHT; + else if( rFont.lfWeight < FW_MEDIUM ) + eWeight = WEIGHT_NORMAL; + else if( rFont.lfWeight == FW_MEDIUM ) + eWeight = WEIGHT_MEDIUM; + else if( rFont.lfWeight <= FW_SEMIBOLD ) + eWeight = WEIGHT_SEMIBOLD; + else if( rFont.lfWeight <= FW_BOLD ) + eWeight = WEIGHT_BOLD; + else if( rFont.lfWeight <= FW_ULTRABOLD ) + eWeight = WEIGHT_ULTRABOLD; + else + eWeight = WEIGHT_BLACK; + aFont.SetWeight( eWeight ); + + if( rFont.lfItalic ) + aFont.SetItalic( ITALIC_NORMAL ); + + if( rFont.lfUnderline ) + aFont.SetUnderline( UNDERLINE_SINGLE ); + + if( rFont.lfStrikeOut ) + aFont.SetStrikeout( STRIKEOUT_SINGLE ); + + if ( rFont.lfOrientation ) + aFont.SetOrientation( (short)rFont.lfOrientation ); + else + aFont.SetOrientation( (short)rFont.lfEscapement ); + + Size aFontSize( Size( rFont.lfWidth, rFont.lfHeight ) ); + if ( rFont.lfHeight > 0 ) + { + // converting the cell height into a font height + VirtualDevice aVDev; + aFont.SetSize( aFontSize ); + aVDev.SetFont( aFont ); + FontMetric aMetric( aVDev.GetFontMetric() ); + long nHeight = aMetric.GetAscent() + aMetric.GetDescent(); + if ( nHeight ) + { + double fHeight = ((double)aFontSize.Height() * rFont.lfHeight ) / nHeight; + aFontSize.Height() = (sal_Int32)( fHeight + 0.5 ); + } + } + else if ( aFontSize.Height() < 0 ) + aFontSize.Height() *= -1; + + if ( !rFont.lfWidth ) + { + VirtualDevice aVDev; + aFont.SetSize( aFontSize ); + aVDev.SetFont( aFont ); + FontMetric aMetric( aVDev.GetFontMetric() ); + aFontSize.Width() = aMetric.GetWidth(); + } + + aFont.SetSize( aFontSize ); +}; + +// ------------------------------------------------------------------------ + +#ifdef WIN_MTF_ASSERT +void WinMtfAssertHandler( const sal_Char* pAction, sal_uInt32 nFlags ) +{ + static sal_Bool bOnlyOnce; + static sal_Int32 nAssertCount; + + if ( nFlags & WIN_MTF_ASSERT_INIT ) + nAssertCount = 0; + if ( nFlags & WIN_MTF_ASSERT_ONCE ) + bOnlyOnce = sal_True; + if ( nFlags & WIN_MTF_ASSERT_MIFE ) + { + if ( ( nAssertCount == 0 ) || ( bOnlyOnce == sal_False ) ) + { + ByteString aText( "WMF/EMF Import: " ); + if ( pAction ) + { + ByteString aAction( pAction ); + aText.Append( aAction ); + } + aText.Append( " needs to be implemented (SJ)" ); + DBG_ASSERT( 0, aText.GetBuffer() ); + } + nAssertCount++; + } +} +#endif + +// ------------------------------------------------------------------------ + +WinMtf::WinMtf( WinMtfOutput* pWinMtfOutput, SvStream& rStreamWMF, FilterConfigItem* pConfigItem ) : + pOut ( pWinMtfOutput ), + pWMF ( &rStreamWMF ), + pFilterConfigItem ( pConfigItem ) +{ +#ifdef WIN_MTF_ASSERT + // we want to assert not implemented features, but we do this + // only once, so that nobody is handicaped by getting too much assertions + // I hope this will bring more testdocuments, without support of these + // testdocuments the implementation of missing features won't be possible. (SJ) + WinMtfAssertHandler( NULL, WIN_MTF_ASSERT_INIT | WIN_MTF_ASSERT_ONCE ); +#endif + + SvLockBytes *pLB = pWMF->GetLockBytes(); + if ( pLB ) + pLB->SetSynchronMode( TRUE ); + + nStartPos = pWMF->Tell(); + + pOut->SetDevOrg( Point() ); + if ( pFilterConfigItem ) + { + xStatusIndicator = pFilterConfigItem->GetStatusIndicator(); + if ( xStatusIndicator.is() ) + { + rtl::OUString aMsg; + xStatusIndicator->start( aMsg, 100 ); + } + } +} + +// ------------------------------------------------------------------------ + +WinMtf::~WinMtf() +{ + delete pOut; + + if ( xStatusIndicator.is() ) + xStatusIndicator->end(); +} + +// ------------------------------------------------------------------------ + +void WinMtf::Callback( USHORT nPercent ) +{ + if ( xStatusIndicator.is() ) + xStatusIndicator->setValue( nPercent ); +} + +// ------------------------------------------------------------------------ + +Color WinMtf::ReadColor() +{ + UINT32 nColor; + *pWMF >> nColor; + return Color( (BYTE)nColor, (BYTE)( nColor >> 8 ), (BYTE)( nColor >> 16 ) ); +}; + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +Point WinMtfOutput::ImplMap( const Point& rPt ) +{ + if ( mnWinExtX && mnWinExtY ) + { + double fX2, fX = rPt.X(); + double fY2, fY = rPt.Y(); + + fX2 = fX * maXForm.eM11 + fY * maXForm.eM21 + maXForm.eDx; + fY2 = fX * maXForm.eM12 + fY * maXForm.eM22 + maXForm.eDy; + + if ( mnGfxMode == GM_COMPATIBLE ) + { + switch( mnMapMode ) + { + case MM_LOENGLISH : + { + fX2 -= mnWinOrgX; + fY2 = mnWinOrgY-fY2; + fX2 *= 25.40; + fY2 *= 25.40; + fX2 += mnDevOrgX; + fY2 += mnDevOrgY; + } + break; + case MM_HIENGLISH : + { + fX2 -= mnWinOrgX; + fY2 = mnWinOrgY-fY2; + fX2 *= 2.540; + fY2 *= 2.540; + fX2 += mnDevOrgX; + fY2 += mnDevOrgY; + } + break; + case MM_LOMETRIC : + { + fX2 -= mnWinOrgX; + fY2 = mnWinOrgY-fY2; + fX2 *= 10; + fY2 *= 10; + fX2 += mnDevOrgX; + fY2 += mnDevOrgY; + } + break; + case MM_HIMETRIC : + { + fX2 -= mnWinOrgX; + fY2 = mnWinOrgY-fY2; + fX2 += mnDevOrgX; + fY2 += mnDevOrgY; + } + break; + default : + { + fX2 -= mnWinOrgX; + fY2 -= mnWinOrgY; + fX2 /= mnWinExtX; + fY2 /= mnWinExtY; + fX2 *= mnDevWidth; + fY2 *= mnDevHeight; + fX2 += mnDevOrgX; + fY2 += mnDevOrgY; // fX2, fY2 now in device units + fX2 *= (double)mnMillX * 100.0 / (double)mnPixX; + fY2 *= (double)mnMillY * 100.0 / (double)mnPixY; + } + break; + } + fX2 -= mrclFrame.Left(); + fY2 -= mrclFrame.Top(); + } + return Point( FRound( fX2 ), FRound( fY2 ) ); + } + else + return Point(); +}; + +// ------------------------------------------------------------------------ + +Size WinMtfOutput::ImplMap( const Size& rSz ) +{ + if ( mnWinExtX && mnWinExtY ) + { + double fWidth = rSz.Width() * maXForm.eM11; + double fHeight = rSz.Height() * maXForm.eM22; + + if ( mnGfxMode == GM_COMPATIBLE ) + { + switch( mnMapMode ) + { + case MM_LOENGLISH : + { + fWidth *= 25.40; + fHeight*=-25.40; + } + break; + case MM_HIENGLISH : + { + fWidth *= 2.540; + fHeight*=-2.540; + } + break; + case MM_LOMETRIC : + { + fWidth *= 10; + fHeight*=-10; + } + break; + case MM_HIMETRIC : + { + fHeight *= -1; + } + break; + default : + { + fWidth /= mnWinExtX; + fHeight /= mnWinExtY; + fWidth *= mnDevWidth; + fHeight *= mnDevHeight; + fWidth *= (double)mnMillX * 100 / (double)mnPixX; + fHeight *= (double)mnMillY * 100 / (double)mnPixY; + } + break; + } + } + return Size( FRound( fWidth ), FRound( fHeight ) ); + } + else + return Size(); +} + +//----------------------------------------------------------------------------------- + +Rectangle WinMtfOutput::ImplMap( const Rectangle& rRect ) +{ + return Rectangle( ImplMap( rRect.TopLeft() ), ImplMap( rRect.GetSize() ) ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ImplMap( Font& rFont ) +{ + // !!! HACK: Wir setzen die Breite jetzt immer auf Null, + // da OS die Breite unterschiedlich interpretieren; + // muss spaeter in SV portabel gemacht werden ( KA 08.02.96 ) + Size aFontSize = ImplMap ( rFont.GetSize() ); + + if( aFontSize.Height() < 0 ) + aFontSize.Height() *= -1; + + rFont.SetSize( aFontSize ); + + if( ( mnWinExtX * mnWinExtY ) < 0 ) + rFont.SetOrientation( 3600 - rFont.GetOrientation() ); +} + +//----------------------------------------------------------------------------------- + +Polygon& WinMtfOutput::ImplMap( Polygon& rPolygon ) +{ + UINT16 nPoints = rPolygon.GetSize(); + for ( UINT16 i = 0; i < nPoints; i++ ) + { + rPolygon[ i ] = ImplMap( rPolygon[ i ] ); + } + return rPolygon; +} + +//----------------------------------------------------------------------------------- + +PolyPolygon& WinMtfOutput::ImplMap( PolyPolygon& rPolyPolygon ) +{ + UINT16 nPolys = rPolyPolygon.Count(); + for ( UINT16 i = 0; i < nPolys; ImplMap( rPolyPolygon[ i++ ] ) ) ; + return rPolyPolygon; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SelectObject( INT32 nIndex ) +{ + GDIObj* pGDIObj = NULL; + + if ( nIndex & ENHMETA_STOCK_OBJECT ) + pGDIObj = new GDIObj(); + else + { + nIndex &= 0xffff; // zur Sicherheit: mehr als 65535 nicht zulassen + + if ( (UINT32)nIndex < vGDIObj.size() ) + pGDIObj = vGDIObj[ nIndex ]; + } + + if( pGDIObj == NULL ) + return; + + if ( nIndex & ENHMETA_STOCK_OBJECT ) + { + UINT16 nStockId = (BYTE)nIndex; + switch( nStockId ) + { + case WHITE_BRUSH : + { + pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ) ) ); + } + break; + case LTGRAY_BRUSH : + { + pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_LIGHTGRAY ) ) ); + } + break; + case GRAY_BRUSH : + case DKGRAY_BRUSH : + { + pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_GRAY ) ) ); + } + break; + case BLACK_BRUSH : + { + pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_BLACK ) ) ); + } + break; + case NULL_BRUSH : + { + pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_TRANSPARENT ), TRUE ) ); + } + break; + case WHITE_PEN : + { + pGDIObj->Set( GDI_PEN, new WinMtfLineStyle( Color( COL_WHITE ) ) ); + } + break; + case BLACK_PEN : + { + pGDIObj->Set( GDI_PEN, new WinMtfLineStyle( Color( COL_BLACK ) ) ); + } + break; + case NULL_PEN : + { + pGDIObj->Set( GDI_PEN, new WinMtfLineStyle( Color( COL_TRANSPARENT ), TRUE ) ); + } + break; + default: + break; + } + } + if ( pGDIObj->pStyle ) + { + switch( pGDIObj->eType ) + { + case GDI_PEN : + maLineStyle = (WinMtfLineStyle*)pGDIObj->pStyle; + break; + case GDI_BRUSH : + { + maFillStyle = (WinMtfFillStyle*)pGDIObj->pStyle; + mbFillStyleSelected = sal_True; + } + break; + case GDI_FONT : + maFont = ((WinMtfFontStyle*)pGDIObj->pStyle)->aFont; + break; + default: + break; // -Wall many options not handled. + } + } + if ( nIndex & ENHMETA_STOCK_OBJECT ) + delete pGDIObj; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetFont( const Font& rFont ) +{ + maFont = rFont; +} + +//----------------------------------------------------------------------------------- + +const Font& WinMtfOutput::GetFont() const +{ + return maFont; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetTextLayoutMode( const sal_uInt32 nTextLayoutMode ) +{ + mnTextLayoutMode = nTextLayoutMode; +} + +//----------------------------------------------------------------------------------- + +sal_uInt32 WinMtfOutput::GetTextLayoutMode() const +{ + return mnTextLayoutMode; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetBkMode( UINT32 nMode ) +{ + mnBkMode = nMode; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetBkColor( const Color& rColor ) +{ + maBkColor = rColor; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetTextColor( const Color& rColor ) +{ + maTextColor = rColor; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetTextAlign( UINT32 nAlign ) +{ + mnTextAlign = nAlign; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ImplResizeObjectArry( UINT32 nNewEntrys ) +{ + sal_uInt32 i = vGDIObj.size(); + vGDIObj.resize( nNewEntrys ); + for ( ; i < nNewEntrys ; i++ ) + vGDIObj[ i ] = NULL; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ImplDrawClippedPolyPolygon( const PolyPolygon& rPolyPoly ) +{ + if ( rPolyPoly.Count() ) + { + ImplSetNonPersistentLineColorTransparenz(); + if ( rPolyPoly.Count() == 1 ) + { + if ( rPolyPoly.IsRect() ) + mpGDIMetaFile->AddAction( new MetaRectAction( rPolyPoly.GetBoundRect() ) ); + else + { + Polygon aPoly( rPolyPoly[ 0 ] ); + sal_uInt16 nCount = aPoly.GetSize(); + if ( nCount ) + { + if ( aPoly[ nCount - 1 ] != aPoly[ 0 ] ) + { + Point aPoint( aPoly[ 0 ] ); + aPoly.Insert( nCount, aPoint ); + } + mpGDIMetaFile->AddAction( new MetaPolygonAction( aPoly ) ); + } + } + } + else + mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPoly ) ); + } +} + + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::CreateObject( GDIObjectType eType, void* pStyle ) +{ + if ( pStyle ) + { + if ( eType == GDI_FONT ) + { + ImplMap( ((WinMtfFontStyle*)pStyle)->aFont ); + if (!((WinMtfFontStyle*)pStyle)->aFont.GetHeight() ) + ((WinMtfFontStyle*)pStyle)->aFont.SetHeight( 423 ); // defaulting to 12pt + } + else if ( eType == GDI_PEN ) + { + Size aSize( ((WinMtfLineStyle*)pStyle)->aLineInfo.GetWidth(), 0 ); + ((WinMtfLineStyle*)pStyle)->aLineInfo.SetWidth( ImplMap( aSize ).Width() ); + if ( ((WinMtfLineStyle*)pStyle)->aLineInfo.GetStyle() == LINE_DASH ) + { + aSize.Width() += 1; + long nDotLen = ImplMap( aSize ).Width(); + ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDistance( nDotLen ); + ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDotLen( nDotLen ); + ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDashLen( nDotLen * 4 ); + } + } + } + UINT32 nIndex; + for ( nIndex = 0; nIndex < vGDIObj.size(); nIndex++ ) + { + if ( vGDIObj[ nIndex ] == NULL ) + break; + } + if ( nIndex == vGDIObj.size() ) + ImplResizeObjectArry( vGDIObj.size() + 16 ); + + vGDIObj[ nIndex ] = new GDIObj( eType, pStyle ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::CreateObject( INT32 nIndex, GDIObjectType eType, void* pStyle ) +{ + if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) + { + nIndex &= 0xffff; // zur Sicherheit: mehr als 65535 nicht zulassen + if ( pStyle ) + { + if ( eType == GDI_FONT ) + ImplMap( ((WinMtfFontStyle*)pStyle)->aFont ); + else if ( eType == GDI_PEN ) + { + Size aSize( ((WinMtfLineStyle*)pStyle)->aLineInfo.GetWidth(), 0 ); + ((WinMtfLineStyle*)pStyle)->aLineInfo.SetWidth( ImplMap( aSize ).Width() ); + if ( ((WinMtfLineStyle*)pStyle)->aLineInfo.GetStyle() == LINE_DASH ) + { + aSize.Width() += 1; + long nDotLen = ImplMap( aSize ).Width(); + ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDistance( nDotLen ); + ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDotLen( nDotLen ); + ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDashLen( nDotLen * 4 ); + } + } + } + if ( (UINT32)nIndex >= vGDIObj.size() ) + ImplResizeObjectArry( nIndex + 16 ); + + if ( vGDIObj[ nIndex ] != NULL ) + delete vGDIObj[ nIndex ]; + + vGDIObj[ nIndex ] = new GDIObj( eType, pStyle ); + } + else + { + switch ( eType ) + { + case GDI_PEN : + delete (WinMtfLineStyle*)pStyle; + break; + case GDI_BRUSH : + delete (WinMtfFillStyle*)pStyle; + break; + case GDI_FONT : + delete (WinMtfFontStyle*)pStyle; + break; + + default: + DBG_ERROR( "unsupported style not deleted" ); + break; + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DeleteObject( sal_Int32 nIndex ) +{ + if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) + { + if ( (sal_uInt32)nIndex < vGDIObj.size() ) + { + delete vGDIObj[ nIndex ]; + vGDIObj[ nIndex ] = NULL; + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::IntersectClipRect( const Rectangle& rRect ) +{ + aClipPath.IntersectClipRect( ImplMap( rRect ) ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ExcludeClipRect( const Rectangle& rRect ) +{ + aClipPath.ExcludeClipRect( ImplMap( rRect ) ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::MoveClipRegion( const Size& rSize ) +{ + aClipPath.MoveClipRegion( ImplMap( rSize ) ); +} + +void WinMtfOutput::SetClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode, sal_Bool bIsMapped ) +{ + if ( bIsMapped ) + aClipPath.SetClipPath( rPolyPolygon, nClippingMode ); + else + { + PolyPolygon aPP( rPolyPolygon ); + aClipPath.SetClipPath( ImplMap( aPP ), nClippingMode ); + } +} + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +WinMtfOutput::WinMtfOutput( GDIMetaFile& rGDIMetaFile ) : + mnLatestTextAlign ( 0 ), + mnTextAlign ( TA_LEFT | TA_TOP | TA_NOUPDATECP ), + maLatestBkColor ( 0x12345678 ), + maBkColor ( COL_WHITE ), + mnLatestTextLayoutMode( TEXT_LAYOUT_DEFAULT ), + mnTextLayoutMode ( TEXT_LAYOUT_DEFAULT ), + mnLatestBkMode ( 0 ), + mnBkMode ( OPAQUE ), + meLatestRasterOp ( ROP_INVERT ), + meRasterOp ( ROP_OVERPAINT ), + maActPos ( Point() ), + mbNopMode ( sal_False ), + mbFillStyleSelected ( sal_False ), + mnGfxMode ( GM_COMPATIBLE ), + mnMapMode ( MM_TEXT ), + mnDevOrgX ( 0 ), + mnDevOrgY ( 0 ), + mnDevWidth ( 1 ), + mnDevHeight ( 1 ), + mnWinOrgX ( 0 ), + mnWinOrgY ( 0 ), + mnWinExtX ( 1 ), + mnWinExtY ( 1 ), + mnPixX ( 100 ), + mnPixY ( 100 ), + mnMillX ( 1 ), + mnMillY ( 1 ), + mpGDIMetaFile ( &rGDIMetaFile ) +{ + mpGDIMetaFile->AddAction( new MetaPushAction( PUSH_CLIPREGION ) ); // The original clipregion has to be on top + // of the stack so it can always be restored + // this is necessary to be able to support + // SetClipRgn( NULL ) and similar ClipRgn actions (SJ) + + maFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "Arial" )) ); // sj: #i57205#, we do have some scaling problems if using + maFont.SetCharSet( gsl_getSystemTextEncoding() ); // the default font then most times a x11 font is used, we + maFont.SetHeight( 423 ); // will prevent this defining a font + + maLatestLineStyle.aLineColor = Color( 0x12, 0x34, 0x56 ); + maLatestFillStyle.aFillColor = Color( 0x12, 0x34, 0x56 ); + + mnRop = R2_BLACK + 1; + SetRasterOp( R2_BLACK ); +}; + +//----------------------------------------------------------------------------------- + +WinMtfOutput::~WinMtfOutput() +{ + mpGDIMetaFile->AddAction( new MetaPopAction() ); + mpGDIMetaFile->SetPrefMapMode( MAP_100TH_MM ); + if ( mrclFrame.IsEmpty() ) + mpGDIMetaFile->SetPrefSize( Size( mnDevWidth, mnDevHeight ) ); + else + mpGDIMetaFile->SetPrefSize( mrclFrame.GetSize() ); + + for ( UINT32 i = 0; i < vGDIObj.size(); i++ ) + delete vGDIObj[ i ]; +}; + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::UpdateClipRegion() +{ + if ( aClipPath.bNeedsUpdate ) + { + aClipPath.bNeedsUpdate = sal_False; + + mpGDIMetaFile->AddAction( new MetaPopAction() ); // taking the orignal clipregion + mpGDIMetaFile->AddAction( new MetaPushAction( PUSH_CLIPREGION ) ); // + + switch ( aClipPath.GetType() ) + { + case RECTANGLE : + case COMPLEX : + { +// we will not generate a RegionClipRegion Action, because this action +// cannot be saved to the wmf format - saving to wmf always happens +// if the placeholder graphic for ole objects is generated. (SJ) + +// Region aClipRegion( aClipPath.GetClipPath() ); +// mpGDIMetaFile->AddAction( new MetaISectRegionClipRegionAction( aClipRegion ) ); + + Rectangle aClipRect( aClipPath.GetClipPath().GetBoundRect() ); + mpGDIMetaFile->AddAction( new MetaISectRectClipRegionAction( aClipRect ) ); + } + break; + case EMPTY: + break; // -Wall not handled. + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ImplSetNonPersistentLineColorTransparenz() +{ + Color aColor( COL_TRANSPARENT); + WinMtfLineStyle aTransparentLine( aColor, TRUE ); + if ( ! ( maLatestLineStyle == aTransparentLine ) ) + { + maLatestLineStyle = aTransparentLine; + mpGDIMetaFile->AddAction( new MetaLineColorAction( aTransparentLine.aLineColor, !aTransparentLine.bTransparent ) ); + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::UpdateLineStyle() +{ + if (!( maLatestLineStyle == maLineStyle ) ) + { + maLatestLineStyle = maLineStyle; + mpGDIMetaFile->AddAction( new MetaLineColorAction( maLineStyle.aLineColor, !maLineStyle.bTransparent ) ); + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::UpdateFillStyle() +{ + if ( !mbFillStyleSelected ) // SJ: #i57205# taking care of bkcolor if no brush is selected + maFillStyle = WinMtfFillStyle( maBkColor, mnBkMode == TRANSPARENT ); + if (!( maLatestFillStyle == maFillStyle ) ) + { + maLatestFillStyle = maFillStyle; + mpGDIMetaFile->AddAction( new MetaFillColorAction( maFillStyle.aFillColor, !maFillStyle.bTransparent ) ); + } +} + +//----------------------------------------------------------------------------------- + +sal_uInt32 WinMtfOutput::SetRasterOp( UINT32 nRasterOp ) +{ + sal_uInt32 nRetROP = mnRop; + if ( nRasterOp != mnRop ) + { + mnRop = nRasterOp; + static WinMtfFillStyle aNopFillStyle; + static WinMtfLineStyle aNopLineStyle; + + if ( mbNopMode && ( nRasterOp != R2_NOP ) ) + { // beim uebergang von R2_NOP auf anderen Modus + // gesetzten Pen und Brush aktivieren + maFillStyle = aNopFillStyle; + maLineStyle = aNopLineStyle; + mbNopMode = sal_False; + } + switch( nRasterOp ) + { + case R2_NOT: + meRasterOp = ROP_INVERT; + break; + + case R2_XORPEN: + meRasterOp = ROP_XOR; + break; + + case R2_NOP: + { + meRasterOp = ROP_OVERPAINT; + if( mbNopMode == sal_False ) + { + aNopFillStyle = maFillStyle; + aNopLineStyle = maLineStyle; + maFillStyle = WinMtfFillStyle( Color( COL_TRANSPARENT ), TRUE ); + maLineStyle = WinMtfLineStyle( Color( COL_TRANSPARENT ), TRUE ); + mbNopMode = sal_True; + } + } + break; + + default: + meRasterOp = ROP_OVERPAINT; + break; + } + } + if ( nRetROP != nRasterOp ) + mpGDIMetaFile->AddAction( new MetaRasterOpAction( meRasterOp ) ); + return nRetROP; +}; + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::StrokeAndFillPath( sal_Bool bStroke, sal_Bool bFill ) +{ + if ( aPathObj.Count() ) + { + UpdateClipRegion(); + UpdateLineStyle(); + UpdateFillStyle(); + if ( bFill ) + { + if ( !bStroke ) + { + mpGDIMetaFile->AddAction( new MetaPushAction( PUSH_LINECOLOR ) ); + mpGDIMetaFile->AddAction( new MetaLineColorAction( Color(), FALSE ) ); + } + if ( aPathObj.Count() == 1 ) + mpGDIMetaFile->AddAction( new MetaPolygonAction( aPathObj.GetObject( 0 ) ) ); + else + mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( aPathObj ) ); + + if ( !bStroke ) + mpGDIMetaFile->AddAction( new MetaPopAction() ); + } + else + { + sal_uInt16 i, nCount = aPathObj.Count(); + for ( i = 0; i < nCount; i++ ) + mpGDIMetaFile->AddAction( new MetaPolyLineAction( aPathObj[ i ], maLineStyle.aLineInfo ) ); + } + ClearPath(); + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawPixel( const Point& rSource, const Color& rColor ) +{ + mpGDIMetaFile->AddAction( new MetaPixelAction( ImplMap( rSource), rColor ) ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::MoveTo( const Point& rPoint, sal_Bool bRecordPath ) +{ + Point aDest( ImplMap( rPoint ) ); + if ( bRecordPath ) + aPathObj.AddPoint( aDest ); + maActPos = aDest; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::LineTo( const Point& rPoint, sal_Bool bRecordPath ) +{ + UpdateClipRegion(); + + Point aDest( ImplMap( rPoint ) ); + if ( bRecordPath ) + aPathObj.AddPoint( aDest ); + else + { + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaLineAction( maActPos, aDest, maLineStyle.aLineInfo ) ); + } + maActPos = aDest; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawLine( const Point& rSource, const Point& rDest ) +{ + UpdateClipRegion(); + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaLineAction( ImplMap( rSource), ImplMap( rDest ), maLineStyle.aLineInfo ) ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawRect( const Rectangle& rRect, BOOL bEdge ) +{ + UpdateClipRegion(); + UpdateFillStyle(); + + if ( aClipPath.GetType() == COMPLEX ) + { + Polygon aPoly( ImplMap( rRect ) ); + PolyPolygon aPolyPolyRect( aPoly ); + PolyPolygon aDest; + aClipPath.GetClipPath().GetIntersection( aPolyPolyRect, aDest ); + ImplDrawClippedPolyPolygon( aDest ); + } + else + { + if ( bEdge ) + { + if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) ) + { + ImplSetNonPersistentLineColorTransparenz(); + mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) ); + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( ImplMap( rRect ) ),maLineStyle.aLineInfo ) ); + } + else + { + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) ); + } + } + else + { + ImplSetNonPersistentLineColorTransparenz(); + mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) ); + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawRoundRect( const Rectangle& rRect, const Size& rSize ) +{ + UpdateClipRegion(); + UpdateLineStyle(); + UpdateFillStyle(); + mpGDIMetaFile->AddAction( new MetaRoundRectAction( ImplMap( rRect ), labs( ImplMap( rSize ).Width() ), labs( ImplMap( rSize ).Height() ) ) ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawEllipse( const Rectangle& rRect ) +{ + UpdateClipRegion(); + UpdateFillStyle(); + + if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) ) + { + Point aCenter( ImplMap( rRect.Center() ) ); + Size aRad( ImplMap( Size( rRect.GetWidth() / 2, rRect.GetHeight() / 2 ) ) ); + + ImplSetNonPersistentLineColorTransparenz(); + mpGDIMetaFile->AddAction( new MetaEllipseAction( ImplMap( rRect ) ) ); + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aCenter, aRad.Width(), aRad.Height() ), maLineStyle.aLineInfo ) ); + } + else + { + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaEllipseAction( ImplMap( rRect ) ) ); + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawArc( const Rectangle& rRect, const Point& rStart, const Point& rEnd, BOOL bTo ) +{ + UpdateClipRegion(); + UpdateLineStyle(); + UpdateFillStyle(); + + Rectangle aRect( ImplMap( rRect ) ); + Point aStart( ImplMap( rStart ) ); + Point aEnd( ImplMap( rEnd ) ); + + if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) ) + { + if ( aStart == aEnd ) + { // SJ: #i53768# if start & end is identical, then we have to draw a full ellipse + Point aCenter( aRect.Center() ); + Size aRad( aRect.GetWidth() / 2, aRect.GetHeight() / 2 ); + + mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aCenter, aRad.Width(), aRad.Height() ), maLineStyle.aLineInfo ) ); + } + else + mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aRect, aStart, aEnd, POLY_ARC ), maLineStyle.aLineInfo ) ); + } + else + mpGDIMetaFile->AddAction( new MetaArcAction( aRect, aStart, aEnd ) ); + + if ( bTo ) + maActPos = aEnd; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawPie( const Rectangle& rRect, const Point& rStart, const Point& rEnd ) +{ + UpdateClipRegion(); + UpdateFillStyle(); + + Rectangle aRect( ImplMap( rRect ) ); + Point aStart( ImplMap( rStart ) ); + Point aEnd( ImplMap( rEnd ) ); + + if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) ) + { + ImplSetNonPersistentLineColorTransparenz(); + mpGDIMetaFile->AddAction( new MetaPieAction( aRect, aStart, aEnd ) ); + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aRect, aStart, aEnd, POLY_PIE ), maLineStyle.aLineInfo ) ); + } + else + { + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPieAction( aRect, aStart, aEnd ) ); + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawChord( const Rectangle& rRect, const Point& rStart, const Point& rEnd ) +{ + UpdateClipRegion(); + UpdateFillStyle(); + + Rectangle aRect( ImplMap( rRect ) ); + Point aStart( ImplMap( rStart ) ); + Point aEnd( ImplMap( rEnd ) ); + + if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) ) + { + ImplSetNonPersistentLineColorTransparenz(); + mpGDIMetaFile->AddAction( new MetaChordAction( aRect, aStart, aEnd ) ); + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aRect, aStart, aEnd, POLY_CHORD ), maLineStyle.aLineInfo ) ); + } + else + { + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaChordAction( aRect, aStart, aEnd ) ); + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawPolygon( Polygon& rPolygon, sal_Bool bRecordPath ) +{ + UpdateClipRegion(); + ImplMap( rPolygon ); + if ( bRecordPath ) + aPathObj.AddPolygon( rPolygon ); + else + { + UpdateFillStyle(); + + if ( aClipPath.GetType() == COMPLEX ) + { + PolyPolygon aPolyPoly( rPolygon ); + PolyPolygon aDest; + aClipPath.GetClipPath().GetIntersection( aPolyPoly, aDest ); + ImplDrawClippedPolyPolygon( aDest ); + } + else + { + if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) ) + { + USHORT nCount = rPolygon.GetSize(); + if ( nCount ) + { + if ( rPolygon[ nCount - 1 ] != rPolygon[ 0 ] ) + { + Point aPoint( rPolygon[ 0 ] ); + rPolygon.Insert( nCount, aPoint ); + } + } + ImplSetNonPersistentLineColorTransparenz(); + mpGDIMetaFile->AddAction( new MetaPolygonAction( rPolygon ) ); + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) ); + } + else + { + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPolygonAction( rPolygon ) ); + } + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawPolyPolygon( PolyPolygon& rPolyPolygon, sal_Bool bRecordPath ) +{ + UpdateClipRegion(); + + ImplMap( rPolyPolygon ); + + if ( bRecordPath ) + aPathObj.AddPolyPolygon( rPolyPolygon ); + else + { + UpdateFillStyle(); + + if ( aClipPath.GetType() == COMPLEX ) + { + PolyPolygon aDest; + aClipPath.GetClipPath().GetIntersection( rPolyPolygon, aDest ); + ImplDrawClippedPolyPolygon( aDest ); + } + else + { + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPolygon ) ); + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawPolyLine( Polygon& rPolygon, sal_Bool bTo, sal_Bool bRecordPath ) +{ + UpdateClipRegion(); + + ImplMap( rPolygon ); + if ( bTo ) + { + rPolygon[ 0 ] = maActPos; + maActPos = rPolygon[ rPolygon.GetSize() - 1 ]; + } + if ( bRecordPath ) + aPathObj.AddPolyLine( rPolygon ); + else + { + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) ); + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawPolyBezier( Polygon& rPolygon, sal_Bool bTo, sal_Bool bRecordPath ) +{ + UpdateClipRegion(); + + sal_uInt16 nPoints = rPolygon.GetSize(); + if ( ( nPoints >= 4 ) && ( ( ( nPoints - 4 ) % 3 ) == 0 ) ) + { + ImplMap( rPolygon ); + if ( bTo ) + { + rPolygon[ 0 ] = maActPos; + maActPos = rPolygon[ nPoints - 1 ]; + } + sal_uInt16 i; + for ( i = 0; ( i + 2 ) < nPoints; ) + { + rPolygon.SetFlags( i++, POLY_NORMAL ); + rPolygon.SetFlags( i++, POLY_CONTROL ); + rPolygon.SetFlags( i++, POLY_CONTROL ); + } + if ( bRecordPath ) + aPathObj.AddPolyLine( rPolygon ); + else + { + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) ); + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawText( Point& rPosition, String& rText, sal_Int32* pDXArry, sal_Bool bRecordPath, sal_Int32 nGfxMode ) +{ + UpdateClipRegion(); + + VirtualDevice* pVDev = NULL; + + rPosition = ImplMap( rPosition ); + + sal_Int32 nOldGfxMode = GetGfxMode(); + SetGfxMode( GM_COMPATIBLE ); + if ( pDXArry ) + { + sal_Int32 i, nSum, nLen = rText.Len(); + + for( i = 0, nSum = 0; i < nLen; i++ ) + { + sal_Int32 nTemp = ImplMap( Size( pDXArry[ i ], 0 ) ).Width(); + nSum += nTemp; + pDXArry[ i ] = nSum; + } + } + if ( mnLatestTextLayoutMode != mnTextLayoutMode ) + { + mnLatestTextLayoutMode = mnTextLayoutMode; + mpGDIMetaFile->AddAction( new MetaLayoutModeAction( mnTextLayoutMode ) ); + } + SetGfxMode( nGfxMode ); + sal_Bool bChangeFont = sal_False; + if ( mnLatestTextAlign != mnTextAlign ) + { + bChangeFont = sal_True; + mnLatestTextAlign = mnTextAlign; + TextAlign eTextAlign; + if ( ( mnTextAlign & TA_BASELINE) == TA_BASELINE ) + eTextAlign = ALIGN_BASELINE; + else if( ( mnTextAlign & TA_BOTTOM) == TA_BOTTOM ) + eTextAlign = ALIGN_BOTTOM; + else + eTextAlign = ALIGN_TOP; + mpGDIMetaFile->AddAction( new MetaTextAlignAction( eTextAlign ) ); + } + if ( maLatestTextColor != maTextColor ) + { + bChangeFont = sal_True; + maLatestTextColor = maTextColor; + mpGDIMetaFile->AddAction( new MetaTextColorAction( maTextColor ) ); + } + sal_Bool bChangeFillColor = sal_False; + if ( maLatestBkColor != maBkColor ) + { + bChangeFillColor = sal_True; + maLatestBkColor = maBkColor; + } + if ( mnLatestBkMode != mnBkMode ) + { + bChangeFillColor = sal_True; + mnLatestBkMode = mnBkMode; + } + if ( bChangeFillColor ) + { + bChangeFont = sal_True; + mpGDIMetaFile->AddAction( new MetaTextFillColorAction( maFont.GetFillColor(), !maFont.IsTransparent() ) ); + } + Font aTmp( maFont ); + aTmp.SetColor( maTextColor ); + aTmp.SetFillColor( maBkColor ); + + if( mnBkMode == TRANSPARENT ) + aTmp.SetTransparent( sal_True ); + else + aTmp.SetTransparent( sal_False ); + + if ( ( mnTextAlign & TA_BASELINE) == TA_BASELINE ) + aTmp.SetAlign( ALIGN_BASELINE ); + else if( ( mnTextAlign & TA_BOTTOM) == TA_BOTTOM ) + aTmp.SetAlign( ALIGN_BOTTOM ); + else + aTmp.SetAlign( ALIGN_TOP ); + + if ( nGfxMode == GM_ADVANCED ) + { + // check whether there is a font rotation applied via transformation + Point aP1( ImplMap( Point() ) ); + Point aP2( ImplMap( Point( 0, 100 ) ) ); + aP2.X() -= aP1.X(); + aP2.Y() -= aP1.Y(); + double fX = aP2.X(); + double fY = aP2.Y(); + if ( fX ) + { + double fOrientation = acos( fX / sqrt( fX * fX + fY * fY ) ) * 57.29577951308; + if ( fY > 0 ) + fOrientation = 360 - fOrientation; + fOrientation += 90; + fOrientation *= 10; + fOrientation += aTmp.GetOrientation(); + aTmp.SetOrientation( sal_Int16( fOrientation ) ); + } + } + + if( mnTextAlign & ( TA_UPDATECP | TA_RIGHT_CENTER ) ) + { + if ( !pVDev ) + pVDev = new VirtualDevice; + sal_Int32 nTextWidth; + pVDev->SetMapMode( MapMode( MAP_100TH_MM ) ); + pVDev->SetFont( maFont ); + if( pDXArry ) + { + UINT32 nLen = rText.Len(); + nTextWidth = pVDev->GetTextWidth( rText.GetChar( (sal_uInt16)( nLen - 1 ) ) ); + if( nLen > 1 ) + nTextWidth += pDXArry[ nLen - 2 ]; + } + else + nTextWidth = pVDev->GetTextWidth( rText ); + + if( mnTextAlign & TA_UPDATECP ) + rPosition = maActPos; + + if ( mnTextAlign & TA_RIGHT_CENTER ) + { + double fLenght = ( ( mnTextAlign & TA_RIGHT_CENTER ) == TA_RIGHT ) ? nTextWidth : nTextWidth >> 1; + rPosition.X() -= (sal_Int32)( fLenght * cos( maFont.GetOrientation() * F_PI1800 ) ); + rPosition.Y() -= (sal_Int32)(-( fLenght * sin( maFont.GetOrientation() * F_PI1800 ) ) ); + } + + if( mnTextAlign & TA_UPDATECP ) + maActPos.X() = rPosition.X() + nTextWidth; + } + if ( bChangeFont || ( maLatestFont != aTmp ) ) + { + maLatestFont = aTmp; + mpGDIMetaFile->AddAction( new MetaFontAction( aTmp ) ); + mpGDIMetaFile->AddAction( new MetaTextAlignAction( aTmp.GetAlign() ) ); + mpGDIMetaFile->AddAction( new MetaTextColorAction( aTmp.GetColor() ) ); + mpGDIMetaFile->AddAction( new MetaTextFillColorAction( aTmp.GetFillColor(), !aTmp.IsTransparent() ) ); + } + if ( bRecordPath ) + { + // ToDo + } + else + { + /* because text without dx array is badly scaled, we + will create such an array if necessary */ + sal_Int32* pDX = pDXArry; + if ( !pDXArry ) + { + pDX = new sal_Int32[ rText.Len() ]; + if ( !pVDev ) + pVDev = new VirtualDevice; + pVDev->SetMapMode( MAP_100TH_MM ); + pVDev->SetFont( maLatestFont ); + pVDev->GetTextArray( rText, pDX, 0, STRING_LEN ); + } + mpGDIMetaFile->AddAction( new MetaTextArrayAction( rPosition, rText, pDX, 0, STRING_LEN ) ); + if ( !pDXArry ) // this means we have created our own array + delete[] pDX; // which must be deleted + } + SetGfxMode( nOldGfxMode ); + delete pVDev; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ImplDrawBitmap( const Point& rPos, const Size& rSize, const BitmapEx rBitmap ) +{ + BitmapEx aBmpEx( rBitmap ); + if ( aClipPath.GetType() == COMPLEX ) + { + VirtualDevice aVDev; + MapMode aMapMode( MAP_100TH_MM ); + aMapMode.SetOrigin( Point( -rPos.X(), -rPos.Y() ) ); + const Size aOutputSizePixel( aVDev.LogicToPixel( rSize, aMapMode ) ); + const Size aSizePixel( rBitmap.GetSizePixel() ); + if ( aOutputSizePixel.Width() && aOutputSizePixel.Height() ) + { + aMapMode.SetScaleX( Fraction( aSizePixel.Width(), aOutputSizePixel.Width() ) ); + aMapMode.SetScaleY( Fraction( aSizePixel.Height(), aOutputSizePixel.Height() ) ); + } + aVDev.SetMapMode( aMapMode ); + aVDev.SetOutputSizePixel( aSizePixel ); + aVDev.SetFillColor( Color( COL_BLACK ) ); + const PolyPolygon aClip( aClipPath.GetClipPath() ); + aVDev.DrawPolyPolygon( aClip ); + const Point aEmptyPoint; + + // #i50672# Extract whole VDev content (to match size of rBitmap) + aVDev.EnableMapMode( FALSE ); + Bitmap aMask( aVDev.GetBitmap( aEmptyPoint, aSizePixel ).CreateMask( Color( COL_WHITE ) ) ); + + if ( aBmpEx.IsTransparent() ) + { + if ( rBitmap.GetTransparentColor() == Color( COL_WHITE ) ) + aMask.CombineSimple( rBitmap.GetMask(), BMP_COMBINE_OR ); + else + aMask.CombineSimple( rBitmap.GetMask(), BMP_COMBINE_AND ); + aBmpEx = BitmapEx( rBitmap.GetBitmap(), aMask ); + } + else + aBmpEx = BitmapEx( rBitmap.GetBitmap(), aMask ); + } + if ( aBmpEx.IsTransparent() ) + mpGDIMetaFile->AddAction( new MetaBmpExScaleAction( rPos, rSize, aBmpEx ) ); + else + mpGDIMetaFile->AddAction( new MetaBmpScaleAction( rPos, rSize, aBmpEx.GetBitmap() ) ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ResolveBitmapActions( List& rSaveList ) +{ + UpdateClipRegion(); + + sal_uInt32 nObjects = rSaveList.Count(); + sal_uInt32 nObjectsLeft = nObjects; + + while ( nObjectsLeft ) + { + sal_uInt32 i, nObjectsOfSameSize = 0; + sal_uInt32 nObjectStartIndex = nObjects - nObjectsLeft; + + BSaveStruct* pSave = (BSaveStruct*)rSaveList.GetObject( nObjectStartIndex ); + Rectangle aRect( pSave->aOutRect ); + + for ( i = nObjectStartIndex; i < nObjects; ) + { + nObjectsOfSameSize++; + if ( ++i < nObjects ) + { + pSave = (BSaveStruct*)rSaveList.GetObject( i ); + if ( pSave->aOutRect != aRect ) + break; + } + } + Point aPos( ImplMap( aRect.TopLeft() ) ); + Size aSize( ImplMap( aRect.GetSize() ) ); + + for ( i = nObjectStartIndex; i < ( nObjectStartIndex + nObjectsOfSameSize ); i++ ) + { + pSave = (BSaveStruct*)rSaveList.GetObject( i ); + + sal_uInt32 nWinRop = pSave->nWinRop; + sal_uInt8 nRasterOperation = (sal_uInt8)( nWinRop >> 16 ); + + sal_uInt32 nUsed = 0; + if ( ( nRasterOperation & 0xf ) != ( nRasterOperation >> 4 ) ) + nUsed |= 1; // pattern is used + if ( ( nRasterOperation & 0x33 ) != ( ( nRasterOperation & 0xcc ) >> 2 ) ) + nUsed |= 2; // source is used + if ( ( nRasterOperation & 0xaa ) != ( ( nRasterOperation & 0x55 ) << 1 ) ) + nUsed |= 4; // destination is used + + if ( (nUsed & 1) && (( nUsed & 2 ) == 0) ) + { // patterns aren't well supported yet + sal_uInt32 nOldRop = SetRasterOp( ROP_OVERPAINT ); // in this case nRasterOperation is either 0 or 0xff + UpdateFillStyle(); + DrawRect( aRect, FALSE ); + SetRasterOp( nOldRop ); + } + else + { + sal_Bool bDrawn = sal_False; + + if ( i == nObjectStartIndex ) // optimizing, sometimes it is possible to create just one transparent bitmap + { + if ( nObjectsOfSameSize == 2 ) + { + BSaveStruct* pSave2 = (BSaveStruct*)rSaveList.GetObject( i + 1 ); + if ( ( pSave->aBmp.GetPrefSize() == pSave2->aBmp.GetPrefSize() ) && + ( pSave->aBmp.GetPrefMapMode() == pSave2->aBmp.GetPrefMapMode() ) ) + { + // TODO: Strictly speaking, we should + // check whether mask is monochrome, and + // whether image is black (upper branch) + // or white (lower branch). Otherwise, the + // effect is not the same as a masked + // bitmap. + if ( ( nWinRop == SRCPAINT ) && ( pSave2->nWinRop == SRCAND ) ) + { + Bitmap aMask( pSave->aBmp ); aMask.Invert(); + BitmapEx aBmpEx( pSave2->aBmp, aMask ); + ImplDrawBitmap( aPos, aSize, aBmpEx ); + bDrawn = sal_True; + i++; + } + // #i20085# This is just the other way + // around as above. Only difference: mask + // is inverted + else if ( ( nWinRop == SRCAND ) && ( pSave2->nWinRop == SRCPAINT ) ) + { + Bitmap aMask( pSave->aBmp ); + BitmapEx aBmpEx( pSave2->aBmp, aMask ); + ImplDrawBitmap( aPos, aSize, aBmpEx ); + bDrawn = sal_True; + i++; + } + } + } + } + + if ( !bDrawn ) + { + Push(); + sal_uInt32 nOldRop = SetRasterOp( R2_COPYPEN ); + Bitmap aBitmap( pSave->aBmp ); + sal_uInt32 nOperation = ( nRasterOperation & 0xf ); + switch( nOperation ) + { + case 0x1 : + case 0xe : + { + SetRasterOp( R2_XORPEN ); + ImplDrawBitmap( aPos, aSize, aBitmap ); + SetRasterOp( R2_COPYPEN ); + Bitmap aMask( aBitmap ); + aMask.Invert(); + BitmapEx aBmpEx( aBitmap, aMask ); + ImplDrawBitmap( aPos, aSize, aBmpEx ); + if ( nOperation == 0x1 ) + { + SetRasterOp( R2_NOT ); + DrawRect( aRect, FALSE ); + } + } + break; + case 0x7 : + case 0x8 : + { + Bitmap aMask( aBitmap ); + if ( ( nUsed & 1 ) && ( nRasterOperation & 0xb0 ) == 0xb0 ) // pattern used + { + aBitmap.Convert( BMP_CONVERSION_24BIT ); + aBitmap.Erase( maFillStyle.aFillColor ); + } + BitmapEx aBmpEx( aBitmap, aMask ); + ImplDrawBitmap( aPos, aSize, aBmpEx ); + if ( nOperation == 0x7 ) + { + SetRasterOp( R2_NOT ); + DrawRect( aRect, FALSE ); + } + } + break; + + case 0x4 : + case 0xb : + { + SetRasterOp( R2_NOT ); + DrawRect( aRect, FALSE ); + SetRasterOp( R2_COPYPEN ); + Bitmap aMask( aBitmap ); + aBitmap.Invert(); + BitmapEx aBmpEx( aBitmap, aMask ); + ImplDrawBitmap( aPos, aSize, aBmpEx ); + SetRasterOp( R2_XORPEN ); + ImplDrawBitmap( aPos, aSize, aBitmap ); + if ( nOperation == 0xb ) + { + SetRasterOp( R2_NOT ); + DrawRect( aRect, FALSE ); + } + } + break; + + case 0x2 : + case 0xd : + { + Bitmap aMask( aBitmap ); + aMask.Invert(); + BitmapEx aBmpEx( aBitmap, aMask ); + ImplDrawBitmap( aPos, aSize, aBmpEx ); + SetRasterOp( R2_XORPEN ); + ImplDrawBitmap( aPos, aSize, aBitmap ); + if ( nOperation == 0xd ) + { + SetRasterOp( R2_NOT ); + DrawRect( aRect, FALSE ); + } + } + break; + case 0x6 : + case 0x9 : + { + SetRasterOp( R2_XORPEN ); + ImplDrawBitmap( aPos, aSize, aBitmap ); + if ( nOperation == 0x9 ) + { + SetRasterOp( R2_NOT ); + DrawRect( aRect, FALSE ); + } + } + break; + + case 0x0 : // WHITENESS + case 0xf : // BLACKNESS + { // in this case nRasterOperation is either 0 or 0xff + maFillStyle = WinMtfFillStyle( Color( nRasterOperation, nRasterOperation, nRasterOperation ) ); + UpdateFillStyle(); + DrawRect( aRect, FALSE ); + } + break; + + case 0x3 : // only source is used + case 0xc : + { + if ( nRasterOperation == 0x33 ) + aBitmap.Invert(); + ImplDrawBitmap( aPos, aSize, aBitmap ); + } + break; + + case 0x5 : // only destination is used + { + SetRasterOp( R2_NOT ); + DrawRect( aRect, FALSE ); + } + case 0xa : // no operation + break; + } + SetRasterOp( nOldRop ); + Pop(); + } + } + } + nObjectsLeft -= nObjectsOfSameSize; + } + + void* pPtr; + for ( pPtr = rSaveList.First(); pPtr; pPtr = rSaveList.Next() ) + delete (BSaveStruct*)pPtr; + rSaveList.Clear(); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetDevOrg( const Point& rPoint ) +{ + mnDevOrgX = rPoint.X(); + mnDevOrgY = rPoint.Y(); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetDevOrgOffset( INT32 nXAdd, INT32 nYAdd ) +{ + mnDevOrgX += nXAdd; + mnDevOrgY += nYAdd; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetDevExt( const Size& rSize ) +{ + if ( rSize.Width() && rSize.Height() ) + { + switch( mnMapMode ) + { + case MM_ISOTROPIC : + case MM_ANISOTROPIC : + { + mnDevWidth = rSize.Width(); + mnDevHeight = rSize.Height(); + } + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ScaleDevExt( double fX, double fY ) +{ + mnDevWidth = FRound( mnDevWidth * fX ); + mnDevHeight = FRound( mnDevHeight * fY ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetWinOrg( const Point& rPoint ) +{ + mnWinOrgX = rPoint.X(); + mnWinOrgY = rPoint.Y(); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetWinOrgOffset( INT32 nXAdd, INT32 nYAdd ) +{ + mnWinOrgX += nXAdd; + mnWinOrgY += nYAdd; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetWinExt( const Size& rSize ) +{ + + if( rSize.Width() && rSize.Height() ) + { + switch( mnMapMode ) + { + case MM_ISOTROPIC : + case MM_ANISOTROPIC : + { + mnWinExtX = rSize.Width(); + mnWinExtY = rSize.Height(); + } + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ScaleWinExt( double fX, double fY ) +{ + mnWinExtX = FRound( mnWinExtX * fX ); + mnWinExtY = FRound( mnWinExtY * fY ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetrclBounds( const Rectangle& rRect ) +{ + mrclBounds = rRect; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetrclFrame( const Rectangle& rRect ) +{ + mrclFrame = rRect; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetRefPix( const Size& rSize ) +{ + mnPixX = rSize.Width(); + mnPixY = rSize.Height(); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetRefMill( const Size& rSize ) +{ + mnMillX = rSize.Width(); + mnMillY = rSize.Height(); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetMapMode( sal_uInt32 nMapMode ) +{ + mnMapMode = nMapMode; + if ( nMapMode == MM_TEXT ) + { + mnWinExtX = mnDevWidth; + mnWinExtY = mnDevHeight; + } + else if ( mnMapMode == MM_HIMETRIC ) + { + mnWinExtX = mnMillX * 100; + mnWinExtY = mnMillY * 100; + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetWorldTransform( const XForm& rXForm ) +{ + maXForm.eM11 = rXForm.eM11; + maXForm.eM12 = rXForm.eM12; + maXForm.eM21 = rXForm.eM21; + maXForm.eM22 = rXForm.eM22; + maXForm.eDx = rXForm.eDx; + maXForm.eDy = rXForm.eDy; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ModifyWorldTransform( const XForm& rXForm, UINT32 nMode ) +{ + switch( nMode ) + { + case MWT_IDENTITY : + { + maXForm.eM11 = maXForm.eM12 = maXForm.eM21 = maXForm.eM22 = 1.0f; + maXForm.eDx = maXForm.eDx = 0.0f; + } + break; + + case MWT_RIGHTMULTIPLY : + case MWT_LEFTMULTIPLY : + { + const XForm* pLeft; + const XForm* pRight; + + if ( nMode == MWT_LEFTMULTIPLY ) + { + pLeft = &rXForm; + pRight = &maXForm; + } + else + { + pLeft = &maXForm; + pRight = &rXForm; + } + + float aF[3][3]; + float bF[3][3]; + float cF[3][3]; + + aF[0][0] = pLeft->eM11; + aF[0][1] = pLeft->eM12; + aF[0][2] = 0; + aF[1][0] = pLeft->eM21; + aF[1][1] = pLeft->eM22; + aF[1][2] = 0; + aF[2][0] = pLeft->eDx; + aF[2][1] = pLeft->eDy; + aF[2][2] = 1; + + bF[0][0] = pRight->eM11; + bF[0][1] = pRight->eM12; + bF[0][2] = 0; + bF[1][0] = pRight->eM21; + bF[1][1] = pRight->eM22; + bF[1][2] = 0; + bF[2][0] = pRight->eDx; + bF[2][1] = pRight->eDy; + bF[2][2] = 1; + + int i, j, k; + for ( i = 0; i < 3; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + cF[i][j] = 0; + for ( k = 0; k < 3; k++ ) + cF[i][j] += aF[i][k] * bF[k][j]; + } + } + maXForm.eM11 = cF[0][0]; + maXForm.eM12 = cF[0][1]; + maXForm.eM21 = cF[1][0]; + maXForm.eM22 = cF[1][1]; + maXForm.eDx = cF[2][0]; + maXForm.eDy = cF[2][1]; + } + break; + } + } + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::Push() // !! to be able to access the original ClipRegion it +{ // is not allowed to use the MetaPushAction() + UpdateClipRegion(); // (the original clip region is on top of the stack) (SJ) + SaveStructPtr pSave( new SaveStruct ); + + pSave->aLineStyle = maLineStyle; + pSave->aFillStyle = maFillStyle; + + pSave->aFont = maFont; + pSave->aTextColor = maTextColor; + pSave->nTextAlign = mnTextAlign; + pSave->nTextLayoutMode = mnTextLayoutMode; + pSave->nMapMode = mnMapMode; + pSave->nGfxMode = mnGfxMode; + pSave->nBkMode = mnBkMode; + pSave->aBkColor = maBkColor; + pSave->bFillStyleSelected = mbFillStyleSelected; + + pSave->aActPos = maActPos; + pSave->aXForm = maXForm; + pSave->eRasterOp = meRasterOp; + + pSave->nWinOrgX = mnWinOrgX; + pSave->nWinOrgY = mnWinOrgY; + pSave->nWinExtX = mnWinExtX; + pSave->nWinExtY = mnWinExtY; + pSave->nDevOrgX = mnDevOrgX; + pSave->nDevOrgY = mnDevOrgY; + pSave->nDevWidth = mnDevWidth; + pSave->nDevHeight = mnDevHeight; + + pSave->aPathObj = aPathObj; + pSave->aClipPath = aClipPath; + + vSaveStack.push_back( pSave ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::Pop() +{ + // Die aktuellen Daten vom Stack holen + if( vSaveStack.size() ) + { + // Die aktuelle Daten auf dem Stack sichern + SaveStructPtr pSave( vSaveStack.back() ); + + maLineStyle = pSave->aLineStyle; + maFillStyle = pSave->aFillStyle; + + maFont = pSave->aFont; + maTextColor = pSave->aTextColor; + mnTextAlign = pSave->nTextAlign; + mnTextLayoutMode = pSave->nTextLayoutMode; + mnBkMode = pSave->nBkMode; + mnGfxMode = pSave->nGfxMode; + mnMapMode = pSave->nMapMode; + maBkColor = pSave->aBkColor; + mbFillStyleSelected = pSave->bFillStyleSelected; + + maActPos = pSave->aActPos; + maXForm = pSave->aXForm; + meRasterOp = pSave->eRasterOp; + + mnWinOrgX = pSave->nWinOrgX; + mnWinOrgY = pSave->nWinOrgY; + mnWinExtX = pSave->nWinExtX; + mnWinExtY = pSave->nWinExtY; + mnDevOrgX = pSave->nDevOrgX; + mnDevOrgY = pSave->nDevOrgY; + mnDevWidth = pSave->nDevWidth; + mnDevHeight = pSave->nDevHeight; + + aPathObj = pSave->aPathObj; + if ( ! ( aClipPath == pSave->aClipPath ) ) + { + aClipPath = pSave->aClipPath; + aClipPath.bNeedsUpdate = sal_True; + } + if ( meLatestRasterOp != meRasterOp ) + mpGDIMetaFile->AddAction( new MetaRasterOpAction( meRasterOp ) ); + vSaveStack.pop_back(); + } +} + +void WinMtfOutput::AddFromGDIMetaFile( GDIMetaFile& rGDIMetaFile ) +{ + rGDIMetaFile.Play( *mpGDIMetaFile, 0xFFFFFFFF ); +} + diff --git a/svtools/source/filter.vcl/wmf/winmtf.hxx b/svtools/source/filter.vcl/wmf/winmtf.hxx new file mode 100644 index 000000000000..beb1f62e22d6 --- /dev/null +++ b/svtools/source/filter.vcl/wmf/winmtf.hxx @@ -0,0 +1,776 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _WINMTF_HXX +#define _WINMTF_HXX + +#ifdef DBG_UTIL +#define WIN_MTF_ASSERT +#endif + +#include <sot/object.hxx> +#ifndef BOOST_SHARED_PTR_HPP_INCLUDED +#include <boost/shared_ptr.hpp> +#endif +#ifndef _TOOL_DEBUG_HXX +#include <tools/debug.hxx> +#endif +#include <tools/stack.hxx> +#include <tools/table.hxx> +#include <tools/dynary.hxx> +#include <vcl/graph.hxx> +#include <vcl/virdev.hxx> +#include <tools/poly.hxx> +#include <vcl/font.hxx> +#include <vcl/bmpacc.hxx> +#include <vcl/lineinfo.hxx> +#include <svtools/fltcall.hxx> + +#include <vector> +#include <math.h> +#include <stdlib.h> + +#define ERROR 0 +#define NULLREGION 1 +#define SIMPLEREGION 2 +#define COMPLEXREGION 3 + +#define RGN_AND 1 +#define RGN_OR 2 +#define RGN_XOR 3 +#define RGN_DIFF 4 +#define RGN_COPY 5 + +#define TRANSPARENT 1 +#define OPAQUE 2 +#define BKMODE_LAST 2 + +/* xform stuff */ +#define MWT_IDENTITY 1 +#define MWT_LEFTMULTIPLY 2 +#define MWT_RIGHTMULTIPLY 3 + +#define ENHMETA_STOCK_OBJECT 0x80000000 + +/* Stock Logical Objects */ +#define WHITE_BRUSH 0 +#define LTGRAY_BRUSH 1 +#define GRAY_BRUSH 2 +#define DKGRAY_BRUSH 3 +#define BLACK_BRUSH 4 +#define NULL_BRUSH 5 +#define HOLLOW_BRUSH NULL_BRUSH +#define WHITE_PEN 6 +#define BLACK_PEN 7 +#define NULL_PEN 8 +#define OEM_FIXED_FONT 10 +#define ANSI_FIXED_FONT 11 +#define ANSI_VAR_FONT 12 +#define SYSTEM_FONT 13 +#define DEVICE_DEFAULT_FONT 14 +#define DEFAULT_PALETTE 15 +#define SYSTEM_FIXED_FONT 16 + + +#define R2_BLACK 1 +#define R2_NOTMERGEPEN 2 +#define R2_MASKNOTPEN 3 +#define R2_NOTCOPYPEN 4 +#define R2_MASKPENNOT 5 +#define R2_NOT 6 +#define R2_XORPEN 7 +#define R2_NOTMASKPEN 8 +#define R2_MASKPEN 9 +#define R2_NOTXORPEN 10 +#define R2_NOP 11 +#define R2_MERGENOTPEN 12 +#define R2_COPYPEN 13 +#define R2_MERGEPENNOT 14 +#define R2_MERGEPEN 15 +#define R2_WHITE 16 + +/* Mapping Modes */ +#define MM_TEXT 1 +#define MM_LOMETRIC 2 +#define MM_HIMETRIC 3 +#define MM_LOENGLISH 4 +#define MM_HIENGLISH 5 +#define MM_TWIPS 6 +#define MM_ISOTROPIC 7 +#define MM_ANISOTROPIC 8 + + +/* Graphics Modes */ +#define GM_COMPATIBLE 1 +#define GM_ADVANCED 2 +#define GM_LAST 2 + +/* StretchBlt() Modes */ +#define BLACKONWHITE 1 +#define WHITEONBLACK 2 +#define COLORONCOLOR 3 +#define HALFTONE 4 +#define MAXSTRETCHBLTMODE 4 +#define STRETCH_ANDSCANS BLACKONWHITE +#define STRETCH_ORSCANS WHITEONBLACK +#define STRETCH_DELETESCANS COLORONCOLOR +#define STRETCH_HALFTONE HALFTONE + +#define LF_FACESIZE 32 + +struct LOGFONTW +{ + INT32 lfHeight; + INT32 lfWidth; + INT32 lfEscapement; + INT32 lfOrientation; + INT32 lfWeight; + BYTE lfItalic; + BYTE lfUnderline; + BYTE lfStrikeOut; + BYTE lfCharSet; + BYTE lfOutPrecision; + BYTE lfClipPrecision; + BYTE lfQuality; + BYTE lfPitchAndFamily; + String alfFaceName; +}; + +#define TA_NOUPDATECP 0x0000 +#define TA_UPDATECP 0x0001 +#define TA_LEFT 0x0000 +#define TA_RIGHT 0x0002 +#define TA_CENTER 0x0006 +#define TA_RIGHT_CENTER (TA_RIGHT | TA_CENTER) +#define TA_TOP 0x0000 +#define TA_BOTTOM 0x0008 +#define TA_BASELINE 0x0018 + +#define SRCCOPY 0x00CC0020L +#define SRCPAINT 0x00EE0086L +#define SRCAND 0x008800C6L +#define SRCINVERT 0x00660046L +#define SRCERASE 0x00440328L +#define NOTSRCCOPY 0x00330008L +#define NOTSRCERASE 0x001100A6L +#define MERGECOPY 0x00C000CAL +#define MERGEPAINT 0x00BB0226L +#define PATCOPY 0x00F00021L +#define PATPAINT 0x00FB0A09L +#define PATINVERT 0x005A0049L +#define DSTINVERT 0x00550009L +#define BLACKNESS 0x00000042L +#define WHITENESS 0x00FF0062L + +#define PS_SOLID 0 +#define PS_DASH 1 +#define PS_DOT 2 +#define PS_DASHDOT 3 +#define PS_DASHDOTDOT 4 +#define PS_NULL 5 +#define PS_INSIDEFRAME 6 +#define PS_USERSTYLE 7 +#define PS_ALTERNATE 8 +#define PS_STYLE_MASK 15 + +#define PS_ENDCAP_ROUND 0x000 +#define PS_ENDCAP_SQUARE 0x100 +#define PS_ENDCAP_FLAT 0x200 +#define PS_ENDCAP_MASK 0xF00 + +#define PS_JOIN_ROUND 0x0000 +#define PS_JOIN_BEVEL 0x1000 +#define PS_JOIN_MITER 0x2000 +#define PS_JOIN_MASK 0xF000 + +#define PS_COSMETIC 0x00000 +#define PS_GEOMETRIC 0x10000 +#define PS_TYPE_MASK 0xF0000 + +#define ANSI_CHARSET 0 +#define DEFAULT_CHARSET 1 +#define SYMBOL_CHARSET 2 +#define SHIFTJIS_CHARSET 128 +#define HANGEUL_CHARSET 129 +#define GB2312_CHARSET 134 +#define CHINESEBIG5_CHARSET 136 +#define OEM_CHARSET 255 +/*WINVER >= 0x0400*/ +#define JOHAB_CHARSET 130 +#define HEBREW_CHARSET 177 +#define ARABIC_CHARSET 178 +#define GREEK_CHARSET 161 +#define TURKISH_CHARSET 162 +#define VIETNAMESE_CHARSET 163 +#define THAI_CHARSET 222 +#define EASTEUROPE_CHARSET 238 +#define RUSSIAN_CHARSET 204 +#define MAC_CHARSET 77 +#define BALTIC_CHARSET 186 + +#define ETO_OPAQUE 0x0002 +#define ETO_CLIPPED 0x0004 +/*WINVER >= 0x0400*/ +#define ETO_GLYPH_INDEX 0x0010 +#define ETO_RTLREADING 0x0080 +#define ETO_NUMERICSLOCAL 0x0400 +#define ETO_NUMERICSLATIN 0x0800 +#define ETO_IGNORELANGUAGE 0x1000 +/*_WIN32_WINNT >= 0x0500*/ +#define ETO_PDY 0x2000 + + +#define DEFAULT_PITCH 0x00 +#define FIXED_PITCH 0x01 +#define VARIABLE_PITCH 0x02 + +/* Font Families */ +#define FF_DONTCARE 0x00 +#define FF_ROMAN 0x10 +#define FF_SWISS 0x20 +#define FF_MODERN 0x30 +#define FF_SCRIPT 0x40 +#define FF_DECORATIVE 0x50 + +#define FW_DONTCARE 0 +#define FW_THIN 100 +#define FW_EXTRALIGHT 200 +#define FW_LIGHT 300 +#define FW_NORMAL 400 +#define FW_MEDIUM 500 +#define FW_SEMIBOLD 600 +#define FW_BOLD 700 +#define FW_EXTRABOLD 800 +#define FW_HEAVY 900 +#define FW_ULTRALIGHT 200 +#define FW_REGULAR 400 +#define FW_DEMIBOLD 600 +#define FW_ULTRABOLD 800 +#define FW_BLACK 900 + +#define BS_SOLID 0 +#define BS_NULL 1 +#define BS_HOLLOW 1 +#define BS_HATCHED 2 +#define BS_PATTERN 3 +#define BS_INDEXED 4 +#define BS_DIBPATTERN 5 +#define BS_DIBPATTERNPT 6 +#define BS_PATTERN8X8 7 +#define BS_DIBPATTERN8X8 8 +#define BS_MONOPATTERN 9 + +#define W_HS_HORIZONTAL 0 +#define W_HS_VERTICAL 1 +#define W_HS_FDIAGONAL 2 +#define W_HS_BDIAGONAL 3 +#define W_HS_CROSS 4 +#define W_HS_DIAGCROSS 5 + +#define RDH_RECTANGLES 1 + +#define W_MFCOMMENT 15 + +#define PRIVATE_ESCAPE_UNICODE 2 + +//============================ WMFReader ================================== + + +#ifdef WIN_MTF_ASSERT +#define WIN_MTF_ASSERT_INIT 0x80000000 +#define WIN_MTF_ASSERT_ONCE 0x40000000 +#define WIN_MTF_ASSERT_MIFE 0x20000000 + +void WinMtfAssertHandler( const sal_Char*, sal_uInt32 nFlags = WIN_MTF_ASSERT_MIFE ); +#endif + +enum WinMtfClipPathType{ EMPTY, RECTANGLE, COMPLEX }; + +class WinMtfClipPath +{ + PolyPolygon aPolyPoly; + WinMtfClipPathType eType; + + void ImpUpdateType(); + + public : + + sal_Bool bNeedsUpdate; + + WinMtfClipPath(): eType(EMPTY), bNeedsUpdate( sal_False ){}; + + void SetClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode ); + void IntersectClipRect( const Rectangle& rRect ); + void ExcludeClipRect( const Rectangle& rRect ); + void MoveClipRegion( const Size& rSize ); + + WinMtfClipPathType GetType() const { return eType; }; + const PolyPolygon& GetClipPath() const { return aPolyPoly; }; + + sal_Bool operator==( const WinMtfClipPath& rPath ) + { + return ( rPath.eType == eType ) && + ( rPath.aPolyPoly == aPolyPoly ); + }; +}; + +class WinMtfPathObj : public PolyPolygon +{ + sal_Bool bClosed; + + public : + + WinMtfPathObj() { bClosed = sal_True; } + void Init() { Clear(); bClosed = sal_True; }; + void ClosePath(); + + void AddPoint( const Point& rPoint ); + void AddPolygon( const Polygon& rPoly ); + void AddPolyLine( const Polygon& rPoly ); + void AddPolyPolygon( const PolyPolygon& rPolyPolygon ); +}; + +struct WinMtfFontStyle +{ + Font aFont; + + WinMtfFontStyle( LOGFONTW& rLogFont ); +}; + +// ----------------------------------------------------------------------------- + +struct WinMtfFillStyle +{ + Color aFillColor; + BOOL bTransparent; + + WinMtfFillStyle() : + aFillColor ( Color( COL_BLACK ) ), + bTransparent( FALSE ) + { + }; + + WinMtfFillStyle( const Color& rColor, BOOL bTrans = FALSE ) : + aFillColor ( rColor ), + bTransparent( bTrans ) + { + }; + + BOOL operator==( const WinMtfFillStyle& rStyle ) + { return ( ( aFillColor == rStyle.aFillColor ) && ( bTransparent == rStyle.bTransparent ) ); }; + BOOL operator==( WinMtfFillStyle* pStyle ) + { return ( ( aFillColor == pStyle->aFillColor ) && ( bTransparent == pStyle->bTransparent ) ); }; + void operator=( const WinMtfFillStyle& rStyle ) { aFillColor = rStyle.aFillColor; bTransparent = rStyle.bTransparent; }; + void operator=( WinMtfFillStyle* pStyle ) { aFillColor = pStyle->aFillColor; bTransparent = pStyle->bTransparent; }; +}; + +// ----------------------------------------------------------------------------- + +struct WinMtfLineStyle +{ + Color aLineColor; + LineInfo aLineInfo; + BOOL bTransparent; + + WinMtfLineStyle() : + aLineColor ( COL_BLACK ), + bTransparent( FALSE ) {}; + + WinMtfLineStyle( const Color& rColor, BOOL bTrans = FALSE ) : + aLineColor ( rColor ), + bTransparent( bTrans ) {}; + + WinMtfLineStyle( const Color& rColor, const LineInfo rStyle, BOOL bTrans = FALSE ) : + aLineColor ( rColor ), + aLineInfo ( rStyle ), + bTransparent( bTrans ) {}; + + BOOL operator==( const WinMtfLineStyle& rStyle ) { return ( ( aLineColor == rStyle.aLineColor ) && ( bTransparent == rStyle.bTransparent ) && ( aLineInfo == rStyle.aLineInfo ) ); }; + BOOL operator==( WinMtfLineStyle* pStyle ) { return ( ( aLineColor == pStyle->aLineColor ) && ( bTransparent == pStyle->bTransparent ) && ( aLineInfo == pStyle->aLineInfo ) ); }; + void operator=( const WinMtfLineStyle& rStyle ) + { + aLineColor = rStyle.aLineColor; + bTransparent = rStyle.bTransparent; + aLineInfo = rStyle.aLineInfo; + }; + + void operator=( WinMtfLineStyle* pStyle ) + { + aLineColor = pStyle->aLineColor; + bTransparent = pStyle->bTransparent; + aLineInfo = pStyle->aLineInfo; + }; +}; + +// ----------------------------------------------------------------------------- + +struct XForm +{ + float eM11; + float eM12; + float eM21; + float eM22; + float eDx; + float eDy; + XForm() + { + eM11 = eM22 = 1.0f; + eDx = eDy = eM12 = eM21 = 0.0f; + }; + + friend SvStream& operator>>( SvStream& rIn, XForm& rXForm ); +}; + +// ----------------------------------------------------------------------------- + +struct SaveStruct +{ + sal_uInt32 nBkMode, nMapMode, nGfxMode, nTextLayoutMode; + sal_Int32 nWinOrgX, nWinOrgY, nWinExtX, nWinExtY; + sal_Int32 nDevOrgX, nDevOrgY, nDevWidth, nDevHeight; + + WinMtfLineStyle aLineStyle; + WinMtfFillStyle aFillStyle; + + Font aFont; + Color aBkColor; + Color aTextColor; + sal_uInt32 nTextAlign; + RasterOp eRasterOp; + + Point aActPos; + WinMtfPathObj aPathObj; + WinMtfClipPath aClipPath; + XForm aXForm; + + sal_Bool bRecordPath; + sal_Bool bFillStyleSelected; +}; + +typedef ::boost::shared_ptr< SaveStruct > SaveStructPtr; + +// ----------------------------------------------------------------------------- + +struct BSaveStruct +{ + Bitmap aBmp; + Rectangle aOutRect; + UINT32 nWinRop; + + BSaveStruct( const Bitmap& rBmp, const Rectangle& rOutRect, UINT32 nRop ) : + aBmp( rBmp ), aOutRect( rOutRect ), nWinRop( nRop ){}; +}; + +// ----------------------------------------------------------------------------- + +enum GDIObjectType { GDI_DUMMY = 0, GDI_PEN = 1, GDI_BRUSH = 2, GDI_FONT = 3, GDI_PALETTE = 4, GDI_BITMAP = 5, GDI_REGION = 6 }; + +struct GDIObj +{ + void* pStyle; + GDIObjectType eType; + + GDIObj() : + pStyle ( NULL ), + eType ( GDI_DUMMY ) + { + }; + + GDIObj( GDIObjectType eT, void* pS ) { pStyle = pS; eType = eT; }; + void Set( GDIObjectType eT, void* pS ) { pStyle = pS; eType = eT; }; + void Delete() + { + if ( pStyle ) + { + switch ( eType ) + { + case GDI_PEN : + delete (WinMtfLineStyle*)pStyle; + break; + case GDI_BRUSH : + delete (WinMtfFillStyle*)pStyle; + break; + case GDI_FONT : + delete (WinMtfFontStyle*)pStyle; + break; + + default: + DBG_ERROR( "unsupported style deleted" ); + break; + } + pStyle = NULL; + } + }; + + ~GDIObj() + { + Delete(); + } +}; + +// ----------------------------------------------------------------------------- + +class WinMtfOutput +{ + + WinMtfPathObj aPathObj; + WinMtfClipPath aClipPath; + + WinMtfLineStyle maLatestLineStyle; + WinMtfLineStyle maLineStyle; + WinMtfFillStyle maLatestFillStyle; + WinMtfFillStyle maFillStyle; + Font maLatestFont; + Font maFont; + sal_uInt32 mnLatestTextAlign; + sal_uInt32 mnTextAlign; + Color maLatestTextColor; + Color maTextColor; + Color maLatestBkColor; + Color maBkColor; + sal_uInt32 mnLatestTextLayoutMode; + sal_uInt32 mnTextLayoutMode; + sal_uInt32 mnLatestBkMode; + sal_uInt32 mnBkMode; + RasterOp meLatestRasterOp; + RasterOp meRasterOp; + + std::vector< GDIObj* > vGDIObj; + + Point maActPos; + + sal_uInt32 mnRop; + sal_Bool mbNopMode; + sal_Bool mbFillStyleSelected; + + std::vector< SaveStructPtr > vSaveStack; + + sal_uInt32 mnGfxMode; + sal_uInt32 mnMapMode; + XForm maXForm; + sal_Int32 mnDevOrgX, mnDevOrgY; + sal_Int32 mnDevWidth, mnDevHeight; + sal_Int32 mnWinOrgX, mnWinOrgY; // aktuelles Window-Origin + sal_Int32 mnWinExtX, mnWinExtY; // aktuelles Window-Extent + + sal_Int32 mnPixX, mnPixY; // Reference Device in pixel + sal_Int32 mnMillX, mnMillY; // Reference Device in Mill + Rectangle mrclFrame; // rectangle in logical units 1/100th mm + Rectangle mrclBounds; + + GDIMetaFile* mpGDIMetaFile; + + void UpdateLineStyle(); + void UpdateFillStyle(); + + Point ImplMap( const Point& rPt ); + Size ImplMap( const Size& rSz ); + Rectangle ImplMap( const Rectangle& rRectangle ); + void ImplMap( Font& rFont ); + Polygon& ImplMap( Polygon& rPolygon ); + PolyPolygon& ImplMap( PolyPolygon& rPolyPolygon ); + void ImplResizeObjectArry( UINT32 nNewEntry ); + void ImplSetNonPersistentLineColorTransparenz(); + void ImplDrawClippedPolyPolygon( const PolyPolygon& rPolyPoly ); + void ImplDrawBitmap( const Point& rPos, const Size& rSize, const BitmapEx rBitmap ); + + public: + + void SetDevOrg( const Point& rPoint ); + void SetDevOrgOffset( INT32 nXAdd, INT32 nYAdd ); + void SetDevExt( const Size& rSize ); + void ScaleDevExt( double fX, double fY ); + + void SetWinOrg( const Point& rPoint ); + void SetWinOrgOffset( INT32 nX, INT32 nY ); + void SetWinExt( const Size& rSize ); + void ScaleWinExt( double fX, double fY ); + + void SetrclBounds( const Rectangle& rRect ); + void SetrclFrame( const Rectangle& rRect ); + void SetRefPix( const Size& rSize ); + void SetRefMill( const Size& rSize ); + + sal_uInt32 GetMapMode() const { return mnMapMode; }; + void SetMapMode( sal_uInt32 mnMapMode ); + void SetWorldTransform( const XForm& rXForm ); + void ModifyWorldTransform( const XForm& rXForm, UINT32 nMode ); + + void Push(); + void Pop(); + + UINT32 SetRasterOp( UINT32 nRasterOp ); + void StrokeAndFillPath( sal_Bool bStroke, sal_Bool bFill ); + + void SetGfxMode( sal_Int32 nGfxMode ){ mnGfxMode = nGfxMode; }; + sal_Int32 GetGfxMode() const { return mnGfxMode; }; + void SetBkMode( UINT32 nMode ); + void SetBkColor( const Color& rColor ); + void SetTextColor( const Color& rColor ); + void SetTextAlign( UINT32 nAlign ); + void CreateObject( GDIObjectType, void* pStyle = NULL ); + void CreateObject( INT32 nIndex, GDIObjectType, void* pStyle = NULL ); + void DeleteObject( INT32 nIndex ); + void SelectObject( INT32 nIndex ); + CharSet GetCharSet(){ return maFont.GetCharSet(); }; + void SetFont( const Font& rFont ); + const Font& GetFont() const; + void SetTextLayoutMode( const sal_uInt32 nLayoutMode ); + sal_uInt32 GetTextLayoutMode() const; + + void ClearPath(){ aPathObj.Init(); }; + void ClosePath(){ aPathObj.ClosePath(); }; + const PolyPolygon& GetPathObj(){ return aPathObj; }; + + void MoveTo( const Point& rPoint, sal_Bool bRecordPath = sal_False ); + void LineTo( const Point& rPoint, sal_Bool bRecordPath = sal_False ); + void DrawPixel( const Point& rSource, const Color& rColor ); + void DrawLine( const Point& rSource, const Point& rDest ); + void DrawRect( const Rectangle& rRect, BOOL bEdge = TRUE ); + void DrawRoundRect( const Rectangle& rRect, const Size& rSize ); + void DrawEllipse( const Rectangle& rRect ); + void DrawArc( const Rectangle& rRect, const Point& rStartAngle, const Point& rEndAngle, BOOL bDrawTo = FALSE ); + void DrawPie( const Rectangle& rRect, const Point& rStartAngle, const Point& rEndAngle ); + void DrawChord( const Rectangle& rRect, const Point& rStartAngle, const Point& rEndAngle ); + void DrawPolygon( Polygon& rPolygon, sal_Bool bRecordPath = sal_False ); + void DrawPolyPolygon( PolyPolygon& rPolyPolygon, sal_Bool bRecordPath = sal_False ); + void DrawPolyLine( Polygon& rPolygon, sal_Bool bDrawTo = sal_False, sal_Bool bRecordPath = sal_False ); + void DrawPolyBezier( Polygon& rPolygin, sal_Bool bDrawTo = sal_False, sal_Bool bRecordPath = sal_False ); + void DrawText( Point& rPosition, String& rString, sal_Int32* pDXArry = NULL, sal_Bool bRecordPath = sal_False, + sal_Int32 nGraphicsMode = GM_COMPATIBLE ); + void ResolveBitmapActions( List& rSaveList ); + + void IntersectClipRect( const Rectangle& rRect ); + void ExcludeClipRect( const Rectangle& rRect ); + void MoveClipRegion( const Size& rSize ); + void SetClipPath( const PolyPolygon& rPolyPoly, sal_Int32 nClippingMode, sal_Bool bIsMapped ); + void UpdateClipRegion(); + void AddFromGDIMetaFile( GDIMetaFile& rGDIMetaFile ); + + WinMtfOutput( GDIMetaFile& rGDIMetaFile ); + virtual ~WinMtfOutput(); +}; + +// ----------------------------------------------------------------------------- + +class WinMtf +{ + protected: + + WinMtfOutput* pOut; // + SvStream* pWMF; // Die einzulesende WMF/EMF-Datei + + UINT32 nStartPos, nEndPos; + List aBmpSaveList; + + FilterConfigItem* pFilterConfigItem; + + com::sun::star::uno::Reference< com::sun::star::task::XStatusIndicator > xStatusIndicator; + + // Sorgt dafuer, das aSampledBrush der aktuelle Brush des GDIMetaFiles ist. + + Color ReadColor(); + void Callback( USHORT nPercent ); + + WinMtf( WinMtfOutput* pOut, SvStream& rStreamWMF, FilterConfigItem* pConfigItem = NULL ); + ~WinMtf(); + + public: + +}; + +//============================ EMFReader ================================== + +class EnhWMFReader : public WinMtf +{ + sal_Bool bRecordPath; + sal_Int32 nRecordCount; + + BOOL ReadHeader(); + Rectangle ReadRectangle( INT32, INT32, INT32, INT32 ); // Liesst und konvertiert ein Rechteck + void ImplExtTextOut( BOOL bWideCharakter ); + +public: + EnhWMFReader( SvStream& rStreamWMF, GDIMetaFile& rGDIMetaFile, FilterConfigItem* pConfigItem = NULL ) + : WinMtf( new WinMtfOutput( rGDIMetaFile ), rStreamWMF, pConfigItem ), bRecordPath( sal_False ) {}; + ~EnhWMFReader(); + + BOOL ReadEnhWMF(); +}; + +//============================ WMFReader ================================== + +class WMFReader : public WinMtf +{ +private: + + VirtualDevice aVDev; // just for the purpose of "IsFontAvailable" + UINT16 nUnitsPerInch; + sal_uInt32 nRecSize; + + // embedded EMF data + SvMemoryStream* pEMFStream; + + // total number of comment records containing EMF data + sal_uInt32 nEMFRecCount; + + // number of EMF records read + sal_uInt32 nEMFRec; + + // total size of embedded EMF data + sal_uInt32 nEMFSize; + + sal_uInt32 nSkipActions; + sal_uInt32 nCurrentAction; + sal_uInt32 nUnicodeEscapeAction; + + // Liesst den Kopf der WMF-Datei + BOOL ReadHeader(); + + // Liesst die Parameter des Rocords mit der Funktionsnummer nFunction. + void ReadRecordParams( USHORT nFunction ); + + Point ReadPoint(); // Liesst und konvertiert einen Punkt (erst X dann Y) + Point ReadYX(); // Liesst und konvertiert einen Punkt (erst Y dann X) + Rectangle ReadRectangle(); // Liesst und konvertiert ein Rechteck + Size ReadYXExt(); + sal_Bool GetPlaceableBound( Rectangle& rSize, SvStream* pStrm ); + +public: + + WMFReader( SvStream& rStreamWMF, GDIMetaFile& rGDIMetaFile, FilterConfigItem* pConfigItem = NULL ) + : WinMtf( new WinMtfOutput( rGDIMetaFile ), rStreamWMF, pConfigItem ) {}; + + ~WMFReader(); + + // Liesst aus dem Stream eine WMF-Datei und fuellt das GDIMetaFile + void ReadWMF(); +}; + +#endif + + diff --git a/svtools/source/filter.vcl/wmf/winwmf.cxx b/svtools/source/filter.vcl/wmf/winwmf.cxx new file mode 100644 index 000000000000..f7c4f51ce1e2 --- /dev/null +++ b/svtools/source/filter.vcl/wmf/winwmf.cxx @@ -0,0 +1,1426 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +#include "winmtf.hxx" +#include <vcl/gdimtf.hxx> +#include <rtl/crc.h> +#include <rtl/tencinfo.h> +#include <osl/endian.h> + +//====================== MS-Windows-defines =============================== + +#define W_META_SETBKCOLOR 0x0201 +#define W_META_SETBKMODE 0x0102 +#define W_META_SETMAPMODE 0x0103 +#define W_META_SETROP2 0x0104 +#define W_META_SETRELABS 0x0105 +#define W_META_SETPOLYFILLMODE 0x0106 +#define W_META_SETSTRETCHBLTMODE 0x0107 +#define W_META_SETTEXTCHAREXTRA 0x0108 +#define W_META_SETTEXTCOLOR 0x0209 +#define W_META_SETTEXTJUSTIFICATION 0x020A +#define W_META_SETWINDOWORG 0x020B +#define W_META_SETWINDOWEXT 0x020C +#define W_META_SETVIEWPORTORG 0x020D +#define W_META_SETVIEWPORTEXT 0x020E +#define W_META_OFFSETWINDOWORG 0x020F +#define W_META_SCALEWINDOWEXT 0x0410 +#define W_META_OFFSETVIEWPORTORG 0x0211 +#define W_META_SCALEVIEWPORTEXT 0x0412 +#define W_META_LINETO 0x0213 +#define W_META_MOVETO 0x0214 +#define W_META_EXCLUDECLIPRECT 0x0415 +#define W_META_INTERSECTCLIPRECT 0x0416 +#define W_META_ARC 0x0817 +#define W_META_ELLIPSE 0x0418 +#define W_META_FLOODFILL 0x0419 +#define W_META_PIE 0x081A +#define W_META_RECTANGLE 0x041B +#define W_META_ROUNDRECT 0x061C +#define W_META_PATBLT 0x061D +#define W_META_SAVEDC 0x001E +#define W_META_SETPIXEL 0x041F +#define W_META_OFFSETCLIPRGN 0x0220 +#define W_META_TEXTOUT 0x0521 +#define W_META_BITBLT 0x0922 +#define W_META_STRETCHBLT 0x0B23 +#define W_META_POLYGON 0x0324 +#define W_META_POLYLINE 0x0325 +#define W_META_ESCAPE 0x0626 +#define W_META_RESTOREDC 0x0127 +#define W_META_FILLREGION 0x0228 +#define W_META_FRAMEREGION 0x0429 +#define W_META_INVERTREGION 0x012A +#define W_META_PAINTREGION 0x012B +#define W_META_SELECTCLIPREGION 0x012C +#define W_META_SELECTOBJECT 0x012D +#define W_META_SETTEXTALIGN 0x012E +#define W_META_DRAWTEXT 0x062F +#define W_META_CHORD 0x0830 +#define W_META_SETMAPPERFLAGS 0x0231 +#define W_META_EXTTEXTOUT 0x0a32 +#define W_META_SETDIBTODEV 0x0d33 +#define W_META_SELECTPALETTE 0x0234 +#define W_META_REALIZEPALETTE 0x0035 +#define W_META_ANIMATEPALETTE 0x0436 +#define W_META_SETPALENTRIES 0x0037 +#define W_META_POLYPOLYGON 0x0538 +#define W_META_RESIZEPALETTE 0x0139 +#define W_META_DIBBITBLT 0x0940 +#define W_META_DIBSTRETCHBLT 0x0b41 +#define W_META_DIBCREATEPATTERNBRUSH 0x0142 +#define W_META_STRETCHDIB 0x0f43 +#define W_META_EXTFLOODFILL 0x0548 +#define W_META_RESETDC 0x014C +#define W_META_STARTDOC 0x014D +#define W_META_STARTPAGE 0x004F +#define W_META_ENDPAGE 0x0050 +#define W_META_ABORTDOC 0x0052 +#define W_META_ENDDOC 0x005E +#define W_META_DELETEOBJECT 0x01f0 +#define W_META_CREATEPALETTE 0x00f7 +#define W_META_CREATEBRUSH 0x00F8 +#define W_META_CREATEPATTERNBRUSH 0x01F9 +#define W_META_CREATEPENINDIRECT 0x02FA +#define W_META_CREATEFONTINDIRECT 0x02FB +#define W_META_CREATEBRUSHINDIRECT 0x02FC +#define W_META_CREATEBITMAPINDIRECT 0x02FD +#define W_META_CREATEBITMAP 0x06FE +#define W_META_CREATEREGION 0x06FF + +//=================== Methoden von WMFReader ============================== + +inline Point WMFReader::ReadPoint() +{ + short nX, nY; + *pWMF >> nX >> nY; + return Point( nX, nY ); +} + +// ------------------------------------------------------------------------ + +inline Point WMFReader::ReadYX() +{ + short nX, nY; + *pWMF >> nY >> nX; + return Point( nX, nY ); +} + +// ------------------------------------------------------------------------ + +Rectangle WMFReader::ReadRectangle() +{ + Point aBR, aTL; + aBR = ReadYX(); + aTL = ReadYX(); + aBR.X()--; + aBR.Y()--; + return Rectangle( aTL, aBR ); +} + +// ------------------------------------------------------------------------ + +Size WMFReader::ReadYXExt() +{ + short nW, nH; + *pWMF >> nH >> nW; + return Size( nW, nH ); +} + +// ------------------------------------------------------------------------ + +void WMFReader::ReadRecordParams( USHORT nFunc ) +{ + switch( nFunc ) + { + case W_META_SETBKCOLOR: + { + pOut->SetBkColor( ReadColor() ); + } + break; + + case W_META_SETBKMODE: + { + USHORT nDat; + *pWMF >> nDat; + pOut->SetBkMode( nDat ); + } + break; + + // !!! + case W_META_SETMAPMODE: + { + sal_Int16 nMapMode; + *pWMF >> nMapMode; + pOut->SetMapMode( nMapMode ); + } + break; + + case W_META_SETROP2: + { + UINT16 nROP2; + *pWMF >> nROP2; + pOut->SetRasterOp( nROP2 ); + } + break; + + case W_META_SETTEXTCOLOR: + { + pOut->SetTextColor( ReadColor() ); + } + break; + + case W_META_SETWINDOWORG: + { + pOut->SetWinOrg( ReadYX() ); + } + break; + + case W_META_SETWINDOWEXT: + { + short nWidth, nHeight; + *pWMF >> nHeight >> nWidth; + pOut->SetWinExt( Size( nWidth, nHeight ) ); + } + break; + + case W_META_OFFSETWINDOWORG: + { + short nXAdd, nYAdd; + *pWMF >> nYAdd >> nXAdd; + pOut->SetWinOrgOffset( nXAdd, nYAdd ); + } + break; + + case W_META_SCALEWINDOWEXT: + { + short nXNum, nXDenom, nYNum, nYDenom; + *pWMF >> nYDenom >> nYNum >> nXDenom >> nXNum; + pOut->ScaleWinExt( (double)nXNum / nXDenom, (double)nYNum / nYDenom ); + } + break; + + case W_META_SETVIEWPORTORG: + case W_META_SETVIEWPORTEXT: + break; + + case W_META_OFFSETVIEWPORTORG: + { + short nXAdd, nYAdd; + *pWMF >> nYAdd >> nXAdd; + pOut->SetDevOrgOffset( nXAdd, nYAdd ); + } + break; + + case W_META_SCALEVIEWPORTEXT: + { + short nXNum, nXDenom, nYNum, nYDenom; + *pWMF >> nYDenom >> nYNum >> nXDenom >> nXNum; + pOut->ScaleDevExt( (double)nXNum / nXDenom, (double)nYNum / nYDenom ); + } + break; + + case W_META_LINETO: + { + pOut->LineTo( ReadYX() ); + } + break; + + case W_META_MOVETO: + { + pOut->MoveTo( ReadYX() ); + } + break; + + case W_META_INTERSECTCLIPRECT: + { + pOut->IntersectClipRect( ReadRectangle() ); + } + break; + + case W_META_RECTANGLE: + { + pOut->DrawRect( ReadRectangle() ); + } + break; + + case W_META_ROUNDRECT: + { + Size aSize( ReadYXExt() ); + pOut->DrawRoundRect( ReadRectangle(), Size( aSize.Width() / 2, aSize.Height() / 2 ) ); + } + break; + + case W_META_ELLIPSE: + { + pOut->DrawEllipse( ReadRectangle() ); + } + break; + + case W_META_ARC: + { + Point aEnd( ReadYX() ); + Point aStart( ReadYX() ); + Rectangle aRect( ReadRectangle() ); + aRect.Justify(); + pOut->DrawArc( aRect, aStart, aEnd ); + } + break; + + case W_META_PIE: + { + Point aEnd( ReadYX() ); + Point aStart( ReadYX() ); + Rectangle aRect( ReadRectangle() ); + aRect.Justify(); + + // #i73608# OutputDevice deviates from WMF + // semantics. start==end means full ellipse here. + if( aStart == aEnd ) + pOut->DrawEllipse( aRect ); + else + pOut->DrawPie( aRect, aStart, aEnd ); + } + break; + + case W_META_CHORD: + { + Point aEnd( ReadYX() ); + Point aStart( ReadYX() ); + Rectangle aRect( ReadRectangle() ); + aRect.Justify(); + pOut->DrawChord( aRect, aStart, aEnd ); + } + break; + + case W_META_POLYGON: + { + USHORT i,nPoints; + *pWMF >> nPoints; + Polygon aPoly( nPoints ); + for( i = 0; i < nPoints; i++ ) + aPoly[ i ] = ReadPoint(); + pOut->DrawPolygon( aPoly ); + } + break; + + case W_META_POLYPOLYGON: + { + USHORT i, nPoly, nPoints; + USHORT* pnPoints; + Point* pPtAry; + // Anzahl der Polygone: + *pWMF >> nPoly; + // Anzahl der Punkte eines jeden Polygons holen, Gesammtzahl der Punkte ermitteln: + pnPoints = new USHORT[ nPoly ]; + nPoints = 0; + for( i = 0; i < nPoly; i++ ) + { + *pWMF >> pnPoints[i]; + nPoints = nPoints + pnPoints[i]; + } + // Polygonpunkte holen: + pPtAry = (Point*) new char[ nPoints * sizeof(Point) ]; + for ( i = 0; i < nPoints; i++ ) + pPtAry[ i ] = ReadPoint(); + // PolyPolygon Actions erzeugen + PolyPolygon aPolyPoly( nPoly, pnPoints, pPtAry ); + pOut->DrawPolyPolygon( aPolyPoly ); + delete[] (char*) pPtAry; + delete[] pnPoints; + } + break; + + case W_META_POLYLINE: + { + USHORT i,nPoints; + *pWMF >> nPoints; + Polygon aPoly( nPoints ); + for( i = 0; i < nPoints; i++ ) + aPoly[ i ] = ReadPoint(); + pOut->DrawPolyLine( aPoly ); + } + break; + + case W_META_SAVEDC: + { + pOut->Push(); + } + break; + + case W_META_RESTOREDC: + { + pOut->Pop(); + } + break; + + case W_META_SETPIXEL: + { + const Color aColor = ReadColor(); + pOut->DrawPixel( ReadYX(), aColor ); + } + break; + + case W_META_OFFSETCLIPRGN: + { + pOut->MoveClipRegion( ReadYXExt() ); + } + break; + + case W_META_TEXTOUT: + { + USHORT nLength; + *pWMF >> nLength; + if ( nLength ) + { + char* pChar = new char[ ( nLength + 1 ) &~ 1 ]; + pWMF->Read( pChar, ( nLength + 1 ) &~ 1 ); + String aText( pChar, nLength, pOut->GetCharSet() ); + delete[] pChar; + Point aPosition( ReadYX() ); + pOut->DrawText( aPosition, aText ); + } + } + break; + + case W_META_EXTTEXTOUT: + { + sal_Int16 nDx, nDxTmp; + sal_uInt16 i, nLen, nOptions; + sal_Int32 nRecordPos, nRecordSize, nOriginalTextLen, nNewTextLen; + Point aPosition; + Rectangle aRect; + sal_Int32* pDXAry = NULL; + + pWMF->SeekRel(-6); + nRecordPos = pWMF->Tell(); + *pWMF >> nRecordSize; + pWMF->SeekRel(2); + aPosition = ReadYX(); + *pWMF >> nLen >> nOptions; + + sal_Int32 nTextLayoutMode = TEXT_LAYOUT_DEFAULT; + if ( nOptions & ETO_RTLREADING ) + nTextLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT; + pOut->SetTextLayoutMode( nTextLayoutMode ); + DBG_ASSERT( ( nOptions & ( ETO_PDY | ETO_GLYPH_INDEX ) ) == 0, "SJ: ETO_PDY || ETO_GLYPH_INDEX in WMF" ); + + // Nur wenn der Text auch Zeichen enthaelt, macht die Ausgabe Sinn + if( nLen ) + { + nOriginalTextLen = nLen; + if( nOptions & ETO_CLIPPED ) + { + const Point aPt1( ReadPoint() ); + const Point aPt2( ReadPoint() ); + aRect = Rectangle( aPt1, aPt2 ); + } + char* pChar = new char[ ( nOriginalTextLen + 1 ) &~ 1 ]; + pWMF->Read( pChar, ( nOriginalTextLen + 1 ) &~ 1 ); + String aText( pChar, (sal_uInt16)nOriginalTextLen, pOut->GetCharSet() );// after this conversion the text may contain + nNewTextLen = aText.Len(); // less character (japanese version), so the + delete[] pChar; // dxAry will not fit + + if ( nNewTextLen ) + { + sal_uInt32 nMaxStreamPos = nRecordPos + ( nRecordSize << 1 ); + sal_Int32 nDxArySize = nMaxStreamPos - pWMF->Tell(); + sal_Int32 nDxAryEntries = nDxArySize >> 1; + sal_Bool bUseDXAry = FALSE; + + if ( ( ( nDxAryEntries % nOriginalTextLen ) == 0 ) && ( nNewTextLen <= nOriginalTextLen ) ) + { + pDXAry = new sal_Int32[ nNewTextLen ]; + for ( i = 0; i < nNewTextLen; i++ ) + { + if ( pWMF->Tell() >= nMaxStreamPos ) + break; + *pWMF >> nDx; + if ( nNewTextLen != nOriginalTextLen ) + { + ByteString aTmp( aText.GetChar( i ), pOut->GetCharSet() ); + if ( aTmp.Len() > 1 ) + { + sal_Int32 nDxCount = aTmp.Len() - 1; + if ( ( ( nDxCount * 2 ) + pWMF->Tell() ) > nMaxStreamPos ) + break; + while ( nDxCount-- ) + { + *pWMF >> nDxTmp; + nDx = nDx + nDxTmp; + } + } + } + pDXAry[ i ] = nDx; + } + if ( i == nNewTextLen ) + bUseDXAry = TRUE; + } + if ( pDXAry && bUseDXAry ) + pOut->DrawText( aPosition, aText, pDXAry ); + else + pOut->DrawText( aPosition, aText ); + } + } + delete[] pDXAry; + + } + break; + + case W_META_SELECTOBJECT: + { + INT16 nObjIndex; + *pWMF >> nObjIndex; + pOut->SelectObject( nObjIndex ); + } + break; + + case W_META_SETTEXTALIGN: + { + UINT16 nAlign; + *pWMF >> nAlign; + pOut->SetTextAlign( nAlign ); + } + break; + + case W_META_BITBLT: + { + // 0-3 : nWinROP #93454# + // 4-5 : y offset of source bitmap + // 6-7 : x offset of source bitmap + // 8-9 : used height of source bitmap + // 10-11 : used width of source bitmap + // 12-13 : destination position y (in pixel) + // 14-15 : destination position x (in pixel) + // 16-17 : dont know + // 18-19 : Width Bitmap in Pixel + // 20-21 : Height Bitmap in Pixel + // 22-23 : bytes per scanline + // 24 : planes + // 25 : bitcount + + sal_Int32 nWinROP; + sal_uInt16 nSx, nSy, nSxe, nSye, nDontKnow, nWidth, nHeight, nBytesPerScan; + sal_uInt8 nPlanes, nBitCount; + + *pWMF >> nWinROP + >> nSy >> nSx >> nSye >> nSxe; + Point aPoint( ReadYX() ); + *pWMF >> nDontKnow >> nWidth >> nHeight >> nBytesPerScan >> nPlanes >> nBitCount; + + if ( nWidth && nHeight && ( nPlanes == 1 ) && ( nBitCount == 1 ) ) + { + Bitmap aBmp( Size( nWidth, nHeight ), nBitCount ); + BitmapWriteAccess* pAcc; + pAcc = aBmp.AcquireWriteAccess(); + if ( pAcc ) + { + sal_uInt16 y, x, scan; + sal_Int8 i, nEightPixels; + for ( y = 0; y < nHeight; y++ ) + { + x = 0; + for ( scan = 0; scan < nBytesPerScan; scan++ ) + { + *pWMF >> nEightPixels; + for ( i = 7; i >= 0; i-- ) + { + if ( x < nWidth ) + { + pAcc->SetPixel( y, x, (nEightPixels>>i)&1 ); + } + x++; + } + } + } + aBmp.ReleaseAccess( pAcc ); + if ( nSye && nSxe && + ( ( nSx + nSxe ) <= aBmp.GetSizePixel().Width() ) && + ( ( nSy + nSye <= aBmp.GetSizePixel().Height() ) ) ) + { + Rectangle aCropRect( Point( nSx, nSy ), Size( nSxe, nSye ) ); + aBmp.Crop( aCropRect ); + } + Rectangle aDestRect( aPoint, Size( nSxe, nSye ) ); + aBmpSaveList.Insert( new BSaveStruct( aBmp, aDestRect, nWinROP ), LIST_APPEND ); + } + } + } + break; + + case W_META_STRETCHBLT: + case W_META_DIBBITBLT: + case W_META_DIBSTRETCHBLT: + case W_META_STRETCHDIB: + { + sal_Int32 nWinROP; + sal_uInt16 nSx, nSy, nSxe, nSye, nUsage; + Bitmap aBmp; + + *pWMF >> nWinROP; + + if( nFunc == W_META_STRETCHDIB ) + *pWMF >> nUsage; + + // nSye and nSxe is the number of pixels that has to been used + if( nFunc == W_META_STRETCHDIB || nFunc == W_META_STRETCHBLT || nFunc == W_META_DIBSTRETCHBLT ) + *pWMF >> nSye >> nSxe; + else + nSye = nSxe = 0; // set this to zero as indicator not to scale the bitmap later + + // nSy and nx is the offset of the first pixel + *pWMF >> nSy >> nSx; + + if( nFunc == W_META_STRETCHDIB || nFunc == W_META_DIBBITBLT || nFunc == W_META_DIBSTRETCHBLT ) + { + if ( nWinROP == PATCOPY ) + *pWMF >> nUsage; // i don't know anything of this parameter, so its called nUsage + // pOut->DrawRect( Rectangle( ReadYX(), aDestSize ), FALSE ); + + Size aDestSize( ReadYXExt() ); + if ( aDestSize.Width() && aDestSize.Height() ) // #92623# do not try to read buggy bitmaps + { + Rectangle aDestRect( ReadYX(), aDestSize ); + if ( nWinROP != PATCOPY ) + aBmp.Read( *pWMF, FALSE ); + + // test if it is sensible to crop + if ( nSye && nSxe && + ( ( nSx + nSxe ) <= aBmp.GetSizePixel().Width() ) && + ( ( nSy + nSye <= aBmp.GetSizePixel().Height() ) ) ) + { + Rectangle aCropRect( Point( nSx, nSy ), Size( nSxe, nSye ) ); + aBmp.Crop( aCropRect ); + } + aBmpSaveList.Insert( new BSaveStruct( aBmp, aDestRect, nWinROP ), LIST_APPEND ); + } + } + } + break; + + case W_META_DIBCREATEPATTERNBRUSH: + { + Bitmap aBmp; + BitmapReadAccess* pBmp; + UINT32 nRed = 0, nGreen = 0, nBlue = 0, nCount = 1; + UINT16 nFunction; + + *pWMF >> nFunction >> nFunction; + + aBmp.Read( *pWMF, FALSE ); + pBmp = aBmp.AcquireReadAccess(); + if ( pBmp ) + { + for ( INT32 y = 0; y < pBmp->Height(); y++ ) + { + for ( INT32 x = 0; x < pBmp->Width(); x++ ) + { + const BitmapColor aColor( pBmp->GetColor( y, x ) ); + + nRed += aColor.GetRed(); + nGreen += aColor.GetGreen(); + nBlue += aColor.GetBlue(); + } + } + nCount = pBmp->Height() * pBmp->Width(); + if ( !nCount ) + nCount++; + aBmp.ReleaseAccess( pBmp ); + } + Color aColor( (BYTE)( nRed / nCount ), (BYTE)( nGreen / nCount ), (BYTE)( nBlue / nCount ) ); + pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( aColor, FALSE ) ); + } + break; + + case W_META_DELETEOBJECT: + { + INT16 nIndex; + *pWMF >> nIndex; + pOut->DeleteObject( nIndex ); + } + break; + + case W_META_CREATEPALETTE: + { + pOut->CreateObject( GDI_DUMMY ); + } + break; + + case W_META_CREATEBRUSH: + { + pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ), FALSE ) ); + } + break; + + case W_META_CREATEPATTERNBRUSH: + { + pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ), FALSE ) ); + } + break; + + case W_META_CREATEPENINDIRECT: + { + LineInfo aLineInfo; + USHORT nStyle, nWidth, nHeight; + + *pWMF >> nStyle >> nWidth >> nHeight; + + if ( nWidth ) + aLineInfo.SetWidth( nWidth ); + + BOOL bTransparent = FALSE; + UINT16 nDashCount = 0; + UINT16 nDotCount = 0; + switch( nStyle ) + { + case PS_DASHDOTDOT : + nDotCount++; + case PS_DASHDOT : + nDashCount++; + case PS_DOT : + nDotCount++; + break; + case PS_DASH : + nDashCount++; + break; + case PS_NULL : + bTransparent = TRUE; + aLineInfo.SetStyle( LINE_NONE ); + break; + default : + case PS_INSIDEFRAME : + case PS_SOLID : + aLineInfo.SetStyle( LINE_SOLID ); + } + if ( nDashCount | nDotCount ) + { + aLineInfo.SetStyle( LINE_DASH ); + aLineInfo.SetDashCount( nDashCount ); + aLineInfo.SetDotCount( nDotCount ); + } + pOut->CreateObject( GDI_PEN, new WinMtfLineStyle( ReadColor(), aLineInfo, bTransparent ) ); + } + break; + + case W_META_CREATEBRUSHINDIRECT: + { + USHORT nStyle; + *pWMF >> nStyle; + pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( ReadColor(), ( nStyle == BS_HOLLOW ) ? TRUE : FALSE ) ); + } + break; + + case W_META_CREATEFONTINDIRECT: + { + Size aFontSize; + char lfFaceName[ LF_FACESIZE ]; + INT16 lfEscapement, lfOrientation, lfWeight; // ( ehemals USHORT ) + + LOGFONTW aLogFont; + aFontSize = ReadYXExt(); + *pWMF >> lfEscapement >> lfOrientation >> lfWeight + >> aLogFont.lfItalic >> aLogFont.lfUnderline >> aLogFont.lfStrikeOut >> aLogFont.lfCharSet >> aLogFont.lfOutPrecision + >> aLogFont.lfClipPrecision >> aLogFont.lfQuality >> aLogFont.lfPitchAndFamily; + pWMF->Read( lfFaceName, LF_FACESIZE ); + aLogFont.lfWidth = aFontSize.Width(); + aLogFont.lfHeight = aFontSize.Height(); + aLogFont.lfEscapement = lfEscapement; + aLogFont.lfOrientation = lfOrientation; + aLogFont.lfWeight = lfWeight; + + CharSet eCharSet; + if ( ( aLogFont.lfCharSet == OEM_CHARSET ) || ( aLogFont.lfCharSet == DEFAULT_CHARSET ) ) + eCharSet = gsl_getSystemTextEncoding(); + else + eCharSet = rtl_getTextEncodingFromWindowsCharset( aLogFont.lfCharSet ); + if ( eCharSet == RTL_TEXTENCODING_DONTKNOW ) + eCharSet = gsl_getSystemTextEncoding(); + if ( eCharSet == RTL_TEXTENCODING_SYMBOL ) + eCharSet = RTL_TEXTENCODING_MS_1252; + aLogFont.alfFaceName = UniString( lfFaceName, eCharSet ); + + pOut->CreateObject( GDI_FONT, new WinMtfFontStyle( aLogFont ) ); + } + break; + + case W_META_CREATEBITMAPINDIRECT: + { + pOut->CreateObject( GDI_DUMMY ); + } + break; + + case W_META_CREATEBITMAP: + { + pOut->CreateObject( GDI_DUMMY ); + } + break; + + case W_META_CREATEREGION: + { + pOut->CreateObject( GDI_DUMMY ); + } + break; + + case W_META_EXCLUDECLIPRECT : + { + pOut->ExcludeClipRect( ReadRectangle() ); + } + break; + + case W_META_PATBLT: + { + UINT32 nROP, nOldROP; + *pWMF >> nROP; + Size aSize = ReadYXExt(); + nOldROP = pOut->SetRasterOp( nROP ); + pOut->DrawRect( Rectangle( ReadYX(), aSize ), FALSE ); + pOut->SetRasterOp( nOldROP ); + } + break; + + case W_META_SELECTCLIPREGION: + { + sal_Int16 nObjIndex; + *pWMF >> nObjIndex; + if ( !nObjIndex ) + { + PolyPolygon aEmptyPolyPoly; + pOut->SetClipPath( aEmptyPolyPoly, RGN_COPY, sal_True ); + } + } + break; + + case W_META_ESCAPE : + { + // nRecSize has been checked previously to be greater than 3 + sal_uInt64 nMetaRecSize = static_cast< sal_uInt64 >( nRecSize - 2 ) * 2; + sal_uInt64 nMetaRecEndPos = pWMF->Tell() + nMetaRecSize; + + // taking care that nRecSize does not exceed the maximal stream position + if ( nMetaRecEndPos > nEndPos ) + { + pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); + break; + } + if ( nRecSize >= 4 ) // minimal escape lenght + { + sal_uInt16 nMode, nLen; + *pWMF >> nMode + >> nLen; + if ( ( nMode == W_MFCOMMENT ) && ( nLen >= 4 ) ) + { + sal_uInt32 nNewMagic; // we have to read int32 for + *pWMF >> nNewMagic; // META_ESCAPE_ENHANCED_METAFILE CommentIdentifier + + if( nNewMagic == 0x2c2a4f4f && nLen >= 14 ) + { + sal_uInt16 nMagic2; + *pWMF >> nMagic2; + if( nMagic2 == 0x0a ) // 2nd half of magic + { // continue with private escape + sal_uInt32 nCheck, nEsc; + *pWMF >> nCheck + >> nEsc; + + sal_uInt32 nEscLen = nLen - 14; + if ( nEscLen <= ( nRecSize * 2 ) ) + { +#ifdef OSL_BIGENDIAN + sal_uInt32 nTmp = SWAPLONG( nEsc ); + sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 ); +#else + sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 ); +#endif + sal_Int8* pData = NULL; + + if ( ( static_cast< sal_uInt64 >( nEscLen ) + pWMF->Tell() ) > nMetaRecEndPos ) + { + pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); + break; + } + if ( nEscLen > 0 ) + { + pData = new sal_Int8[ nEscLen ]; + pWMF->Read( pData, nEscLen ); + nCheckSum = rtl_crc32( nCheckSum, pData, nEscLen ); + } + if ( nCheck == nCheckSum ) + { + switch( nEsc ) + { + case PRIVATE_ESCAPE_UNICODE : + { // we will use text instead of polygons only if we have the correct font + if ( aVDev.IsFontAvailable( pOut->GetFont().GetName() ) ) + { + Point aPt; + String aString; + sal_uInt32 i, nStringLen, nDXCount; + sal_Int32* pDXAry = NULL; + SvMemoryStream aMemoryStream( nEscLen ); + aMemoryStream.Write( pData, nEscLen ); + aMemoryStream.Seek( STREAM_SEEK_TO_BEGIN ); + aMemoryStream >> aPt.X() + >> aPt.Y() + >> nStringLen; + + if ( ( static_cast< sal_uInt64 >( nStringLen ) * sizeof( sal_Unicode ) ) < ( nEscLen - aMemoryStream.Tell() ) ) + { + sal_Unicode* pBuf = aString.AllocBuffer( (xub_StrLen)nStringLen ); + for ( i = 0; i < nStringLen; i++ ) + aMemoryStream >> pBuf[ i ]; + aMemoryStream >> nDXCount; + if ( ( static_cast< sal_uInt64 >( nDXCount ) * sizeof( sal_Int32 ) ) >= ( nEscLen - aMemoryStream.Tell() ) ) + nDXCount = 0; + if ( nDXCount ) + pDXAry = new sal_Int32[ nDXCount ]; + for ( i = 0; i < nDXCount; i++ ) + aMemoryStream >> pDXAry[ i ]; + aMemoryStream >> nSkipActions; + pOut->DrawText( aPt, aString, pDXAry ); + delete[] pDXAry; + } + } + } + break; + } + } + delete[] pData; + } + } + } + else if ( (nNewMagic == static_cast< sal_uInt32 >(0x43464D57)) && (nLen >= 34) && ( (sal_Int32)(nLen + 10) <= (sal_Int32)(nRecSize * 2) )) + { + sal_uInt32 nComType, nVersion, nFlags, nComRecCount, + nCurRecSize, nRemainingSize, nEMFTotalSize; + sal_uInt16 nCheck; + + *pWMF >> nComType >> nVersion >> nCheck >> nFlags + >> nComRecCount >> nCurRecSize + >> nRemainingSize >> nEMFTotalSize; // the nRemainingSize is not mentioned in MSDN documentation + // but it seems to be required to read in data produced by OLE + + if( nComType == 0x01 && nVersion == 0x10000 && nComRecCount ) + { + if( !nEMFRec ) + { // first EMF comment + nEMFRecCount = nComRecCount; + nEMFSize = nEMFTotalSize; + pEMFStream = new SvMemoryStream( nEMFSize ); + } + else if( ( nEMFRecCount != nComRecCount ) || ( nEMFSize != nEMFTotalSize ) ) // add additional checks here + { + // total records should be the same as in previous comments + nEMFRecCount = 0xFFFFFFFF; + delete pEMFStream; + pEMFStream = NULL; + } + nEMFRec++; + + if( pEMFStream && nCurRecSize + 34 > nLen ) + { + nEMFRecCount = 0xFFFFFFFF; + delete pEMFStream; + pEMFStream = NULL; + } + + if( pEMFStream ) + { + sal_Int8* pBuf = new sal_Int8[ nCurRecSize ]; + sal_uInt32 nCount = pWMF->Read( pBuf, nCurRecSize ); + if( nCount == nCurRecSize ) + pEMFStream->Write( pBuf, nCount ); + delete[] pBuf; + } + } + } + } + } + } + break; + + case W_META_SETRELABS: + case W_META_SETPOLYFILLMODE: + case W_META_SETSTRETCHBLTMODE: + case W_META_SETTEXTCHAREXTRA: + case W_META_SETTEXTJUSTIFICATION: + case W_META_FLOODFILL : + case W_META_FILLREGION: + case W_META_FRAMEREGION: + case W_META_INVERTREGION: + case W_META_PAINTREGION: + case W_META_DRAWTEXT: + case W_META_SETMAPPERFLAGS: + case W_META_SETDIBTODEV: + case W_META_SELECTPALETTE: + case W_META_REALIZEPALETTE: + case W_META_ANIMATEPALETTE: + case W_META_SETPALENTRIES: + case W_META_RESIZEPALETTE: + case W_META_EXTFLOODFILL: + case W_META_RESETDC: + case W_META_STARTDOC: + case W_META_STARTPAGE: + case W_META_ENDPAGE: + case W_META_ABORTDOC: + case W_META_ENDDOC: + break; + } +} + +// ------------------------------------------------------------------------ + +BOOL WMFReader::ReadHeader() +{ + Rectangle aPlaceableBound; + sal_uInt32 nl, nStrmPos = pWMF->Tell(); + + // Einlesen des METAFILEHEADER, falls vorhanden + *pWMF >> nl; + + Size aWMFSize; + if ( nl == 0x9ac6cdd7L ) + { + INT16 nVal; + + // hmf (Unused) ueberlesen wir + pWMF->SeekRel(2); + + // BoundRect + *pWMF >> nVal; aPlaceableBound.Left() = nVal; + *pWMF >> nVal; aPlaceableBound.Top() = nVal; + *pWMF >> nVal; aPlaceableBound.Right() = nVal; + *pWMF >> nVal; aPlaceableBound.Bottom() = nVal; + + // inch + *pWMF >> nUnitsPerInch; + + // reserved + pWMF->SeekRel( 4 ); + + // checksum pruefen wir lieber nicht + pWMF->SeekRel( 2 ); + } + else + { + nUnitsPerInch = 96; + pWMF->Seek( nStrmPos + 18 ); // set the streampos to the start of the the metaactions + GetPlaceableBound( aPlaceableBound, pWMF ); + pWMF->Seek( nStrmPos ); + } + + pOut->SetWinOrg( aPlaceableBound.TopLeft() ); + aWMFSize = Size( labs( aPlaceableBound.GetWidth() ), labs( aPlaceableBound.GetHeight() ) ); + pOut->SetWinExt( aWMFSize ); + + Size aDevExt( 10000, 10000 ); + if( ( labs( aWMFSize.Width() ) > 1 ) && ( labs( aWMFSize.Height() ) > 1 ) ) + { + const Fraction aFrac( 1, nUnitsPerInch ); + MapMode aWMFMap( MAP_INCH, Point(), aFrac, aFrac ); + Size aSize100( OutputDevice::LogicToLogic( aWMFSize, aWMFMap, MAP_100TH_MM ) ); + aDevExt = Size( labs( aSize100.Width() ), labs( aSize100.Height() ) ); + } + pOut->SetDevExt( aDevExt ); + + // Einlesen des METAHEADER + *pWMF >> nl; // Typ und Headergroesse + + if( nl != 0x00090001 ) + { + pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); + return FALSE; + } + + pWMF->SeekRel( 2 ); // Version (von Windows) + pWMF->SeekRel( 4 ); // Size (der Datei in Words) + pWMF->SeekRel( 2 ); // NoObjects (Maximale Anzahl der gleichzeitigen Objekte) + pWMF->SeekRel( 4 ); // MaxRecord (Groesse des groessten Records in Words) + pWMF->SeekRel( 2 ); // NoParameters (Unused + + return TRUE; +} + +void WMFReader::ReadWMF() +{ + USHORT nFunction; + ULONG nPos, nPercent, nLastPercent; + + nSkipActions = 0; + nCurrentAction = 0; + nUnicodeEscapeAction = 0; + + pEMFStream = NULL; + nEMFRecCount = 0; + nEMFRec = 0; + nEMFSize = 0; + + pOut->SetMapMode( MM_ANISOTROPIC ); + pOut->SetWinOrg( Point() ); + pOut->SetWinExt( Size( 1, 1 ) ); + pOut->SetDevExt( Size( 10000, 10000 ) ); + + nEndPos=pWMF->Seek( STREAM_SEEK_TO_END ); + pWMF->Seek( nStartPos ); + Callback( (USHORT) ( nLastPercent = 0 ) ); + + if ( ReadHeader() ) + { + + nPos = pWMF->Tell(); + + if( nEndPos - nStartPos ) + { + while( TRUE ) + { + nCurrentAction++; + nPercent = ( nPos - nStartPos ) * 100 / ( nEndPos - nStartPos ); + + if( nLastPercent + 4 <= nPercent ) + { + Callback( (USHORT) nPercent ); + nLastPercent = nPercent; + } + *pWMF >> nRecSize >> nFunction; + + if( pWMF->GetError() || ( nRecSize < 3 ) || ( nRecSize==3 && nFunction==0 ) || pWMF->IsEof() ) + { + + if( pWMF->IsEof() ) + pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); + + break; + } + if( aBmpSaveList.Count() && + ( nFunction != W_META_STRETCHDIB ) && + ( nFunction != W_META_DIBBITBLT ) && + ( nFunction != W_META_DIBSTRETCHBLT ) ) + { + pOut->ResolveBitmapActions( aBmpSaveList ); + } + if ( !nSkipActions ) + ReadRecordParams( nFunction ); + else + nSkipActions--; + + if( pEMFStream && nEMFRecCount == nEMFRec ) + { + GDIMetaFile aMeta; + pEMFStream->Seek( 0 ); + EnhWMFReader* pEMFReader = new EnhWMFReader ( *pEMFStream, aMeta ); + BOOL bRead = pEMFReader->ReadEnhWMF(); + delete pEMFReader; // destroy first!!! + + if( bRead ) + { + pOut->AddFromGDIMetaFile( aMeta ); + pOut->SetrclFrame( Rectangle(0, 0, aMeta.GetPrefSize().Width(), aMeta.GetPrefSize().Height() )); + // we have successfully read the embedded EMF data + // no need to process WMF data further + break; + } + else + { + // something went wrong + // continue with WMF, don't try this again + delete pEMFStream; + pEMFStream = NULL; + } + + } + + nPos += nRecSize * 2; + if ( nPos <= nEndPos ) + pWMF->Seek( nPos ); + else + pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); + + } + } + else + pWMF->SetError( SVSTREAM_GENERALERROR ); + + if( !pWMF->GetError() && aBmpSaveList.Count() ) + pOut->ResolveBitmapActions( aBmpSaveList ); + } + if ( pWMF->GetError() ) + pWMF->Seek( nStartPos ); +} + +// ------------------------------------------------------------------------ + +static void GetWinExtMax( const Point& rSource, Rectangle& rPlaceableBound, const sal_Int16 nMapMode ) +{ + Point aSource( rSource ); + if ( nMapMode == MM_HIMETRIC ) + aSource.Y() = -rSource.Y(); + if ( aSource.X() < rPlaceableBound.Left() ) + rPlaceableBound.Left() = aSource.X(); + if ( aSource.X() > rPlaceableBound.Right() ) + rPlaceableBound.Right() = aSource.X(); + if ( aSource.Y() < rPlaceableBound.Top() ) + rPlaceableBound.Top() = aSource.Y(); + if ( aSource.Y() > rPlaceableBound.Bottom() ) + rPlaceableBound.Bottom() = aSource.Y(); +} + +static void GetWinExtMax( const Rectangle& rSource, Rectangle& rPlaceableBound, const sal_Int16 nMapMode ) +{ + GetWinExtMax( rSource.TopLeft(), rPlaceableBound, nMapMode ); + GetWinExtMax( rSource.BottomRight(), rPlaceableBound, nMapMode ); +} + +sal_Bool WMFReader::GetPlaceableBound( Rectangle& rPlaceableBound, SvStream* pStm ) +{ + sal_Bool bRet = sal_True; + + rPlaceableBound.Left() = (sal_Int32)0x7fffffff; + rPlaceableBound.Top() = (sal_Int32)0x7fffffff; + rPlaceableBound.Right() = (sal_Int32)0x80000000; + rPlaceableBound.Bottom() = (sal_Int32)0x80000000; + + sal_Int16 nMapMode = MM_ANISOTROPIC; + + sal_uInt16 nFunction; + sal_uInt32 nRSize; + sal_uInt32 nPos = pStm->Tell(); + sal_uInt32 nEnd = pStm->Seek( STREAM_SEEK_TO_END ); + + pStm->Seek( nPos ); + + if( nEnd - nPos ) + { + while( bRet ) + { + *pStm >> nRSize >> nFunction; + + if( pStm->GetError() || ( nRSize < 3 ) || ( nRSize==3 && nFunction==0 ) || pStm->IsEof() ) + { + if( pStm->IsEof() ) + { + pStm->SetError( SVSTREAM_FILEFORMAT_ERROR ); + bRet = sal_False; + } + break; + } + switch( nFunction ) + { + case W_META_SETWINDOWORG: + { + Point aWinOrg; + aWinOrg = ReadYX(); + rPlaceableBound.SetPos( aWinOrg ); + } + break; + + case W_META_SETWINDOWEXT: + { + Point aPos0( 0, 0 ); + sal_Int16 nWidth, nHeight; + *pStm >> nHeight >> nWidth; + rPlaceableBound.SetSize( Size( nWidth, nHeight ) ); + } + break; + + case W_META_SETMAPMODE : + *pStm >> nMapMode; + break; + + case W_META_MOVETO: + case W_META_LINETO: + GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode ); + break; + + case W_META_RECTANGLE: + case W_META_INTERSECTCLIPRECT: + case W_META_EXCLUDECLIPRECT : + case W_META_ELLIPSE: + GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode ); + break; + + case W_META_ROUNDRECT: + { + Size aSize( ReadYXExt() ); + GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode ); + } + break; + + case W_META_ARC: + case W_META_PIE: + case W_META_CHORD: + { + Point aEnd( ReadYX() ); + Point aStart( ReadYX() ); + GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode ); + } + break; + + case W_META_POLYGON: + { + USHORT i,nPoints; + *pStm >> nPoints; + for( i = 0; i < nPoints; i++ ) + GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode ); + } + break; + + case W_META_POLYPOLYGON: + { + USHORT i, nPoly, nPoints = 0; + *pStm >> nPoly; + for( i = 0; i < nPoly; i++ ) + { + sal_uInt16 nP; + *pStm >> nP; + nPoints = nPoints + nP; + } + for ( i = 0; i < nPoints; i++ ) + GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode ); + } + break; + + case W_META_POLYLINE: + { + USHORT i,nPoints; + *pStm >> nPoints; + for( i = 0; i < nPoints; i++ ) + GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode ); + } + break; + + case W_META_SETPIXEL: + { + const Color aColor = ReadColor(); + GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode ); + } + break; + + case W_META_TEXTOUT: + { + USHORT nLength; + *pStm >> nLength; + // todo: we also have to take care of the text width + if ( nLength ) + { + pStm->SeekRel( ( nLength + 1 ) &~ 1 ); + GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode ); + } + } + break; + + case W_META_EXTTEXTOUT: + { + sal_uInt16 nLen, nOptions; + sal_Int32 nRecordPos, nRecordSize; + Point aPosition; + Rectangle aRect; + + pStm->SeekRel(-6); + nRecordPos = pStm->Tell(); + *pStm >> nRecordSize; + pStm->SeekRel(2); + aPosition = ReadYX(); + *pStm >> nLen >> nOptions; + // todo: we also have to take care of the text width + if( nLen ) + GetWinExtMax( aPosition, rPlaceableBound, nMapMode ); + } + break; + case W_META_BITBLT: + case W_META_STRETCHBLT: + case W_META_DIBBITBLT: + case W_META_DIBSTRETCHBLT: + case W_META_STRETCHDIB: + { + sal_Int32 nWinROP; + sal_uInt16 nSx, nSy, nSxe, nSye, nUsage; + *pStm >> nWinROP; + + if( nFunction == W_META_STRETCHDIB ) + *pStm >> nUsage; + + // nSye and nSxe is the number of pixels that has to been used + if( nFunction == W_META_STRETCHDIB || nFunction == W_META_STRETCHBLT || nFunction == W_META_DIBSTRETCHBLT ) + *pStm >> nSye >> nSxe; + else + nSye = nSxe = 0; // set this to zero as indicator not to scale the bitmap later + + // nSy and nx is the offset of the first pixel + *pStm >> nSy >> nSx; + + if( nFunction == W_META_STRETCHDIB || nFunction == W_META_DIBBITBLT || nFunction == W_META_DIBSTRETCHBLT ) + { + if ( nWinROP == PATCOPY ) + *pStm >> nUsage; // i don't know anything of this parameter, so its called nUsage + // pOut->DrawRect( Rectangle( ReadYX(), aDestSize ), FALSE ); + + Size aDestSize( ReadYXExt() ); + if ( aDestSize.Width() && aDestSize.Height() ) // #92623# do not try to read buggy bitmaps + { + Rectangle aDestRect( ReadYX(), aDestSize ); + GetWinExtMax( aDestRect, rPlaceableBound, nMapMode ); + } + } + } + break; + + case W_META_PATBLT: + { + UINT32 nROP; + *pStm >> nROP; + Size aSize = ReadYXExt(); + GetWinExtMax( Rectangle( ReadYX(), aSize ), rPlaceableBound, nMapMode ); + } + break; + } + nPos += nRSize * 2; + if ( nPos <= nEnd ) + pStm->Seek( nPos ); + else + { + pStm->SetError( SVSTREAM_FILEFORMAT_ERROR ); + bRet = sal_False; + } + + } + } + else + { + pStm->SetError( SVSTREAM_GENERALERROR ); + bRet = sal_False; + } + return bRet; +} + +WMFReader::~WMFReader() +{ + if( pEMFStream ) + delete pEMFStream; +} + diff --git a/svtools/source/filter.vcl/wmf/wmf.cxx b/svtools/source/filter.vcl/wmf/wmf.cxx new file mode 100644 index 000000000000..25ca9f721b33 --- /dev/null +++ b/svtools/source/filter.vcl/wmf/wmf.cxx @@ -0,0 +1,114 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +#include "winmtf.hxx" +#include "emfwr.hxx" +#include "wmfwr.hxx" +#include <svtools/wmf.hxx> + +// ----------------------------------------------------------------------------- + +BOOL ConvertWMFToGDIMetaFile( SvStream & rStreamWMF, GDIMetaFile & rGDIMetaFile, FilterConfigItem* pConfigItem ) +{ + UINT32 nMetaType; + UINT32 nOrgPos = rStreamWMF.Tell(); + UINT16 nOrigNumberFormat = rStreamWMF.GetNumberFormatInt(); + rStreamWMF.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + rStreamWMF.Seek( 0x28 ); + rStreamWMF >> nMetaType; + rStreamWMF.Seek( nOrgPos ); + if ( nMetaType == 0x464d4520 ) + { + if ( EnhWMFReader( rStreamWMF, rGDIMetaFile, pConfigItem ).ReadEnhWMF() == FALSE ) + rStreamWMF.SetError( SVSTREAM_FILEFORMAT_ERROR ); + } + else + { + WMFReader( rStreamWMF, rGDIMetaFile, pConfigItem ).ReadWMF(); + } + rStreamWMF.SetNumberFormatInt( nOrigNumberFormat ); + return !rStreamWMF.GetError(); +} + +// ----------------------------------------------------------------------------- + +BOOL ReadWindowMetafile( SvStream& rStream, GDIMetaFile& rMTF, FilterConfigItem* pFilterConfigItem ) +{ + UINT32 nMetaType; + UINT32 nOrgPos = rStream.Tell(); + UINT16 nOrigNumberFormat = rStream.GetNumberFormatInt(); + rStream.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + rStream.Seek( 0x28 ); + rStream >> nMetaType; + rStream.Seek( nOrgPos ); + if ( nMetaType == 0x464d4520 ) + { + if ( EnhWMFReader( rStream, rMTF, NULL ).ReadEnhWMF() == FALSE ) + rStream.SetError( SVSTREAM_FILEFORMAT_ERROR ); + } + else + { + WMFReader( rStream, rMTF, pFilterConfigItem ).ReadWMF(); + } + rStream.SetNumberFormatInt( nOrigNumberFormat ); + return !rStream.GetError(); +} + +// ----------------------------------------------------------------------------- + +BOOL ConvertGDIMetaFileToWMF( const GDIMetaFile & rMTF, SvStream & rTargetStream, + FilterConfigItem* pConfigItem, BOOL bPlaceable) +{ + WMFWriter aWMFWriter; + return aWMFWriter.WriteWMF( rMTF, rTargetStream, pConfigItem, bPlaceable ); +} + +// ----------------------------------------------------------------------------- + +BOOL ConvertGDIMetaFileToEMF( const GDIMetaFile & rMTF, SvStream & rTargetStream, + FilterConfigItem* pConfigItem ) +{ + EMFWriter aEMFWriter; + return aEMFWriter.WriteEMF( rMTF, rTargetStream, pConfigItem ); +} + +// ----------------------------------------------------------------------------- + +BOOL WriteWindowMetafile( SvStream& rStream, const GDIMetaFile& rMTF ) +{ + return WMFWriter().WriteWMF( rMTF, rStream, NULL ); +} + +// ----------------------------------------------------------------------------- + +BOOL WriteWindowMetafileBits( SvStream& rStream, const GDIMetaFile& rMTF ) +{ + return WMFWriter().WriteWMF( rMTF, rStream, NULL, FALSE ); +} diff --git a/svtools/source/filter.vcl/wmf/wmfwr.cxx b/svtools/source/filter.vcl/wmf/wmfwr.cxx new file mode 100644 index 000000000000..4dff9732c7d0 --- /dev/null +++ b/svtools/source/filter.vcl/wmf/wmfwr.cxx @@ -0,0 +1,2096 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +#include <vcl/salbtype.hxx> +#include "wmfwr.hxx" +#include <unotools/fontcvt.hxx> +#include "emfwr.hxx" +#include <rtl/crc.h> +#include <rtl/tencinfo.h> +#include <tools/tenccvt.hxx> +#include <osl/endian.h> +#ifndef INCLUDED_I18NUTIL_UNICODE_HXX +#include <i18nutil/unicode.hxx> //unicode::getUnicodeScriptType +#endif + +#include <vcl/metric.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> + +//====================== MS-Windows-defines =============================== + +#define W_META_SETBKCOLOR 0x0201 +#define W_META_SETBKMODE 0x0102 +#define W_META_SETMAPMODE 0x0103 +#define W_META_SETROP2 0x0104 +#define W_META_SETRELABS 0x0105 +#define W_META_SETPOLYFILLMODE 0x0106 +#define W_META_SETSTRETCHBLTMODE 0x0107 +#define W_META_SETTEXTCHAREXTRA 0x0108 +#define W_META_SETTEXTCOLOR 0x0209 +#define W_META_SETTEXTJUSTIFICATION 0x020A +#define W_META_SETWINDOWORG 0x020B +#define W_META_SETWINDOWEXT 0x020C +#define W_META_SETVIEWPORTORG 0x020D +#define W_META_SETVIEWPORTEXT 0x020E +#define W_META_OFFSETWINDOWORG 0x020F +#define W_META_SCALEWINDOWEXT 0x0410 +#define W_META_OFFSETVIEWPORTORG 0x0211 +#define W_META_SCALEVIEWPORTEXT 0x0412 +#define W_META_LINETO 0x0213 +#define W_META_MOVETO 0x0214 +#define W_META_EXCLUDECLIPRECT 0x0415 +#define W_META_INTERSECTCLIPRECT 0x0416 +#define W_META_ARC 0x0817 +#define W_META_ELLIPSE 0x0418 +#define W_META_FLOODFILL 0x0419 +#define W_META_PIE 0x081A +#define W_META_RECTANGLE 0x041B +#define W_META_ROUNDRECT 0x061C +#define W_META_PATBLT 0x061D +#define W_META_SAVEDC 0x001E +#define W_META_SETPIXEL 0x041F +#define W_META_OFFSETCLIPRGN 0x0220 +#define W_META_TEXTOUT 0x0521 +#define W_META_BITBLT 0x0922 +#define W_META_STRETCHBLT 0x0B23 +#define W_META_POLYGON 0x0324 +#define W_META_POLYLINE 0x0325 +#define W_META_ESCAPE 0x0626 +#define W_META_RESTOREDC 0x0127 +#define W_META_FILLREGION 0x0228 +#define W_META_FRAMEREGION 0x0429 +#define W_META_INVERTREGION 0x012A +#define W_META_PAINTREGION 0x012B +#define W_META_SELECTCLIPREGION 0x012C +#define W_META_SELECTOBJECT 0x012D +#define W_META_SETTEXTALIGN 0x012E +#define W_META_DRAWTEXT 0x062F +#define W_META_CHORD 0x0830 +#define W_META_SETMAPPERFLAGS 0x0231 +#define W_META_EXTTEXTOUT 0x0a32 +#define W_META_SETDIBTODEV 0x0d33 +#define W_META_SELECTPALETTE 0x0234 +#define W_META_REALIZEPALETTE 0x0035 +#define W_META_ANIMATEPALETTE 0x0436 +#define W_META_SETPALENTRIES 0x0037 +#define W_META_POLYPOLYGON 0x0538 +#define W_META_RESIZEPALETTE 0x0139 +#define W_META_DIBBITBLT 0x0940 +#define W_META_DIBSTRETCHBLT 0x0b41 +#define W_META_DIBCREATEPATTERNBRUSH 0x0142 +#define W_META_STRETCHDIB 0x0f43 +#define W_META_EXTFLOODFILL 0x0548 +#define W_META_RESETDC 0x014C +#define W_META_STARTDOC 0x014D +#define W_META_STARTPAGE 0x004F +#define W_META_ENDPAGE 0x0050 +#define W_META_ABORTDOC 0x0052 +#define W_META_ENDDOC 0x005E +#define W_META_DELETEOBJECT 0x01f0 +#define W_META_CREATEPALETTE 0x00f7 +#define W_META_CREATEBRUSH 0x00F8 +#define W_META_CREATEPATTERNBRUSH 0x01F9 +#define W_META_CREATEPENINDIRECT 0x02FA +#define W_META_CREATEFONTINDIRECT 0x02FB +#define W_META_CREATEBRUSHINDIRECT 0x02FC +#define W_META_CREATEBITMAPINDIRECT 0x02FD +#define W_META_CREATEBITMAP 0x06FE +#define W_META_CREATEREGION 0x06FF + +#define W_TRANSPARENT 1 +#define W_OPAQUE 2 + +#define W_R2_BLACK 1 +#define W_R2_NOTMERGEPEN 2 +#define W_R2_MASKNOTPEN 3 +#define W_R2_NOTCOPYPEN 4 +#define W_R2_MASKPENNOT 5 +#define W_R2_NOT 6 +#define W_R2_XORPEN 7 +#define W_R2_NOTMASKPEN 8 +#define W_R2_MASKPEN 9 +#define W_R2_NOTXORPEN 10 +#define W_R2_NOP 11 +#define W_R2_MERGENOTPEN 12 +#define W_R2_COPYPEN 13 +#define W_R2_MERGEPENNOT 14 +#define W_R2_MERGEPEN 15 +#define W_R2_WHITE 16 + +#define W_TA_NOUPDATECP 0x0000 +#define W_TA_UPDATECP 0x0001 +#define W_TA_LEFT 0x0000 +#define W_TA_RIGHT 0x0002 +#define W_TA_CENTER 0x0006 +#define W_TA_TOP 0x0000 +#define W_TA_BOTTOM 0x0008 +#define W_TA_BASELINE 0x0018 +#define W_TA_RTLREADING 0x0100 + +#define W_SRCCOPY 0x00CC0020L +#define W_SRCPAINT 0x00EE0086L +#define W_SRCAND 0x008800C6L +#define W_SRCINVERT 0x00660046L +#define W_SRCERASE 0x00440328L +#define W_NOTSRCCOPY 0x00330008L +#define W_NOTSRCERASE 0x001100A6L +#define W_MERGECOPY 0x00C000CAL +#define W_MERGEPAINT 0x00BB0226L +#define W_PATCOPY 0x00F00021L +#define W_PATPAINT 0x00FB0A09L +#define W_PATINVERT 0x005A0049L +#define W_DSTINVERT 0x00550009L +#define W_BLACKNESS 0x00000042L +#define W_WHITENESS 0x00FF0062L + +#define W_PS_SOLID 0 +#define W_PS_DASH 1 +#define W_PS_DOT 2 +#define W_PS_DASHDOT 3 +#define W_PS_DASHDOTDOT 4 +#define W_PS_NULL 5 +#define W_PS_INSIDEFRAME 6 + +#define W_LF_FACESIZE 32 + +#define W_ANSI_CHARSET 0 +#define W_DEFAULT_CHARSET 1 +#define W_SYMBOL_CHARSET 2 +#define W_SHIFTJIS_CHARSET 128 +#define W_HANGEUL_CHARSET 129 +#define W_GB2312_CHARSET 134 +#define W_CHINESEBIG5_CHARSET 136 +#define W_OEM_CHARSET 255 +/*WINVER >= 0x0400*/ +#define W_JOHAB_CHARSET 130 +#define W_HEBREW_CHARSET 177 +#define W_ARABIC_CHARSET 178 +#define W_GREEK_CHARSET 161 +#define W_TURKISH_CHARSET 162 +#define W_VIETNAMESE_CHARSET 163 +#define W_THAI_CHARSET 222 +#define W_EASTEUROPE_CHARSET 238 +#define W_RUSSIAN_CHARSET 204 +#define W_MAC_CHARSET 77 +#define W_BALTIC_CHARSET 186 + +#define W_DEFAULT_PITCH 0x00 +#define W_FIXED_PITCH 0x01 +#define W_VARIABLE_PITCH 0x02 + +#define W_FF_DONTCARE 0x00 +#define W_FF_ROMAN 0x10 +#define W_FF_SWISS 0x20 +#define W_FF_MODERN 0x30 +#define W_FF_SCRIPT 0x40 +#define W_FF_DECORATIVE 0x50 + +#define W_FW_DONTCARE 0 +#define W_FW_THIN 100 +#define W_FW_EXTRALIGHT 200 +#define W_FW_LIGHT 300 +#define W_FW_NORMAL 400 +#define W_FW_MEDIUM 500 +#define W_FW_SEMIBOLD 600 +#define W_FW_BOLD 700 +#define W_FW_EXTRABOLD 800 +#define W_FW_HEAVY 900 +#define W_FW_ULTRALIGHT 200 +#define W_FW_REGULAR 400 +#define W_FW_DEMIBOLD 600 +#define W_FW_ULTRABOLD 800 +#define W_FW_BLACK 900 + +#define W_BS_SOLID 0 +#define W_BS_HOLLOW 1 +#define W_BS_HATCHED 2 +#define W_BS_PATTERN 3 +#define W_BS_INDEXED 4 +#define W_BS_DIBPATTERN 5 + +#define W_HS_HORIZONTAL 0 +#define W_HS_VERTICAL 1 +#define W_HS_FDIAGONAL 2 +#define W_HS_BDIAGONAL 3 +#define W_HS_CROSS 4 +#define W_HS_DIAGCROSS 5 + +#define W_MFCOMMENT 15 + +#define PRIVATE_ESCAPE_UNICODE 2 + +/// copied from writerwordglue.cxx + +/* + Utility to categorize unicode characters into the best fit windows charset + range for exporting to ww6, or as a hint to non \u unicode token aware rtf + readers +*/ +rtl_TextEncoding getScriptClass(sal_Unicode cChar) +{ + using namespace com::sun::star::i18n; + + static ScriptTypeList aScripts[] = + { + { UnicodeScript_kBasicLatin, UnicodeScript_kBasicLatin, RTL_TEXTENCODING_MS_1252}, + { UnicodeScript_kLatin1Supplement, UnicodeScript_kLatin1Supplement, RTL_TEXTENCODING_MS_1252}, + { UnicodeScript_kLatinExtendedA, UnicodeScript_kLatinExtendedA, RTL_TEXTENCODING_MS_1250}, + { UnicodeScript_kLatinExtendedB, UnicodeScript_kLatinExtendedB, RTL_TEXTENCODING_MS_1257}, + { UnicodeScript_kGreek, UnicodeScript_kGreek, RTL_TEXTENCODING_MS_1253}, + { UnicodeScript_kCyrillic, UnicodeScript_kCyrillic, RTL_TEXTENCODING_MS_1251}, + { UnicodeScript_kHebrew, UnicodeScript_kHebrew, RTL_TEXTENCODING_MS_1255}, + { UnicodeScript_kArabic, UnicodeScript_kArabic, RTL_TEXTENCODING_MS_1256}, + { UnicodeScript_kThai, UnicodeScript_kThai, RTL_TEXTENCODING_MS_1258}, + { UnicodeScript_kScriptCount, UnicodeScript_kScriptCount, RTL_TEXTENCODING_MS_1252} + }; + return unicode::getUnicodeScriptType(cChar, aScripts, + RTL_TEXTENCODING_MS_1252); +} + +//========================== Methoden von WMFWriter ========================== + +void WMFWriter::MayCallback() +{ + if ( xStatusIndicator.is() ) + { + ULONG nPercent; + + // Wir gehen mal einfach so davon aus, dass 16386 Actions einer Bitmap entsprechen + // (in der Regel wird ein Metafile entweder nur Actions oder einige Bitmaps und fast + // keine Actions enthalten. Dann ist das Verhaeltnis ziemlich unwichtig) + + nPercent=((nWrittenBitmaps<<14)+(nActBitmapPercent<<14)/100+nWrittenActions) + *100 + /((nNumberOfBitmaps<<14)+nNumberOfActions); + + if ( nPercent >= nLastPercent + 3 ) + { + nLastPercent = nPercent; + if( nPercent <= 100 ) + xStatusIndicator->setValue( nPercent ); + } + } +} + +void WMFWriter::CountActionsAndBitmaps( const GDIMetaFile & rMTF ) +{ + ULONG nAction, nActionCount; + + nActionCount = rMTF.GetActionCount(); + + for ( nAction=0; nAction<nActionCount; nAction++ ) + { + MetaAction* pMA = rMTF.GetAction( nAction ); + + switch( pMA->GetType() ) + { + case META_BMP_ACTION: + case META_BMPSCALE_ACTION: + case META_BMPSCALEPART_ACTION: + case META_BMPEX_ACTION: + case META_BMPEXSCALE_ACTION: + case META_BMPEXSCALEPART_ACTION: + nNumberOfBitmaps++; + break; + } + nNumberOfActions++; + } +} + + +void WMFWriter::WritePointXY(const Point & rPoint) +{ + Point aPt( pVirDev->LogicToLogic(rPoint,aSrcMapMode,aTargetMapMode) ); + *pWMF << ((short)aPt.X()) << ((short)aPt.Y()); +} + + +void WMFWriter::WritePointYX(const Point & rPoint) +{ + Point aPt( pVirDev->LogicToLogic(rPoint,aSrcMapMode,aTargetMapMode) ); + *pWMF << ((short)aPt.Y()) << ((short)aPt.X()); +} + + +sal_Int32 WMFWriter::ScaleWidth( sal_Int32 nDX ) +{ + Size aSz( pVirDev->LogicToLogic(Size(nDX,0),aSrcMapMode,aTargetMapMode) ); + return aSz.Width(); +} + + +void WMFWriter::WriteSize(const Size & rSize) +{ + Size aSz( pVirDev->LogicToLogic(rSize,aSrcMapMode,aTargetMapMode) ); + *pWMF << ((short)aSz.Width()) << ((short)aSz.Height()); +} + + +void WMFWriter::WriteHeightWidth(const Size & rSize) +{ + Size aSz( pVirDev->LogicToLogic(rSize,aSrcMapMode,aTargetMapMode) ); + *pWMF << ((short)aSz.Height()) << ((short)aSz.Width()); +} + + +void WMFWriter::WriteRectangle(const Rectangle & rRect) +{ + WritePointYX(Point(rRect.Right()+1,rRect.Bottom()+1)); + WritePointYX(rRect.TopLeft()); +} + + +void WMFWriter::WriteColor(const Color & rColor) +{ + *pWMF << (BYTE) rColor.GetRed() << (BYTE) rColor.GetGreen() << (BYTE) rColor.GetBlue() << (BYTE) 0; +} + + +void WMFWriter::WriteRecordHeader(sal_uInt32 nSizeWords, sal_uInt16 nType) +{ + nActRecordPos=pWMF->Tell(); + if (nSizeWords>nMaxRecordSize) nMaxRecordSize=nSizeWords; + *pWMF << nSizeWords << nType; +} + + +void WMFWriter::UpdateRecordHeader() +{ + ULONG nPos; + sal_uInt32 nSize; + + nPos=pWMF->Tell(); nSize=nPos-nActRecordPos; + if ((nSize & 1)!=0) { + *pWMF << (BYTE)0; + nPos++; nSize++; + } + nSize/=2; + if (nSize>nMaxRecordSize) nMaxRecordSize=nSize; + pWMF->Seek(nActRecordPos); + *pWMF << nSize; + pWMF->Seek(nPos); +} + + +void WMFWriter::WMFRecord_Arc(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt) +{ + WriteRecordHeader(0x0000000b,W_META_ARC); + WritePointYX(rEndPt); + WritePointYX(rStartPt); + WriteRectangle(rRect); +} + +void WMFWriter::WMFRecord_Chord(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt) +{ + WriteRecordHeader(0x0000000b,W_META_CHORD); + WritePointYX(rEndPt); + WritePointYX(rStartPt); + WriteRectangle(rRect); +} + + +void WMFWriter::WMFRecord_CreateBrushIndirect(const Color& rColor) +{ + WriteRecordHeader(0x00000007,W_META_CREATEBRUSHINDIRECT); + + if( rColor==Color(COL_TRANSPARENT) ) + *pWMF << (UINT16) W_BS_HOLLOW; + else + *pWMF << (UINT16) W_BS_SOLID; + + WriteColor( rColor ); + *pWMF << (UINT16) 0; +} + + +void WMFWriter::WMFRecord_CreateFontIndirect(const Font & rFont) +{ + USHORT nWeight,i; + BYTE nPitchFamily; + + WriteRecordHeader(0x00000000,W_META_CREATEFONTINDIRECT); + WriteHeightWidth(Size(rFont.GetSize().Width(),-rFont.GetSize().Height())); + *pWMF << (short)rFont.GetOrientation() << (short)rFont.GetOrientation(); + + switch (rFont.GetWeight()) { + case WEIGHT_THIN: nWeight=W_FW_THIN; break; + case WEIGHT_ULTRALIGHT: nWeight=W_FW_ULTRALIGHT; break; + case WEIGHT_LIGHT: nWeight=W_FW_LIGHT; break; + case WEIGHT_SEMILIGHT: nWeight=W_FW_LIGHT; break; + case WEIGHT_NORMAL: nWeight=W_FW_NORMAL; break; + case WEIGHT_MEDIUM: nWeight=W_FW_MEDIUM; break; + case WEIGHT_SEMIBOLD: nWeight=W_FW_SEMIBOLD; break; + case WEIGHT_BOLD: nWeight=W_FW_BOLD; break; + case WEIGHT_ULTRABOLD: nWeight=W_FW_ULTRABOLD; break; + case WEIGHT_BLACK: nWeight=W_FW_BLACK; break; + default: nWeight=W_FW_DONTCARE; + } + *pWMF << nWeight; + + if (rFont.GetItalic()==ITALIC_NONE) *pWMF << (BYTE)0; else *pWMF << (BYTE)1; + if (rFont.GetUnderline()==UNDERLINE_NONE) *pWMF << (BYTE)0; else *pWMF << (BYTE)1; + if (rFont.GetStrikeout()==STRIKEOUT_NONE) *pWMF << (BYTE)0; else *pWMF << (BYTE)1; + + CharSet eFontNameEncoding = rFont.GetCharSet(); + sal_uInt8 nCharSet = rtl_getBestWindowsCharsetFromTextEncoding( eFontNameEncoding ); + if ( eFontNameEncoding == RTL_TEXTENCODING_SYMBOL ) + eFontNameEncoding = RTL_TEXTENCODING_MS_1252; + if ( nCharSet == 1 ) + nCharSet = W_ANSI_CHARSET; + *pWMF << nCharSet; + + *pWMF << (BYTE)0 << (BYTE)0 << (BYTE)0; + + switch (rFont.GetPitch()) { + case PITCH_FIXED: nPitchFamily=W_FIXED_PITCH; break; + case PITCH_VARIABLE: nPitchFamily=W_VARIABLE_PITCH; break; + default: nPitchFamily=W_DEFAULT_PITCH; + } + switch (rFont.GetFamily()) { + case FAMILY_DECORATIVE: nPitchFamily|=W_FF_DECORATIVE; break; + case FAMILY_MODERN: nPitchFamily|=W_FF_MODERN; break; + case FAMILY_ROMAN: nPitchFamily|=W_FF_ROMAN; break; + case FAMILY_SCRIPT: nPitchFamily|=W_FF_SCRIPT; break; + case FAMILY_SWISS: nPitchFamily|=W_FF_SWISS; break; + default: nPitchFamily|=W_FF_DONTCARE; + } + *pWMF << nPitchFamily; + + ByteString aFontName( rFont.GetName(), eFontNameEncoding ); + for ( i = 0; i < W_LF_FACESIZE; i++ ) + { + sal_Char nChar = ( i < aFontName.Len() ) ? aFontName.GetChar( i ) : 0; + *pWMF << nChar; + } + UpdateRecordHeader(); +} + +void WMFWriter::WMFRecord_CreatePenIndirect(const Color& rColor, const LineInfo& rLineInfo ) +{ + WriteRecordHeader(0x00000008,W_META_CREATEPENINDIRECT); + USHORT nStyle = rColor == Color( COL_TRANSPARENT ) ? W_PS_NULL : W_PS_SOLID; + switch( rLineInfo.GetStyle() ) + { + case LINE_DASH : + { + if ( rLineInfo.GetDotCount() ) + { + if ( !rLineInfo.GetDashCount() ) + nStyle = W_PS_DOT; + else + { + if ( !rLineInfo.GetDotCount() == 1 ) + nStyle = W_PS_DASHDOT; + else + nStyle = W_PS_DASHDOTDOT; + } + } + else + nStyle = W_PS_DASH; + } + break; + case LINE_NONE : + nStyle = W_PS_NULL; + break; + default: + break; + } + *pWMF << nStyle; + + WriteSize( Size( rLineInfo.GetWidth(), 0 ) ); + WriteColor( rColor ); +} + +void WMFWriter::WMFRecord_DeleteObject(USHORT nObjectHandle) +{ + WriteRecordHeader(0x00000004,W_META_DELETEOBJECT); + *pWMF << nObjectHandle; +} + + +void WMFWriter::WMFRecord_Ellipse(const Rectangle & rRect) +{ + WriteRecordHeader(0x00000007,W_META_ELLIPSE); + WriteRectangle(rRect); +} + +bool IsStarSymbol(const String &rStr) +{ + return rStr.EqualsIgnoreCaseAscii("starsymbol") || + rStr.EqualsIgnoreCaseAscii("opensymbol"); +} + +void WMFWriter::WMFRecord_Escape( sal_uInt32 nEsc, sal_uInt32 nLen, const sal_Int8* pData ) +{ +#ifdef OSL_BIGENDIAN + sal_uInt32 nTmp = SWAPLONG( nEsc ); + sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 ); +#else + sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 ); +#endif + if ( nLen ) + nCheckSum = rtl_crc32( nCheckSum, pData, nLen ); + + WriteRecordHeader( 3 + 9 + ( ( nLen + 1 ) >> 1 ), W_META_ESCAPE ); + *pWMF << (sal_uInt16)W_MFCOMMENT + << (sal_uInt16)( nLen + 14 ) // we will always have a fourteen byte escape header: + << (sal_uInt16)0x4f4f // OO + << (sal_uInt32)0xa2c2a // evil magic number + << (sal_uInt32)nCheckSum // crc32 checksum about nEsc & pData + << (sal_uInt32)nEsc; // escape number + pWMF->Write( pData, nLen ); + if ( nLen & 1 ) + *pWMF << (sal_uInt8)0; // pad byte +} + +/* if return value is true, then a complete unicode string and also a polygon replacement has been written, + so there is no more action necessary +*/ +sal_Bool WMFWriter::WMFRecord_Escape_Unicode( const Point& rPoint, const String& rUniStr, const sal_Int32* pDXAry ) +{ + sal_Bool bEscapeUsed = sal_False; + + sal_uInt32 i, nStringLen = rUniStr.Len(); + if ( nStringLen ) + { + // first we will check if a comment is necessary + if ( aSrcFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL ) // symbol is always byte character, so there is no unicode loss + { + const sal_Unicode* pBuf = rUniStr.GetBuffer(); + const rtl_TextEncoding aTextEncodingOrg = aSrcFont.GetCharSet(); + ByteString aByteStr( rUniStr, aTextEncodingOrg ); + String aUniStr2( aByteStr, aTextEncodingOrg ); + const sal_Unicode* pConversion = aUniStr2.GetBuffer(); // this is the unicode array after bytestring <-> unistring conversion + for ( i = 0; i < nStringLen; i++ ) + { + if ( *pBuf++ != *pConversion++ ) + break; + } + + if ( i != nStringLen ) // after conversion the characters are not original, + { // try again, with determining a better charset from unicode char + pBuf = rUniStr.GetBuffer(); + const sal_Unicode* pCheckChar = pBuf; + rtl_TextEncoding aTextEncoding = getScriptClass (*pCheckChar); // try the first character + for ( i = 1; i < nStringLen; i++) + { + if (aTextEncoding != aTextEncodingOrg) // found something + break; + pCheckChar++; + aTextEncoding = getScriptClass (*pCheckChar); // try the next character + } + + aByteStr = ByteString ( rUniStr, aTextEncoding ); + aUniStr2 = String ( aByteStr, aTextEncoding ); + pConversion = aUniStr2.GetBuffer(); // this is the unicode array after bytestring <-> unistring conversion + for ( i = 0; i < nStringLen; i++ ) + { + if ( *pBuf++ != *pConversion++ ) + break; + } + if (i == nStringLen) + { + aSrcFont.SetCharSet (aTextEncoding); + SetAllAttr(); + } + } + + if ( ( i != nStringLen ) || IsStarSymbol( aSrcFont.GetName() ) ) // after conversion the characters are not original, so we + { // will store the unicode string and a polypoly replacement + Color aOldFillColor( aSrcFillColor ); + Color aOldLineColor( aSrcLineColor ); + aSrcLineInfo = LineInfo(); + aSrcFillColor = aSrcTextColor; + aSrcLineColor = Color( COL_TRANSPARENT ); + SetLineAndFillAttr(); + pVirDev->SetFont( aSrcFont ); + std::vector<PolyPolygon> aPolyPolyVec; + if ( pVirDev->GetTextOutlines( aPolyPolyVec, rUniStr ) ) + { + sal_uInt32 nDXCount = pDXAry ? nStringLen : 0; + sal_uInt32 nSkipActions = aPolyPolyVec.size(); + sal_Int32 nStrmLen = 8 + + + sizeof( nStringLen ) + ( nStringLen * 2 ) + + sizeof( nDXCount ) + ( nDXCount * 4 ) + + sizeof( nSkipActions ); + + SvMemoryStream aMemoryStream( nStrmLen ); + Point aPt( pVirDev->LogicToLogic( rPoint, aSrcMapMode, aTargetMapMode ) ); + aMemoryStream << aPt.X() + << aPt.Y() + << nStringLen; + for ( i = 0; i < nStringLen; i++ ) + aMemoryStream << rUniStr.GetChar( (sal_uInt16)i ); + aMemoryStream << nDXCount; + for ( i = 0; i < nDXCount; i++ ) + aMemoryStream << pDXAry[ i ]; + aMemoryStream << nSkipActions; + WMFRecord_Escape( PRIVATE_ESCAPE_UNICODE, nStrmLen, (const sal_Int8*)aMemoryStream.GetData() ); + + std::vector<PolyPolygon>::iterator aIter( aPolyPolyVec.begin() ); + while ( aIter != aPolyPolyVec.end() ) + { + PolyPolygon aPolyPoly( *aIter++ ); + aPolyPoly.Move( rPoint.X(), rPoint.Y() ); + WMFRecord_PolyPolygon( aPolyPoly ); + } + aSrcFillColor = aOldFillColor; + aSrcLineColor = aOldLineColor; + bEscapeUsed = sal_True; + } + } + } + } + return bEscapeUsed; +} + +void WMFWriter::WMFRecord_ExtTextOut( const Point & rPoint, + const String & rString, const sal_Int32 * pDXAry ) +{ + sal_uInt16 nOriginalTextLen = rString.Len(); + + if ( (nOriginalTextLen <= 1) || (pDXAry == NULL) ) + { + WMFRecord_TextOut(rPoint, rString); + return; + } + rtl_TextEncoding eChrSet = aSrcFont.GetCharSet(); + ByteString aByteString(rString, eChrSet); + TrueExtTextOut(rPoint,rString,aByteString,pDXAry); +} + +void WMFWriter::TrueExtTextOut( const Point & rPoint, const String & rString, + const ByteString & rByteString, const sal_Int32 * pDXAry ) +{ + WriteRecordHeader( 0, W_META_EXTTEXTOUT ); + WritePointYX( rPoint ); + sal_uInt16 nNewTextLen = rByteString.Len(); + *pWMF << nNewTextLen << (sal_uInt16)0; + + sal_uInt16 i; + for ( i = 0; i < nNewTextLen; i++ ) + *pWMF << (sal_uInt8)rByteString.GetChar( i ); + if ( nNewTextLen & 1 ) + *pWMF << (sal_uInt8)0; + + sal_uInt16 nOriginalTextLen = rString.Len(); + sal_Int16* pConvertedDXAry = new sal_Int16[ nOriginalTextLen ]; + sal_Int32 j = 0; + pConvertedDXAry[ j++ ] = (sal_Int16)ScaleWidth( pDXAry[ 0 ] ); + for ( i = 1; i < ( nOriginalTextLen - 1 ); i++ ) + pConvertedDXAry[ j++ ] = (sal_Int16)ScaleWidth( pDXAry[ i ] - pDXAry[ i - 1 ] ); + pConvertedDXAry[ j ] = (sal_Int16)ScaleWidth( pDXAry[ nOriginalTextLen - 2 ] / ( nOriginalTextLen - 1 ) ); + + for ( i = 0; i < nOriginalTextLen; i++ ) + { + sal_Int16 nDx = pConvertedDXAry[ i ]; + *pWMF << nDx; + if ( nOriginalTextLen < nNewTextLen ) + { + ByteString aTemp( rString.GetChar( i ), aSrcFont.GetCharSet()); + j = aTemp.Len(); + while ( --j > 0 ) + *pWMF << (sal_uInt16)0; + } + } + delete[] pConvertedDXAry; + UpdateRecordHeader(); +} + +void WMFWriter::WMFRecord_LineTo(const Point & rPoint) +{ + WriteRecordHeader(0x00000005,W_META_LINETO); + WritePointYX(rPoint); +} + + +void WMFWriter::WMFRecord_MoveTo(const Point & rPoint) +{ + WriteRecordHeader(0x00000005,W_META_MOVETO); + WritePointYX(rPoint); +} + + +void WMFWriter::WMFRecord_Pie(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt) +{ + WriteRecordHeader(0x0000000b,W_META_PIE); + WritePointYX(rEndPt); + WritePointYX(rStartPt); + WriteRectangle(rRect); +} + + +void WMFWriter::WMFRecord_Polygon(const Polygon & rPoly) +{ + USHORT nSize,i; + + Polygon aSimplePoly; + if ( rPoly.HasFlags() ) + rPoly.AdaptiveSubdivide( aSimplePoly ); + else + aSimplePoly = rPoly; + nSize = aSimplePoly.GetSize(); + WriteRecordHeader(((ULONG)nSize)*2+4,W_META_POLYGON); + *pWMF << nSize; + for (i=0; i<nSize; i++) WritePointXY(aSimplePoly.GetPoint(i)); +} + + +void WMFWriter::WMFRecord_PolyLine(const Polygon & rPoly) +{ + USHORT nSize,i; + Polygon aSimplePoly; + if ( rPoly.HasFlags() ) + rPoly.AdaptiveSubdivide( aSimplePoly ); + else + aSimplePoly = rPoly; + nSize=aSimplePoly.GetSize(); + WriteRecordHeader(((ULONG)nSize)*2+4,W_META_POLYLINE); + *pWMF << nSize; + for (i=0; i<nSize; i++) WritePointXY(aSimplePoly.GetPoint(i)); +} + + +void WMFWriter::WMFRecord_PolyPolygon(const PolyPolygon & rPolyPoly) +{ + const Polygon * pPoly; + USHORT nCount,nSize,i,j; + + nCount=rPolyPoly.Count(); + PolyPolygon aSimplePolyPoly( rPolyPoly ); + for ( i = 0; i < nCount; i++ ) + { + if ( aSimplePolyPoly[ i ].HasFlags() ) + { + Polygon aSimplePoly; + aSimplePolyPoly[ i ].AdaptiveSubdivide( aSimplePoly ); + aSimplePolyPoly[ i ] = aSimplePoly; + } + } + WriteRecordHeader(0,W_META_POLYPOLYGON); + *pWMF << nCount; + for (i=0; i<nCount; i++) *pWMF << ((USHORT)(aSimplePolyPoly.GetObject(i).GetSize())); + for (i=0; i<nCount; i++) { + pPoly=&(aSimplePolyPoly.GetObject(i)); + nSize=pPoly->GetSize(); + for (j=0; j<nSize; j++) WritePointXY(pPoly->GetPoint(j)); + } + UpdateRecordHeader(); +} + + +void WMFWriter::WMFRecord_Rectangle(const Rectangle & rRect) +{ + WriteRecordHeader( 0x00000007,W_META_RECTANGLE ); + WriteRectangle( rRect ); +} + + +void WMFWriter::WMFRecord_RestoreDC() +{ + WriteRecordHeader(0x00000004,W_META_RESTOREDC); + *pWMF << (short)-1; +} + + +void WMFWriter::WMFRecord_RoundRect(const Rectangle & rRect, long nHorzRound, long nVertRound) +{ + WriteRecordHeader(0x00000009,W_META_ROUNDRECT); + WriteHeightWidth(Size(nHorzRound,nVertRound)); + WriteRectangle(rRect); +} + + +void WMFWriter::WMFRecord_SaveDC() +{ + WriteRecordHeader(0x00000003,W_META_SAVEDC); +} + + +void WMFWriter::WMFRecord_SelectObject(USHORT nObjectHandle) +{ + WriteRecordHeader(0x00000004,W_META_SELECTOBJECT); + *pWMF << nObjectHandle; +} + + +void WMFWriter::WMFRecord_SetBkColor(const Color & rColor) +{ + WriteRecordHeader(0x00000005,W_META_SETBKCOLOR); + WriteColor(rColor); +} + + +void WMFWriter::WMFRecord_SetBkMode(BOOL bTransparent) +{ + WriteRecordHeader(0x00000004,W_META_SETBKMODE); + if (bTransparent==TRUE) *pWMF << (USHORT)W_TRANSPARENT; + else *pWMF << (USHORT)W_OPAQUE; +} + +void WMFWriter::WMFRecord_SetStretchBltMode() +{ + WriteRecordHeader( 0x00000004, W_META_SETSTRETCHBLTMODE ); + *pWMF << (USHORT) 3; // STRETCH_DELETESCANS +} + +void WMFWriter::WMFRecord_SetPixel(const Point & rPoint, const Color & rColor) +{ + WriteRecordHeader(0x00000007,W_META_SETPIXEL); + WriteColor(rColor); + WritePointYX(rPoint); +} + + +void WMFWriter::WMFRecord_SetROP2(RasterOp eROP) +{ + USHORT nROP2; + + switch (eROP) { + case ROP_INVERT: nROP2=W_R2_NOT; break; + case ROP_XOR: nROP2=W_R2_XORPEN; break; + default: nROP2=W_R2_COPYPEN; + } + WriteRecordHeader(0x00000004,W_META_SETROP2); + *pWMF << nROP2; +} + + +void WMFWriter::WMFRecord_SetTextAlign(FontAlign eFontAlign, UINT32 eHorTextAlign) +{ + USHORT nAlign; + + switch (eFontAlign) { + case ALIGN_TOP: nAlign=W_TA_TOP; break; + case ALIGN_BOTTOM: nAlign=W_TA_BOTTOM; break; + default: nAlign=W_TA_BASELINE; + } + nAlign|=eHorTextAlign; + nAlign|=W_TA_NOUPDATECP; + + WriteRecordHeader(0x00000004,W_META_SETTEXTALIGN); + *pWMF << nAlign; +} + + +void WMFWriter::WMFRecord_SetTextColor(const Color & rColor) +{ + WriteRecordHeader(0x00000005,W_META_SETTEXTCOLOR); + WriteColor(rColor); +} + + +void WMFWriter::WMFRecord_SetWindowExt(const Size & rSize) +{ + WriteRecordHeader(0x00000005,W_META_SETWINDOWEXT); + WriteHeightWidth(rSize); +} + + +void WMFWriter::WMFRecord_SetWindowOrg(const Point & rPoint) +{ + WriteRecordHeader(0x00000005,W_META_SETWINDOWORG); + WritePointYX(rPoint); +} + + +void WMFWriter::WMFRecord_StretchDIB( const Point & rPoint, const Size & rSize, + const Bitmap & rBitmap, sal_uInt32 nROP ) +{ + ULONG nPosAnf,nPosEnd; + + nActBitmapPercent=50; + MayCallback(); + + WriteRecordHeader(0x00000000,W_META_STRETCHDIB); + + // Die Reihenfolge im Metafile soll jetzt sein: + // einige Parameter (laenge 22), dann die Bitmap ohne FILEHEADER. + // Da aber *pWMF << rBitmap einen FILEHEADER der Laenge 14 + // erzeugt, schreiben wir zuerst die Bitmap an die richtige Position + // Und ueberschreiben hinterher den FILEHEADER mit den Parametern. + nPosAnf=pWMF->Tell(); // Position merken, wo Parameter hin sollen + *pWMF << (long)0 << (long)0; // 8 bytes auffuellen (diese 8 bytes + + // 14 bytes ueberfluessigen FILEHEADER + // = 22 bytes Parameter) + *pWMF << rBitmap; // Bitmap schreiben + + // Parameter schreiben: + nPosEnd=pWMF->Tell(); + pWMF->Seek(nPosAnf); + + // Raster-Op bestimmen, falls nichts uebergeben wurde + if( !nROP ) + { + switch( eSrcRasterOp ) + { + case ROP_INVERT: nROP = W_DSTINVERT; break; + case ROP_XOR: nROP = W_SRCINVERT; break; + default: nROP = W_SRCCOPY; + } + } + + *pWMF << nROP << + (short) 0 << + (short) rBitmap.GetSizePixel().Height() << + (short) rBitmap.GetSizePixel().Width() << + (short) 0 << + (short) 0; + + WriteHeightWidth(rSize); + WritePointYX(rPoint); + pWMF->Seek(nPosEnd); + + UpdateRecordHeader(); + + nWrittenBitmaps++; + nActBitmapPercent=0; +} + + +void WMFWriter::WMFRecord_TextOut(const Point & rPoint, const String & rStr) +{ + rtl_TextEncoding eChrSet = aSrcFont.GetCharSet(); + ByteString aString( rStr, eChrSet ); + TrueTextOut(rPoint, aString); +} + +void WMFWriter::TrueTextOut(const Point & rPoint, const ByteString& rString) +{ + USHORT nLen,i; + + WriteRecordHeader(0,W_META_TEXTOUT); + nLen=rString.Len(); + *pWMF << nLen; + for ( i = 0; i < nLen; i++ ) + *pWMF << (BYTE)rString.GetChar( i ); + if ((nLen&1)!=0) *pWMF << (BYTE)0; + WritePointYX(rPoint); + UpdateRecordHeader(); +} + +void WMFWriter::WMFRecord_EndOfFile() +{ + WriteRecordHeader(0x00000003,0x0000); +} + + +void WMFWriter::WMFRecord_IntersectClipRect( const Rectangle& rRect ) +{ + WriteRecordHeader( 0x00000007, W_META_INTERSECTCLIPRECT ); + WriteRectangle(rRect); +} + + +USHORT WMFWriter::AllocHandle() +{ + USHORT i; + + for (i=0; i<MAXOBJECTHANDLES; i++) { + if (bHandleAllocated[i]==FALSE) { + bHandleAllocated[i]=TRUE; + return i; + } + } + bStatus=FALSE; + return 0xffff; +} + + +void WMFWriter::FreeHandle(USHORT nObjectHandle) +{ + if (nObjectHandle<MAXOBJECTHANDLES) bHandleAllocated[nObjectHandle]=FALSE; +} + + +void WMFWriter::CreateSelectDeletePen( const Color& rColor, const LineInfo& rLineInfo ) +{ + USHORT nOldHandle; + + nOldHandle=nDstPenHandle; + nDstPenHandle=AllocHandle(); + WMFRecord_CreatePenIndirect( rColor, rLineInfo ); + WMFRecord_SelectObject(nDstPenHandle); + if (nOldHandle<MAXOBJECTHANDLES) { + WMFRecord_DeleteObject(nOldHandle); + FreeHandle(nOldHandle); + } +} + + +void WMFWriter::CreateSelectDeleteFont(const Font & rFont) +{ + USHORT nOldHandle; + + nOldHandle=nDstFontHandle; + nDstFontHandle=AllocHandle(); + WMFRecord_CreateFontIndirect(rFont); + WMFRecord_SelectObject(nDstFontHandle); + if (nOldHandle<MAXOBJECTHANDLES) { + WMFRecord_DeleteObject(nOldHandle); + FreeHandle(nOldHandle); + } +} + + +void WMFWriter::CreateSelectDeleteBrush(const Color& rColor) +{ + USHORT nOldHandle; + + nOldHandle=nDstBrushHandle; + nDstBrushHandle=AllocHandle(); + WMFRecord_CreateBrushIndirect(rColor); + WMFRecord_SelectObject(nDstBrushHandle); + if (nOldHandle<MAXOBJECTHANDLES) { + WMFRecord_DeleteObject(nOldHandle); + FreeHandle(nOldHandle); + } +} + + +void WMFWriter::SetLineAndFillAttr() +{ + if ( eDstROP2 != eSrcRasterOp ) + { + eDstROP2=eSrcRasterOp; + WMFRecord_SetROP2(eDstROP2); + } + if ( ( aDstLineColor != aSrcLineColor ) || ( aDstLineInfo != aSrcLineInfo ) ) + { + aDstLineColor = aSrcLineColor; + aDstLineInfo = aSrcLineInfo; + CreateSelectDeletePen( aDstLineColor, aDstLineInfo ); + } + if ( aDstFillColor != aSrcFillColor ) + { + aDstFillColor = aSrcFillColor; + CreateSelectDeleteBrush( aDstFillColor ); + } + if ( bDstIsClipping != bSrcIsClipping || + (bSrcIsClipping==TRUE && aDstClipRegion!=aSrcClipRegion)) { + bDstIsClipping=bSrcIsClipping; + aDstClipRegion=aSrcClipRegion; + } +} + +void WMFWriter::SetAllAttr() +{ + SetLineAndFillAttr(); + if ( aDstTextColor != aSrcTextColor ) + { + aDstTextColor = aSrcTextColor; + WMFRecord_SetTextColor(aDstTextColor); + } + if ( eDstTextAlign != eSrcTextAlign || eDstHorTextAlign != eSrcHorTextAlign ) + { + eDstTextAlign = eSrcTextAlign; + eDstHorTextAlign = eSrcHorTextAlign; + WMFRecord_SetTextAlign( eDstTextAlign, eDstHorTextAlign ); + } + if ( aDstFont != aSrcFont ) + { + pVirDev->SetFont(aSrcFont); + if ( aDstFont.GetName() != aSrcFont.GetName() ) + { + FontCharMap aFontCharMap; + if ( pVirDev->GetFontCharMap( aFontCharMap ) ) + { + if ( ( aFontCharMap.GetFirstChar() & 0xff00 ) == 0xf000 ) + aSrcFont.SetCharSet( RTL_TEXTENCODING_SYMBOL ); + else if ( aSrcFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL ) + aSrcFont.SetCharSet( RTL_TEXTENCODING_MS_1252 ); + } + } + aDstFont = aSrcFont; + CreateSelectDeleteFont(aDstFont); + } +} + + +void WMFWriter::HandleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon) +{ + if(rLinePolygon.count()) + { + basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon); + basegfx::B2DPolyPolygon aFillPolyPolygon; + + rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon); + + if(aLinePolyPolygon.count()) + { + aSrcLineInfo = rInfo; + SetLineAndFillAttr(); + + for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++) + { + const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a)); + WMFRecord_PolyLine(Polygon(aCandidate)); + } + } + + if(aFillPolyPolygon.count()) + { + const Color aOldLineColor(aSrcLineColor); + const Color aOldFillColor(aSrcFillColor); + + aSrcLineColor = Color( COL_TRANSPARENT ); + aSrcFillColor = aOldLineColor; + SetLineAndFillAttr(); + + for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++) + { + const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a)); + WMFRecord_Polygon(Polygon(aPolygon)); + } + + aSrcLineColor = aOldLineColor; + aSrcFillColor = aOldFillColor; + SetLineAndFillAttr(); + } + } +} + +void WMFWriter::WriteRecords( const GDIMetaFile & rMTF ) +{ + ULONG nA, nACount; + MetaAction* pMA; + + if( bStatus ) + { + nACount = rMTF.GetActionCount(); + + WMFRecord_SetStretchBltMode(); + + for( nA=0; nA<nACount; nA++ ) + { + pMA = rMTF.GetAction( nA ); + + switch( pMA->GetType() ) + { + case META_PIXEL_ACTION: + { + const MetaPixelAction* pA = (const MetaPixelAction *) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_SetPixel( pA->GetPoint(), pA->GetColor() ); + } + break; + + case META_POINT_ACTION: + { + const MetaPointAction* pA = (const MetaPointAction*) pMA; + const Point& rPt = pA->GetPoint(); + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_MoveTo( rPt); + WMFRecord_LineTo( rPt ); + } + break; + + case META_LINE_ACTION: + { + const MetaLineAction* pA = (const MetaLineAction *) pMA; + if(pA->GetLineInfo().IsDefault()) + { + aSrcLineInfo = pA->GetLineInfo(); + SetLineAndFillAttr(); + WMFRecord_MoveTo( pA->GetStartPoint() ); + WMFRecord_LineTo( pA->GetEndPoint() ); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + basegfx::B2DPolygon aPolygon; + aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y())); + aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y())); + HandleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon); + } + } + break; + + case META_RECT_ACTION: + { + const MetaRectAction* pA = (const MetaRectAction*) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_Rectangle( pA->GetRect() ); + } + break; + + case META_ROUNDRECT_ACTION: + { + const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_RoundRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() ); + } + break; + + case META_ELLIPSE_ACTION: + { + const MetaEllipseAction* pA = (const MetaEllipseAction*) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_Ellipse( pA->GetRect() ); + } + break; + + case META_ARC_ACTION: + { + const MetaArcAction* pA = (const MetaArcAction*) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_Arc( pA->GetRect(),pA->GetStartPoint(),pA->GetEndPoint() ); + } + break; + + case META_PIE_ACTION: + { + const MetaPieAction* pA = (const MetaPieAction*) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_Pie( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() ); + } + break; + + + case META_CHORD_ACTION: + { + const MetaChordAction* pA = (const MetaChordAction*) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_Chord( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() ); + } + break; + + case META_POLYLINE_ACTION: + { + const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pMA; + const Polygon& rPoly = pA->GetPolygon(); + + if( rPoly.GetSize() ) + { + if(pA->GetLineInfo().IsDefault()) + { + aSrcLineInfo = pA->GetLineInfo(); + SetLineAndFillAttr(); + WMFRecord_PolyLine( rPoly ); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + HandleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon()); + } + } + } + break; + + case META_POLYGON_ACTION: + { + const MetaPolygonAction* pA = (const MetaPolygonAction*) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_Polygon( pA->GetPolygon() ); + } + break; + + case META_POLYPOLYGON_ACTION: + { + const MetaPolyPolygonAction* pA = (const MetaPolyPolygonAction*) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_PolyPolygon( pA->GetPolyPolygon() ); + } + break; + + case META_TEXTRECT_ACTION: + { + const MetaTextRectAction * pA = (const MetaTextRectAction*)pMA; + String aTemp( pA->GetText() ); + aSrcLineInfo = LineInfo(); + SetAllAttr(); + + Point aPos( pA->GetRect().TopLeft() ); + if ( !WMFRecord_Escape_Unicode( aPos, aTemp, NULL ) ) + WMFRecord_TextOut( aPos, aTemp ); + } + break; + + case META_TEXT_ACTION: + { + const MetaTextAction * pA = (const MetaTextAction*) pMA; + String aTemp( pA->GetText(), pA->GetIndex(), pA->GetLen() ); + aSrcLineInfo = LineInfo(); + SetAllAttr(); + if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, NULL ) ) + WMFRecord_TextOut( pA->GetPoint(), aTemp ); + } + break; + + case META_TEXTARRAY_ACTION: + { + const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pMA; + + String aTemp( pA->GetText(), pA->GetIndex(), pA->GetLen() ); + aSrcLineInfo = LineInfo(); + SetAllAttr(); + if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, pA->GetDXArray() ) ) + WMFRecord_ExtTextOut( pA->GetPoint(), aTemp, pA->GetDXArray() ); + } + break; + + case META_STRETCHTEXT_ACTION: + { + const MetaStretchTextAction* pA = (const MetaStretchTextAction *) pMA; + String aTemp( pA->GetText(), pA->GetIndex(), pA->GetLen() ); + + sal_uInt16 nLen,i; + sal_Int32 nNormSize; + + pVirDev->SetFont( aSrcFont ); + nLen = aTemp.Len(); + sal_Int32* pDXAry = nLen ? new sal_Int32[ nLen ] : NULL; + nNormSize = pVirDev->GetTextArray( aTemp, pDXAry ); + for ( i = 0; i < ( nLen - 1 ); i++ ) + pDXAry[ i ] = pDXAry[ i ] * (sal_Int32)pA->GetWidth() / nNormSize; + if ( ( nLen <= 1 ) || ( (sal_Int32)pA->GetWidth() == nNormSize ) ) + delete[] pDXAry, pDXAry = NULL; + aSrcLineInfo = LineInfo(); + SetAllAttr(); + if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, pDXAry ) ) + WMFRecord_ExtTextOut( pA->GetPoint(), aTemp, pDXAry ); + delete[] pDXAry; + } + break; + + case META_BMP_ACTION: + { + const MetaBmpAction* pA = (const MetaBmpAction *) pMA; + WMFRecord_StretchDIB( pA->GetPoint(), pA->GetBitmap().GetSizePixel(), pA->GetBitmap() ); + } + break; + + case META_BMPSCALE_ACTION: + { + const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pMA; + WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), pA->GetBitmap() ); + } + break; + + case META_BMPSCALEPART_ACTION: + { + const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*) pMA; + Bitmap aTmp( pA->GetBitmap() ); + + if( aTmp.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ) ) + WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aTmp ); + } + break; + + case META_BMPEX_ACTION: + { + const MetaBmpExAction* pA = (const MetaBmpExAction *) pMA; + Bitmap aBmp( pA->GetBitmapEx().GetBitmap() ); + Bitmap aMsk( pA->GetBitmapEx().GetMask() ); + + if( !!aMsk ) + { + aBmp.Replace( aMsk, COL_WHITE ); + aMsk.Invert(); + WMFRecord_StretchDIB( pA->GetPoint(), aMsk.GetSizePixel(), aBmp, W_SRCPAINT ); + WMFRecord_StretchDIB( pA->GetPoint(), aBmp.GetSizePixel(), aBmp, W_SRCAND ); + } + else + WMFRecord_StretchDIB( pA->GetPoint(), aBmp.GetSizePixel(), aBmp ); + } + break; + + case META_BMPEXSCALE_ACTION: + { + const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pMA; + Bitmap aBmp( pA->GetBitmapEx().GetBitmap() ); + Bitmap aMsk( pA->GetBitmapEx().GetMask() ); + + if( !!aMsk ) + { + aBmp.Replace( aMsk, COL_WHITE ); + aMsk.Invert(); + WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aMsk, W_SRCPAINT ); + WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aBmp, W_SRCAND ); + } + else + WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aBmp ); + } + break; + + case META_BMPEXSCALEPART_ACTION: + { + const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*) pMA; + BitmapEx aBmpEx( pA->GetBitmapEx() ); + aBmpEx.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ); + Bitmap aBmp( aBmpEx.GetBitmap() ); + Bitmap aMsk( aBmpEx.GetMask() ); + + if( !!aMsk ) + { + aBmp.Replace( aMsk, COL_WHITE ); + aMsk.Invert(); + WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aMsk, W_SRCPAINT ); + WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aBmp, W_SRCAND ); + } + else + WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aBmp ); + } + break; + + case META_GRADIENT_ACTION: + { + const MetaGradientAction* pA = (const MetaGradientAction*) pMA; + GDIMetaFile aTmpMtf; + + pVirDev->AddGradientActions( pA->GetRect(), pA->GetGradient(), aTmpMtf ); + WriteRecords( aTmpMtf ); + } + break; + + case META_HATCH_ACTION: + { + const MetaHatchAction* pA = (const MetaHatchAction*) pMA; + GDIMetaFile aTmpMtf; + + pVirDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf ); + WriteRecords( aTmpMtf ); + } + break; + + case META_WALLPAPER_ACTION: + { + const MetaWallpaperAction* pA = (const MetaWallpaperAction*) pMA; + const Color& rColor = pA->GetWallpaper().GetColor(); + const Color aOldLineColor( aSrcLineColor ); + const Color aOldFillColor( aSrcFillColor ); + + aSrcLineColor = rColor; + aSrcFillColor = rColor; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_Rectangle( pA->GetRect() ); + aSrcLineColor = aOldLineColor; + aSrcFillColor = aOldFillColor; + } + break; + + case META_ISECTRECTCLIPREGION_ACTION: + { + const MetaISectRectClipRegionAction* pA = (const MetaISectRectClipRegionAction*) pMA; + WMFRecord_IntersectClipRect( pA->GetRect() ); + } + break; + + case META_LINECOLOR_ACTION: + { + const MetaLineColorAction* pA = (const MetaLineColorAction*) pMA; + + if( pA->IsSetting() ) + aSrcLineColor = pA->GetColor(); + else + aSrcLineColor = Color( COL_TRANSPARENT ); + } + break; + + case META_FILLCOLOR_ACTION: + { + const MetaFillColorAction* pA = (const MetaFillColorAction*) pMA; + + if( pA->IsSetting() ) + aSrcFillColor = pA->GetColor(); + else + aSrcFillColor = Color( COL_TRANSPARENT ); + } + break; + + case META_TEXTCOLOR_ACTION: + { + const MetaTextColorAction* pA = (const MetaTextColorAction*) pMA; + aSrcTextColor = pA->GetColor(); + } + break; + + case META_TEXTFILLCOLOR_ACTION: + { + const MetaTextFillColorAction* pA = (const MetaTextFillColorAction*) pMA; + if( pA->IsSetting() ) + aSrcFont.SetFillColor( pA->GetColor() ); + else + aSrcFont.SetFillColor( Color( COL_TRANSPARENT ) ); + } + break; + + case META_TEXTALIGN_ACTION: + { + const MetaTextAlignAction* pA = (const MetaTextAlignAction*) pMA; + eSrcTextAlign = pA->GetTextAlign(); + } + break; + + case META_MAPMODE_ACTION: + { + const MetaMapModeAction* pA = (const MetaMapModeAction*) pMA; + + if (aSrcMapMode!=pA->GetMapMode()) + { + if( pA->GetMapMode().GetMapUnit() == MAP_RELATIVE ) + { + MapMode aMM = pA->GetMapMode(); + Fraction aScaleX = aMM.GetScaleX(); + Fraction aScaleY = aMM.GetScaleY(); + + Point aOrigin = aSrcMapMode.GetOrigin(); + BigInt aX( aOrigin.X() ); + aX *= BigInt( aScaleX.GetDenominator() ); + if( aOrigin.X() >= 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() ); + aOrigin.X() = (long)aX + aMM.GetOrigin().X(); + BigInt aY( aOrigin.Y() ); + aY *= BigInt( aScaleY.GetDenominator() ); + if( aOrigin.Y() >= 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() ); + aOrigin.Y() = (long)aY + aMM.GetOrigin().Y(); + aSrcMapMode.SetOrigin( aOrigin ); + + aScaleX *= aSrcMapMode.GetScaleX(); + aScaleY *= aSrcMapMode.GetScaleY(); + aSrcMapMode.SetScaleX( aScaleX ); + aSrcMapMode.SetScaleY( aScaleY ); + } + else + aSrcMapMode=pA->GetMapMode(); + } + } + break; + + case META_FONT_ACTION: + { + const MetaFontAction* pA = (const MetaFontAction*) pMA; + aSrcFont = pA->GetFont(); + + if ( aSrcFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW ) + aSrcFont.SetCharSet( GetExtendedTextEncoding( gsl_getSystemTextEncoding() ) ); + if ( aSrcFont.GetCharSet() == RTL_TEXTENCODING_UNICODE ) + aSrcFont.SetCharSet( RTL_TEXTENCODING_MS_1252 ); + eSrcTextAlign = aSrcFont.GetAlign(); + aSrcTextColor = aSrcFont.GetColor(); + aSrcFont.SetAlign( ALIGN_BASELINE ); + aSrcFont.SetColor( COL_WHITE ); + } + break; + + case META_PUSH_ACTION: + { + const MetaPushAction* pA = (const MetaPushAction*)pMA; + + WMFWriterAttrStackMember* pAt = new WMFWriterAttrStackMember; + pAt->nFlags = pA->GetFlags(); + pAt->aClipRegion = aSrcClipRegion; + pAt->aLineColor=aSrcLineColor; + pAt->aFillColor=aSrcFillColor; + pAt->eRasterOp=eSrcRasterOp; + pAt->aFont=aSrcFont; + pAt->eTextAlign=eSrcTextAlign; + pAt->aTextColor=aSrcTextColor; + pAt->aMapMode=aSrcMapMode; + pAt->aLineInfo=aDstLineInfo; + pAt->pSucc=pAttrStack; + pAttrStack=pAt; + + SetAllAttr(); // update ( now all source attributes are equal to the destination attributes ) + WMFRecord_SaveDC(); + + } + break; + + case META_POP_ACTION: + { + WMFWriterAttrStackMember * pAt=pAttrStack; + + if( pAt ) + { + aDstLineInfo = pAt->aLineInfo; + aDstLineColor = pAt->aLineColor; + if ( pAt->nFlags & PUSH_LINECOLOR ) + aSrcLineColor = pAt->aLineColor; + aDstFillColor = pAt->aFillColor; + if ( pAt->nFlags & PUSH_FILLCOLOR ) + aSrcFillColor = pAt->aFillColor; + eDstROP2 = pAt->eRasterOp; + if ( pAt->nFlags & PUSH_RASTEROP ) + eSrcRasterOp = pAt->eRasterOp; + aDstFont = pAt->aFont; + if ( pAt->nFlags & PUSH_FONT ) + aSrcFont = pAt->aFont; + eDstTextAlign = pAt->eTextAlign; + if ( pAt->nFlags & ( PUSH_FONT | PUSH_TEXTALIGN ) ) + eSrcTextAlign = pAt->eTextAlign; + aDstTextColor = pAt->aTextColor; + if ( pAt->nFlags & ( PUSH_FONT | PUSH_TEXTCOLOR ) ) + aSrcTextColor = pAt->aTextColor; + if ( pAt->nFlags & PUSH_MAPMODE ) + aSrcMapMode = pAt->aMapMode; + aDstClipRegion = pAt->aClipRegion; + if ( pAt->nFlags & PUSH_CLIPREGION ) + aSrcClipRegion = pAt->aClipRegion; + + WMFRecord_RestoreDC(); + pAttrStack = pAt->pSucc; + delete pAt; + } + } + break; + + case META_EPS_ACTION : + { + const MetaEPSAction* pA = (const MetaEPSAction*)pMA; + const GDIMetaFile aGDIMetaFile( pA->GetSubstitute() ); + + INT32 nCount = aGDIMetaFile.GetActionCount(); + for ( INT32 i = 0; i < nCount; i++ ) + { + const MetaAction* pMetaAct = aGDIMetaFile.GetAction( i ); + if ( pMetaAct->GetType() == META_BMPSCALE_ACTION ) + { + const MetaBmpScaleAction* pBmpScaleAction = (const MetaBmpScaleAction*)pMetaAct; + WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), pBmpScaleAction->GetBitmap() ); + break; + } + } + } + break; + + case META_RASTEROP_ACTION: + { + const MetaRasterOpAction* pA = (const MetaRasterOpAction*) pMA; + eSrcRasterOp=pA->GetRasterOp(); + } + break; + + case META_TRANSPARENT_ACTION: + { + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_PolyPolygon( ( (MetaTransparentAction*) pMA )->GetPolyPolygon() ); + } + break; + + case META_FLOATTRANSPARENT_ACTION: + { + const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*) pMA; + + GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() ); + Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() ); + const Size aSrcSize( aTmpMtf.GetPrefSize() ); + const Point aDestPt( pA->GetPoint() ); + const Size aDestSize( pA->GetSize() ); + const double fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0; + const double fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0; + long nMoveX, nMoveY; + + aSrcLineInfo = LineInfo(); + SetAllAttr(); + + if( fScaleX != 1.0 || fScaleY != 1.0 ) + { + aTmpMtf.Scale( fScaleX, fScaleY ); + aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY ); + } + + nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y(); + + if( nMoveX || nMoveY ) + aTmpMtf.Move( nMoveX, nMoveY ); + + WriteRecords( aTmpMtf ); + } + break; + + case( META_LAYOUTMODE_ACTION ): + { + sal_uInt32 nLayoutMode = ( (MetaLayoutModeAction*) pMA )->GetLayoutMode(); + eSrcHorTextAlign = 0; // TA_LEFT + if (nLayoutMode & TEXT_LAYOUT_BIDI_RTL) + { + eSrcHorTextAlign = W_TA_RIGHT | W_TA_RTLREADING; + } + if (nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_RIGHT) + eSrcHorTextAlign |= W_TA_RIGHT; + else if (nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT) + eSrcHorTextAlign &= ~W_TA_RIGHT; + break; + } + + // Unsupported Actions + case META_MASK_ACTION: + case META_MASKSCALE_ACTION: + case META_MASKSCALEPART_ACTION: + { + DBG_ERROR( "Unsupported action: MetaMask...Action!" ); + } + break; + + case META_CLIPREGION_ACTION: + break; + + case META_ISECTREGIONCLIPREGION_ACTION: + { + DBG_ERROR( "Unsupported action: MetaISectRegionClipRegionAction!" ); + } + break; + + case META_MOVECLIPREGION_ACTION: + { + DBG_ERROR( "Unsupported action: MetaMoveClipRegionAction!" ); + } + break; + } + + nWrittenActions++; + MayCallback(); + + if (pWMF->GetError()) + bStatus=FALSE; + + if(bStatus==FALSE) + break; + } + } +} + +// ------------------------------------------------------------------------ + +void WMFWriter::WriteHeader( const GDIMetaFile &, BOOL bPlaceable ) +{ + if( bPlaceable ) + { + USHORT nCheckSum, nValue; + Size aSize( pVirDev->LogicToLogic(Size(1,1),MapMode(MAP_INCH), aTargetMapMode) ); + USHORT nUnitsPerInch = (USHORT) ( ( aSize.Width() + aSize.Height() ) >> 1 ); + + nCheckSum=0; + nValue=0xcdd7; nCheckSum^=nValue; *pWMF << nValue; + nValue=0x9ac6; nCheckSum^=nValue; *pWMF << nValue; + nValue=0x0000; nCheckSum^=nValue; *pWMF << nValue; + nValue=0x0000; nCheckSum^=nValue; *pWMF << nValue; + nValue=0x0000; nCheckSum^=nValue; *pWMF << nValue; + nValue=(USHORT) aTargetSize.Width(); nCheckSum^=nValue; *pWMF << nValue; + nValue=(USHORT) aTargetSize.Height(); nCheckSum^=nValue; *pWMF << nValue; + nValue=nUnitsPerInch; nCheckSum^=nValue; *pWMF << nValue; + nValue=0x0000; nCheckSum^=nValue; *pWMF << nValue; + nValue=0x0000; nCheckSum^=nValue; *pWMF << nValue; + *pWMF << nCheckSum; + } + + nMetafileHeaderPos=pWMF->Tell(); + *pWMF << (sal_uInt16)0x0001 // Typ: Datei + << (sal_uInt16)0x0009 // Headerlaenge in Worten + << (sal_uInt16)0x0300 // Version als BCD-Zahl + << (sal_uInt32) 0x00000000 // Dateilaenge (ohne 1. Header), wird spaeter durch UpdateHeader() berichtigt + << (sal_uInt16)MAXOBJECTHANDLES // Maximalezahl der gleichzeitigen Objekte + << (sal_uInt32) 0x00000000 // Maximale Record-laenge, wird spaeter durch UpdateHeader() berichtigt + << (sal_uInt16)0x0000; // Reserved +} + +// ------------------------------------------------------------------------ + +void WMFWriter::UpdateHeader() +{ + ULONG nPos; + sal_uInt32 nFileSize; + + nPos=pWMF->Tell(); // Endposition = Gesammtgroesse der Datei + nFileSize=nPos-nMetafileHeaderPos; // Groesse des 1. Headers abziehen + if ((nFileSize&1)!=0) { // ggf. auf ganze Worte aufrunden + *pWMF << (BYTE)0; + nPos++; + nFileSize++; + } + nFileSize>>=1; // In Anzahl Worte umrechnen + pWMF->Seek(nMetafileHeaderPos+6); // Zum Dateigroessen-Eintrag im zweiten Header + *pWMF << nFileSize; // Dateigroesse berichtigen + pWMF->SeekRel(2); // Zum Max-Record-Laenge-Eintrag im zweiten Header + *pWMF << nMaxRecordSize; // und berichtigen + pWMF->Seek(nPos); +} + +// ------------------------------------------------------------------------ + +BOOL WMFWriter::WriteWMF( const GDIMetaFile& rMTF, SvStream& rTargetStream, + FilterConfigItem* pFConfigItem, BOOL bPlaceable ) +{ + WMFWriterAttrStackMember * pAt; + + bEmbedEMF = TRUE; + bStatus=TRUE; + pConvert = 0; + pVirDev = new VirtualDevice; + + pFilterConfigItem = pFConfigItem; + if ( pFilterConfigItem ) + { + xStatusIndicator = pFilterConfigItem->GetStatusIndicator(); + if ( xStatusIndicator.is() ) + { + rtl::OUString aMsg; + xStatusIndicator->start( aMsg, 100 ); + } + } + nLastPercent=0; + + pWMF=&rTargetStream; + pWMF->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN); + + nMaxRecordSize=0; + + aSrcMapMode=rMTF.GetPrefMapMode(); + + if( bPlaceable ) + { + aTargetMapMode = aSrcMapMode; + aTargetSize = rMTF.GetPrefSize(); + nTargetDivisor = CalcSaveTargetMapMode(aTargetMapMode, aTargetSize); + aTargetSize.Width() /= nTargetDivisor; + aTargetSize.Height() /= nTargetDivisor; + } + else + { + aTargetMapMode = MapMode( MAP_INCH ); + + const long nUnit = pVirDev->LogicToPixel( Size( 1, 1 ), aTargetMapMode ).Width(); + const Fraction aFrac( 1, nUnit ); + + aTargetMapMode.SetScaleX( aFrac ); + aTargetMapMode.SetScaleY( aFrac ); + aTargetSize = pVirDev->LogicToLogic( rMTF.GetPrefSize(), aSrcMapMode, aTargetMapMode ); + } + + pVirDev->SetMapMode( aTargetMapMode ); + + pAttrStack=NULL; + + for (USHORT i=0; i<MAXOBJECTHANDLES; i++) + bHandleAllocated[i]=FALSE; + + nDstPenHandle=0xffff; + nDstFontHandle=0xffff; + nDstBrushHandle=0xffff; + + nNumberOfActions=0; + nNumberOfBitmaps=0; + nWrittenActions=0; + nWrittenBitmaps=0; + nActBitmapPercent=0; + + CountActionsAndBitmaps(rMTF); + + WriteHeader(rMTF,bPlaceable); + if( bEmbedEMF ) + WriteEmbeddedEMF( rMTF ); + WMFRecord_SetWindowOrg(Point(0,0)); + WMFRecord_SetWindowExt(rMTF.GetPrefSize()); + WMFRecord_SetBkMode( TRUE ); + + eDstROP2 = eSrcRasterOp = ROP_OVERPAINT; + WMFRecord_SetROP2(eDstROP2); + + aDstLineInfo = LineInfo(); + aDstLineColor = aSrcLineColor = Color( COL_BLACK ); + CreateSelectDeletePen( aDstLineColor, aDstLineInfo ); + + aDstFillColor = aSrcFillColor = Color( COL_WHITE ); + CreateSelectDeleteBrush( aDstFillColor ); + + aDstClipRegion = aSrcClipRegion = Region(); + bDstIsClipping = bSrcIsClipping = FALSE; + + Font aFont; + aFont.SetCharSet( GetExtendedTextEncoding( gsl_getSystemTextEncoding() ) ); + aFont.SetColor( Color( COL_WHITE ) ); + aFont.SetAlign( ALIGN_BASELINE ); + aDstFont = aSrcFont = aFont; + CreateSelectDeleteFont(aDstFont); + + eDstTextAlign = eSrcTextAlign = ALIGN_BASELINE; + eDstHorTextAlign = eSrcHorTextAlign = W_TA_LEFT; + WMFRecord_SetTextAlign( eDstTextAlign, eDstHorTextAlign ); + + aDstTextColor = aSrcTextColor = Color( COL_WHITE ); + WMFRecord_SetTextColor(aDstTextColor); + + // Write records + WriteRecords(rMTF); + + WMFRecord_EndOfFile(); + UpdateHeader(); + + while(pAttrStack) + { + pAt=pAttrStack; + pAttrStack=pAt->pSucc; + delete pAt; + } + + delete pVirDev; + delete pConvert; + + if ( xStatusIndicator.is() ) + xStatusIndicator->end(); + + return bStatus; +} + +// ------------------------------------------------------------------------ + +USHORT WMFWriter::CalcSaveTargetMapMode(MapMode& rMapMode, + const Size& rPrefSize) +{ + Fraction aDivFrac(2, 1); + USHORT nDivisor = 1; + + Size aSize = pVirDev->LogicToLogic( rPrefSize, aSrcMapMode, rMapMode ); + + while( nDivisor <= 64 && (aSize.Width() > 32767 || aSize.Height() > 32767) ) + { + Fraction aFrac = rMapMode.GetScaleX(); + + aFrac *= aDivFrac; + rMapMode.SetScaleX(aFrac); + aFrac = rMapMode.GetScaleY(); + aFrac *= aDivFrac; + rMapMode.SetScaleY(aFrac); + nDivisor <<= 1; + aSize = pVirDev->LogicToLogic( rPrefSize, aSrcMapMode, rMapMode ); + } + + return nDivisor; +} + +// ------------------------------------------------------------------------ + +void WMFWriter::WriteEmbeddedEMF( const GDIMetaFile& rMTF ) +{ + EMFWriter aEMFWriter; + SvMemoryStream aStream; + + if( aEMFWriter.WriteEMF( rMTF, aStream ) ) + { + sal_Size nTotalSize = aStream.Tell(); + if( nTotalSize > SAL_MAX_UINT32 ) + return; + aStream.Seek( 0 ); + sal_uInt32 nRemainingSize = static_cast< sal_uInt32 >( nTotalSize ); + sal_uInt32 nRecCounts = ( (nTotalSize - 1) / 0x2000 ) + 1; + sal_uInt16 nCheckSum = 0, nWord; + + sal_uInt32 nPos = 0; + + while( nPos + 1 < nTotalSize ) + { + aStream >> nWord; + nCheckSum ^= nWord; + nPos += 2; + } + + nCheckSum = static_cast< sal_uInt16 >( nCheckSum * -1 ); + + aStream.Seek( 0 ); + while( nRemainingSize > 0 ) + { + sal_uInt32 nCurSize; + if( nRemainingSize > 0x2000 ) + { + nCurSize = 0x2000; + nRemainingSize -= 0x2000; + } + else + { + nCurSize = nRemainingSize; + nRemainingSize = 0; + } + WriteEMFRecord( aStream, + nCurSize, + nRemainingSize, + nTotalSize, + nRecCounts, + nCheckSum ); + nCheckSum = 0; + } + } +} + +// ------------------------------------------------------------------------ + +void WMFWriter::WriteEMFRecord( SvMemoryStream& rStream, sal_uInt32 nCurSize, sal_uInt32 nRemainingSize, + sal_uInt32 nTotalSize, sal_uInt32 nRecCounts, sal_uInt16 nCheckSum ) +{ + // according to http://msdn.microsoft.com/en-us/library/dd366152%28PROT.13%29.aspx + WriteRecordHeader( 0, W_META_ESCAPE ); + *pWMF << (sal_uInt16)W_MFCOMMENT // same as META_ESCAPE_ENHANCED_METAFILE + << (sal_uInt16)( nCurSize + 34 ) // we will always have a 34 byte escape header: + << (sal_uInt32) 0x43464D57 // WMFC + << (sal_uInt32) 0x00000001 // Comment type + << (sal_uInt32) 0x00010000 // version + << nCheckSum // check sum + << (sal_uInt32) 0 // flags = 0 + << nRecCounts // total number of records + << nCurSize // size of this record's data + << nRemainingSize // remaining size of data in following records, missing in MSDN documentation + << nTotalSize; // total size of EMF stream + + pWMF->Write( static_cast< const sal_Char* >( rStream.GetData() ) + rStream.Tell(), nCurSize ); + rStream.SeekRel( nCurSize ); + UpdateRecordHeader(); +} diff --git a/svtools/source/filter.vcl/wmf/wmfwr.hxx b/svtools/source/filter.vcl/wmf/wmfwr.hxx new file mode 100644 index 000000000000..9fe698b22c2e --- /dev/null +++ b/svtools/source/filter.vcl/wmf/wmfwr.hxx @@ -0,0 +1,229 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _WMFWR_HXX +#define _WMFWR_HXX + +#include <tools/bigint.hxx> +#include <tools/debug.hxx> +#include <vcl/metaact.hxx> +#include <vcl/graph.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/virdev.hxx> +#include <svtools/fltcall.hxx> + +// ----------------------------------------------------------------------------- + +#define MAXOBJECTHANDLES 16 + +// ----------------------------------------------------------------------------- + +struct WMFWriterAttrStackMember +{ + struct WMFWriterAttrStackMember * pSucc; + Color aLineColor; + Color aFillColor; + Color aTextColor; + LineInfo aLineInfo; + TextAlign eTextAlign; + RasterOp eRasterOp; + Font aFont; + MapMode aMapMode; + Region aClipRegion; + sal_uInt16 nFlags; +}; + +// ------------- +// - WMFWriter - +// ------------- + +class StarSymbolToMSMultiFont; +class LineInfo; +namespace basegfx { class B2DPolygon; } + +class WMFWriter +{ +private: + + BOOL bStatus; + + ULONG nLastPercent; // Mit welcher Zahl pCallback zuletzt aufgerufen wurde. + FilterConfigItem* pFilterConfigItem; + + com::sun::star::uno::Reference< com::sun::star::task::XStatusIndicator > xStatusIndicator; + + SvStream* pWMF; + VirtualDevice* pVirDev; + StarSymbolToMSMultiFont *pConvert; + MapMode aTargetMapMode; + Size aTargetSize; + USHORT nTargetDivisor; + + ULONG nMetafileHeaderPos; + sal_uInt32 nMaxRecordSize; // in Worten + ULONG nActRecordPos; + + // Aktuelle Attribute im Quell-Metafile: + Color aSrcLineColor; + Color aSrcFillColor; + Color aSrcTextColor; + LineInfo aSrcLineInfo; + RasterOp eSrcRasterOp; + FontAlign eSrcTextAlign; + Font aSrcFont; + MapMode aSrcMapMode; + BOOL bSrcIsClipping; + Region aSrcClipRegion; + WMFWriterAttrStackMember * pAttrStack; + + UINT32 eSrcHorTextAlign; + + // Aktuelle Attribute im Ziel-Metafile: + Color aDstLineColor; + Color aDstFillColor; + Color aDstTextColor; + LineInfo aDstLineInfo; + RasterOp eDstROP2; + FontAlign eDstTextAlign; + Font aDstFont; + + UINT32 eDstHorTextAlign; + + BOOL bDstIsClipping; // ???: derzeit unberuecksichtigt + Region aDstClipRegion; // ???: derzeit unberuecksichtigt + BOOL bHandleAllocated[MAXOBJECTHANDLES]; // Welche Handles vergeben sind + USHORT nDstPenHandle,nDstFontHandle,nDstBrushHandle; // Welche Handles die jeweiligen + // Selected-Objects besitzen + // 0xffff = keines: + + // Damit nicht bei jeder Operation alle Attribute verglichen werden muessen: + + ULONG nNumberOfActions; // Anzahl der Actions im GDIMetafile + ULONG nNumberOfBitmaps; // Anzahl der Bitmaps + ULONG nWrittenActions; // Anzahl der bereits verarbeiteten Actions beim Schreiben der Orders + ULONG nWrittenBitmaps; // Anzahl der bereits geschriebenen Bitmaps + ULONG nActBitmapPercent; // Wieviel Prozent die naechste Bitmap schon geschrieben ist. + + BOOL bEmbedEMF; // optionally embedd EMF data into WMF + + void MayCallback(); + // Berechnet anhand der obigen 5 Parameter eine Prozentzahl + // und macht dann ggf. einen Callback. Setzt bStatus auf FALSE wenn User abbrechen + // moechte. + + void CountActionsAndBitmaps(const GDIMetaFile & rMTF); + // Zaehlt die Bitmaps und Actions (nNumberOfActions und nNumberOfBitmaps muessen + // zu Anfang auf 0 gesetzt werden, weil diese Methode rekursiv ist) + + void WritePointXY(const Point & rPoint); + void WritePointYX(const Point & rPoint); + sal_Int32 ScaleWidth( sal_Int32 nDX ); + void WriteSize(const Size & rSize); + void WriteHeightWidth(const Size & rSize); + void WriteRectangle(const Rectangle & rRect); + void WriteColor(const Color & rColor); + + void WriteRecordHeader(sal_uInt32 nSizeWords, sal_uInt16 nType); + // nSizeWords ist die Groesse des gesammten Records in Anzahl Worte. + // Wenn nSizeWords unbekannt ist, dann 0 einsetzen (siehe UpdateRecordHeader()). + + void UpdateRecordHeader(); + // berichtig die Groesse des Records nach dem Schreiben der Parameter, wenn + // nSizeWords bei Aufruf von WriteRecordHeader(..) unbekannt war. + // fuegt ggf. noch ein BYTE 0 ein damit Anzahl Bytes immer gerade. + + void WMFRecord_Arc(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt); + void WMFRecord_Chord(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt); + void WMFRecord_CreateBrushIndirect(const Color& rColor); + void WMFRecord_CreateFontIndirect(const Font & rFont); + void WMFRecord_CreatePenIndirect(const Color& rColor, const LineInfo& rLineInfo ); + void WMFRecord_DeleteObject(USHORT nObjectHandle); + void WMFRecord_Ellipse(const Rectangle & rRect); + void WMFRecord_Escape( sal_uInt32 nEsc, sal_uInt32 nLen, const sal_Int8* pData ); + sal_Bool WMFRecord_Escape_Unicode( const Point& rPoint, const String& rStr, const sal_Int32 * pDXAry ); + void WMFRecord_ExtTextOut(const Point & rPoint, const String & rString, const sal_Int32 * pDXAry); + + void TrueExtTextOut(const Point & rPoint, const String & rString, + const ByteString & rByteString, const sal_Int32 * pDXAry); + void TrueTextOut(const Point & rPoint, const ByteString& rString); + void WMFRecord_LineTo(const Point & rPoint); + void WMFRecord_MoveTo(const Point & rPoint); + void WMFRecord_Pie(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt); + void WMFRecord_Polygon(const Polygon & rPoly); + void WMFRecord_PolyLine(const Polygon & rPoly); + void WMFRecord_PolyPolygon(const PolyPolygon & rPolyPoly); + void WMFRecord_Rectangle(const Rectangle & rRect); + void WMFRecord_RestoreDC(); + void WMFRecord_RoundRect(const Rectangle & rRect, long nHorzRound, long nVertRound); + void WMFRecord_SaveDC(); + void WMFRecord_SelectObject(USHORT nObjectHandle); + void WMFRecord_SetBkColor(const Color & rColor); + void WMFRecord_SetBkMode(BOOL bTransparent); + void WMFRecord_SetStretchBltMode(); + void WMFRecord_SetPixel(const Point & rPoint, const Color & rColor); + void WMFRecord_SetROP2(RasterOp eROP); + void WMFRecord_SetTextAlign(FontAlign eFontAlign, UINT32 eHorTextAlign); + void WMFRecord_SetTextColor(const Color & rColor); + void WMFRecord_SetWindowExt(const Size & rSize); + void WMFRecord_SetWindowOrg(const Point & rPoint); + void WMFRecord_StretchDIB(const Point & rPoint, const Size & rSize, const Bitmap & rBitmap, sal_uInt32 nROP = 0UL ); + void WMFRecord_TextOut(const Point & rPoint, const String & rString); + void WMFRecord_EndOfFile(); + void WMFRecord_IntersectClipRect( const Rectangle& rRect); + + USHORT AllocHandle(); + void FreeHandle(USHORT nObjectHandle); + void CreateSelectDeletePen( const Color& rColor, const LineInfo& rLineInfo ); + void CreateSelectDeleteFont(const Font & rFont); + void CreateSelectDeleteBrush(const Color& rColor); + + void SetLineAndFillAttr(); + void SetAllAttr(); + + void HandleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon); + void WriteRecords(const GDIMetaFile & rMTF); + + void WriteHeader(const GDIMetaFile & rMTF, BOOL bPlaceable); + void UpdateHeader(); + + void WriteEmbeddedEMF( const GDIMetaFile& rMTF ); + void WriteEMFRecord( SvMemoryStream& rStream, sal_uInt32 nCurSize, + sal_uInt32 nRemainingSize, + sal_uInt32 nTotalSize, + sal_uInt32 nRecCounts, + sal_uInt16 nCheckSum ); + + USHORT CalcSaveTargetMapMode(MapMode& rMapMode, const Size& rPrefSize); + +public: + + WMFWriter() {} + + BOOL WriteWMF(const GDIMetaFile & rMTF, SvStream & rTargetStream, FilterConfigItem* pFilterConfigItem, BOOL bPlaceable=TRUE); +}; + +#endif |