diff options
author | Jan Holesovsky <kendy@suse.cz> | 2013-01-01 22:48:32 +0100 |
---|---|---|
committer | Petr Mladek <pmladek@suse.cz> | 2013-01-08 16:12:44 +0100 |
commit | 3a571a93df6dc4be855ac5c6433f28e57531fae5 (patch) | |
tree | 40b132bcaad94af7951296ddd46772e8e867def3 /vcl/source/filter/wmf | |
parent | a03f34ce76108b452f2bb655e3a551dcd23ab644 (diff) |
Move GraphicFilter class to vcl.
Change-Id: I2318eeda59cee1cfdb074f9a90fd7d8d80aab19f
Signed-off-by: Cor Nouws <oolst@nouenoff.nl>
Signed-off-by: Olivier Hallot <olivier.hallot@documentfoundation.org>
Signed-off-by: Adolfo Jayme Barrientos <fitoschido@ubuntu.com>
Signed-off-by: Michael Meeks <michael.meeks@suse.com>
Diffstat (limited to 'vcl/source/filter/wmf')
-rw-r--r-- | vcl/source/filter/wmf/emfwr.cxx | 1412 | ||||
-rw-r--r-- | vcl/source/filter/wmf/emfwr.hxx | 93 | ||||
-rw-r--r-- | vcl/source/filter/wmf/enhwmf.cxx | 1418 | ||||
-rw-r--r-- | vcl/source/filter/wmf/winmtf.cxx | 2239 | ||||
-rw-r--r-- | vcl/source/filter/wmf/winmtf.hxx | 890 | ||||
-rw-r--r-- | vcl/source/filter/wmf/winwmf.cxx | 1503 | ||||
-rw-r--r-- | vcl/source/filter/wmf/wmf.cxx | 110 | ||||
-rw-r--r-- | vcl/source/filter/wmf/wmfwr.cxx | 2052 | ||||
-rw-r--r-- | vcl/source/filter/wmf/wmfwr.hxx | 220 |
9 files changed, 9937 insertions, 0 deletions
diff --git a/vcl/source/filter/wmf/emfwr.cxx b/vcl/source/filter/wmf/emfwr.cxx new file mode 100644 index 000000000000..c4caf024b47f --- /dev/null +++ b/vcl/source/filter/wmf/emfwr.cxx @@ -0,0 +1,1412 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "emfwr.hxx" +#include <rtl/strbuf.hxx> +#include <tools/helpers.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 - +// ------------- + +sal_Bool EMFWriter::WriteEMF( const GDIMetaFile& rMtf, FilterConfigItem* pFilterConfigItem ) +{ + const sal_uLong nHeaderPos = m_rStm.Tell(); + + mpHandlesUsed = new sal_Bool[ MAXHANDLES ]; + memset( mpHandlesUsed, 0, MAXHANDLES * sizeof( sal_Bool ) ); + mnHorTextAlign = mnHandleCount = mnLastPercent = mnRecordPos = mnRecordCount = 0; + mnLineHandle = mnFillHandle = mnTextHandle = HANDLE_INVALID; + mbRecordOpen = sal_False; + + maVDev.EnableOutput( sal_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() + m_rStm.SeekRel( 108 ); + + // write initial values + + // set 100th mm map mode in EMF + ImplBeginRecord( WIN_EMR_SETMAPMODE ); + m_rStm << (sal_Int32) MM_ANISOTROPIC; + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SETVIEWPORTEXTEX ); + m_rStm << (sal_Int32) maVDev.ImplGetDPIX() << (sal_Int32) maVDev.ImplGetDPIY(); + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SETWINDOWEXTEX ); + m_rStm << (sal_Int32) 2540 << (sal_Int32) 2540; + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SETVIEWPORTORGEX ); + m_rStm << (sal_Int32) 0 << (sal_Int32) 0; + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SETWINDOWORGEX ); + m_rStm << (sal_Int32) 0 << (sal_Int32) 0; + ImplEndRecord(); + + ImplWriteRasterOp( ROP_OVERPAINT ); + + ImplBeginRecord( WIN_EMR_SETBKMODE ); + m_rStm << (sal_uInt32) 1; // TRANSPARENT + ImplEndRecord(); + + // write emf data + ImplWrite( rMtf ); + + ImplBeginRecord( WIN_EMR_EOF ); + m_rStm<< (sal_uInt32)0 // nPalEntries + << (sal_uInt32)0x10 // offPalEntries + << (sal_uInt32)0x14; // nSizeLast + ImplEndRecord(); + + + // write header + const sal_uLong nEndPos = m_rStm.Tell(); m_rStm.Seek( nHeaderPos ); + + m_rStm << (sal_uInt32) 0x00000001 << (sal_uInt32) 108 //use [MS-EMF 2.2.11] HeaderExtension2 Object + << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) ( aMtfSizePix.Width() - 1 ) << (sal_Int32) ( aMtfSizePix.Height() - 1 ) + << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) ( aMtfSizeLog.Width() - 1 ) << (sal_Int32) ( aMtfSizeLog.Height() - 1 ) + << (sal_uInt32) 0x464d4520 << (sal_uInt32) 0x10000 << (sal_uInt32) ( nEndPos - nHeaderPos ) + << (sal_uInt32) mnRecordCount << (sal_uInt16) ( mnHandleCount + 1 ) << (sal_uInt16) 0 << (sal_uInt32) 0 << (sal_uInt32) 0 << (sal_uInt32) 0 + << (sal_Int32) aMtfSizePix.Width() << (sal_Int32) aMtfSizePix.Height() + << (sal_Int32) ( aMtfSizeLog.Width() / 100 ) << (sal_Int32) ( aMtfSizeLog.Height() / 100 ) + << (sal_uInt32) 0 << (sal_uInt32) 0 << (sal_uInt32) 0 + << (sal_Int32) ( aMtfSizeLog.Width() * 10 ) << (sal_Int32) ( aMtfSizeLog.Height() * 10 ); //use [MS-EMF 2.2.11] HeaderExtension2 Object + + m_rStm.Seek( nEndPos ); + delete[] mpHandlesUsed; + + return( m_rStm.GetError() == ERRCODE_NONE ); +} + +// ----------------------------------------------------------------------------- + +sal_uLong EMFWriter::ImplAcquireHandle() +{ + sal_uLong nHandle = HANDLE_INVALID; + + for( sal_uLong i = 0; i < MAXHANDLES && ( HANDLE_INVALID == nHandle ); i++ ) + { + if( !mpHandlesUsed[ i ] ) + { + mpHandlesUsed[ i ] = sal_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( sal_uLong nHandle ) +{ + DBG_ASSERT( nHandle && ( nHandle < MAXHANDLES ), "Handle out of range" ); + mpHandlesUsed[ nHandle - 1 ] = sal_False; +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplBeginRecord( sal_uInt32 nType ) +{ + DBG_ASSERT( !mbRecordOpen, "Another record is already opened!" ); + + if( !mbRecordOpen ) + { + mbRecordOpen = sal_True; + mnRecordPos = m_rStm.Tell(); + + m_rStm << nType; + m_rStm.SeekRel( 4 ); + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplEndRecord() +{ + DBG_ASSERT( mbRecordOpen, "Record was not opened!" ); + + if( mbRecordOpen ) + { + sal_Int32 nFillBytes, nActPos = m_rStm.Tell(); + m_rStm.Seek( mnRecordPos + 4 ); + nFillBytes = nActPos - mnRecordPos; + nFillBytes += 3; // each record has to be dword aligned + nFillBytes ^= 3; + nFillBytes &= 3; + m_rStm << (sal_uInt32)( ( nActPos - mnRecordPos ) + nFillBytes ); + m_rStm.Seek( nActPos ); + while( nFillBytes-- ) + m_rStm << (sal_uInt8)0; + mnRecordCount++; + mbRecordOpen = sal_False; + } +} + +// ----------------------------------------------------------------------------- + +sal_Bool EMFWriter::ImplPrepareHandleSelect( sal_uInt32& rHandle, sal_uLong nSelectType ) +{ + if( rHandle != HANDLE_INVALID ) + { + sal_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 ); + m_rStm << nStockObject; + ImplEndRecord(); + + // destroy handle of created object + ImplBeginRecord( WIN_EMR_DELETEOBJECT ); + m_rStm << 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 ); + m_rStm << mnLineHandle << nStyle << nWidth << nHeight; + ImplWriteColor( maVDev.GetLineColor() ); + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SELECTOBJECT ); + m_rStm << 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 ); + m_rStm << mnFillHandle << nStyle; + ImplWriteColor( maVDev.GetFillColor() ); + m_rStm << nPatternStyle; + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SELECTOBJECT ); + m_rStm << 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 ); + m_rStm << mnTextHandle; + ImplWriteExtent( -rFont.GetSize().Height() ); + ImplWriteExtent( rFont.GetSize().Width() ); + m_rStm << (sal_Int32) rFont.GetOrientation() << (sal_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; + } + + m_rStm << nWeight; + m_rStm << (sal_uInt8) ( ( ITALIC_NONE == rFont.GetItalic() ) ? 0 : 1 ); + m_rStm << (sal_uInt8) ( ( UNDERLINE_NONE == rFont.GetUnderline() ) ? 0 : 1 ); + m_rStm << (sal_uInt8) ( ( STRIKEOUT_NONE == rFont.GetStrikeout() ) ? 0 : 1 ); + m_rStm << (sal_uInt8) ( ( RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet() ) ? 2 : 0 ); + m_rStm << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 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; + } + + m_rStm << nPitchAndFamily; + + for( i = 0; i < 32; i++ ) + m_rStm << (sal_Unicode) ( ( i < aFontName.Len() ) ? aFontName.GetChar( i ) : 0 ); + + // dummy elfFullName + for( i = 0; i < 64; i++ ) + m_rStm << (sal_Unicode) 0; + + // dummy elfStyle + for( i = 0; i < 32; i++ ) + m_rStm << (sal_Unicode) 0; + + // dummy elfVersion, elfStyleSize, elfMatch, elfReserved + m_rStm << (sal_uInt32) 0 << (sal_uInt32) 0 << (sal_uInt32) 0 << (sal_uInt32) 0 ; + + // dummy elfVendorId + m_rStm << (sal_uInt32) 0; + + // dummy elfCulture + m_rStm << (sal_uInt32) 0; + + // dummy elfPanose + m_rStm << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0; + + // fill record to get a record size divideable by 4 + m_rStm << (sal_uInt16) 0; + + ImplEndRecord(); + + // TextAlign + sal_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 ); + m_rStm << nTextAlign; + ImplEndRecord(); + + // Text color + ImplBeginRecord( WIN_EMR_SETTEXTCOLOR ); + ImplWriteColor( maVDev.GetTextColor() ); + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SELECTOBJECT ); + m_rStm << mnTextHandle; + ImplEndRecord(); + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteColor( const Color& rColor ) +{ + sal_uInt32 nCol = rColor.GetRed(); + + nCol |= ( (sal_uInt32) rColor.GetGreen() ) << 8; + nCol |= ( (sal_uInt32) rColor.GetBlue() ) << 16; + + m_rStm << nCol; +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteRasterOp( RasterOp eRop ) +{ + sal_uInt32 nROP2; + + switch( eRop ) + { + case ROP_INVERT: nROP2 = 6; break; + case ROP_XOR: nROP2 = 7; break; + default: nROP2 = 13;break; + } + + ImplBeginRecord( WIN_EMR_SETROP2 ); + m_rStm << nROP2; + ImplEndRecord(); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteExtent( long nExtent ) +{ + nExtent = maVDev.LogicToLogic( Size( nExtent, 0 ), maVDev.GetMapMode(), maDestMapMode ).Width(); + m_rStm << (sal_Int32) nExtent; +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWritePoint( const Point& rPoint ) +{ + const Point aPoint( maVDev.LogicToLogic( rPoint, maVDev.GetMapMode(), maDestMapMode )); + m_rStm << (sal_Int32) aPoint.X() << (sal_Int32) aPoint.Y(); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteSize( const Size& rSize) +{ + const Size aSize( maVDev.LogicToLogic( rSize, maVDev.GetMapMode(), maDestMapMode )); + m_rStm << (sal_Int32) aSize.Width() << (sal_Int32) aSize.Height(); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteRect( const Rectangle& rRect ) +{ + const Rectangle aRect( maVDev.LogicToLogic ( rRect, maVDev.GetMapMode(), maDestMapMode )); + m_rStm + << static_cast<sal_Int32>(aRect.Left()) + << static_cast<sal_Int32>(aRect.Top()) + << static_cast<sal_Int32>(aRect.Right()) + << static_cast<sal_Int32>(aRect.Bottom()); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWritePolygonRecord( const Polygon& rPoly, sal_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() ); + m_rStm << (sal_uInt32) rPoly.GetSize(); + + for( sal_uInt16 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 ], sal_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() ); + m_rStm << (sal_uInt32)nPolyCount << nTotalPoints; + + for( i = 0; i < nPolyCount; i++ ) + m_rStm << (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() ); + m_rStm << (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() ); + m_rStm << (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, sal_uInt32 nROP ) +{ + if( !!rBmp ) + { + SvMemoryStream aMemStm( 65535, 65535 ); + const Size aBmpSizePixel( rBmp.GetSizePixel() ); + + ImplBeginRecord( WIN_EMR_STRETCHDIBITS ); + ImplWriteRect( Rectangle( rPt, rSz ) ); + ImplWritePoint( rPt ); + m_rStm << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) aBmpSizePixel.Width() << (sal_Int32) aBmpSizePixel.Height(); + + // write offset positions and sizes later + const sal_uLong nOffPos = m_rStm.Tell(); + m_rStm.SeekRel( 16 ); + + m_rStm << (sal_uInt32) 0 << sal_Int32( ( ROP_XOR == maVDev.GetRasterOp() && WIN_SRCCOPY == nROP ) ? WIN_SRCINVERT : nROP ); + ImplWriteSize( rSz ); + + rBmp.Write( aMemStm, sal_True, sal_False ); + + sal_uInt32 nDIBSize = aMemStm.Tell(), nHeaderSize, nCompression, nColsUsed, nPalCount, nImageSize; + sal_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 << (sal_uInt32) nBitCount ) ) : + ( ( 3 == nCompression ) ? 12 : 0 ); + + m_rStm.Write( aMemStm.GetData(), nDIBSize ); + + const sal_uLong nEndPos = m_rStm.Tell(); + m_rStm.Seek( nOffPos ); + m_rStm << (sal_uInt32) 80 << (sal_uInt32)( nHeaderSize + ( nPalCount << 2 ) ); + m_rStm << (sal_uInt32)( 80 + ( nHeaderSize + ( nPalCount << 2 ) ) ) << nImageSize; + m_rStm.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( rtl::OUString(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() ) ) ); + m_rStm << (sal_uInt32)1; + m_rStm << (sal_Int32) 0 << (sal_Int32) 0; + ImplWritePoint( rPos ); + m_rStm << (sal_uInt32) nLen << (sal_uInt32) 76 << (sal_uInt32) 2; + m_rStm << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) 0; + m_rStm << (sal_uInt32) ( 76 + ( nLen << 1 ) + ( (nLen & 1 ) ? 2 : 0 ) ); + + // write text + for( i = 0; i < nLen; i++ ) + m_rStm << (sal_Unicode)rText.GetChar( i ); + + // padding word + if( nLen & 1 ) + m_rStm << (sal_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), sal_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( size_t j = 0, nActionCount = rMtf.GetActionSize(); j < nActionCount; j++ ) + { + const MetaAction* pAction = rMtf.GetAction( j ); + const sal_uInt16 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, sal_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( size_t i = 0, nCount = aSubstitute.GetActionSize(); 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 ); + m_rStm << (sal_Int32) -1; + ImplEndRecord(); + break; + } + } + } + break; + + case META_BMP_ACTION: + { + const MetaBmpAction* pA = (const MetaBmpAction *) pAction; + ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), maVDev.PixelToLogic( 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(), maVDev.PixelToLogic( aMsk.GetSizePixel() ), WIN_SRCPAINT ); + ImplWriteBmpRecord( aBmp, pA->GetPoint(), maVDev.PixelToLogic( 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 = sal_True; + } + break; + + case( META_FILLCOLOR_ACTION ): + { + ( (MetaAction*) pAction )->Execute( &maVDev ); + mbFillChanged = sal_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 = sal_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 ); + m_rStm << (sal_Int32) -1; + ImplEndRecord(); + + ImplWriteRasterOp( maVDev.GetRasterOp() ); + mbLineChanged = mbFillChanged = mbTextChanged = sal_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: + OSL_FAIL(rtl::OStringBuffer(RTL_CONSTASCII_STRINGPARAM( + "EMFWriter::ImplWriteActions: unsupported MetaAction #" )). + append(static_cast<sal_Int32>(nType)).getStr()); + break; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/emfwr.hxx b/vcl/source/filter/wmf/emfwr.hxx new file mode 100644 index 000000000000..f930c352ae33 --- /dev/null +++ b/vcl/source/filter/wmf/emfwr.hxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef _EMFWR_HXX +#define _EMFWR_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& m_rStm; + sal_Bool* mpHandlesUsed; + sal_uLong mnHandleCount; + sal_uLong mnLastPercent; + sal_uLong mnRecordCount; + sal_uLong mnRecordPos; + sal_Bool mbRecordOpen; + sal_Bool mbLineChanged; + sal_uInt32 mnLineHandle; + sal_Bool mbFillChanged; + sal_uInt32 mnFillHandle; + sal_Bool mbTextChanged; + sal_uInt32 mnTextHandle; + sal_uInt32 mnHorTextAlign; + + void ImplBeginRecord( sal_uInt32 nType ); + void ImplEndRecord(); + + sal_uLong ImplAcquireHandle(); + void ImplReleaseHandle( sal_uLong nHandle ); + + sal_Bool ImplPrepareHandleSelect( sal_uInt32& rHandle, sal_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, sal_Bool bClose ); + void ImplWritePolyPolygonRecord( const PolyPolygon& rPolyPoly ); + void ImplWriteBmpRecord( const Bitmap& rBmp, const Point& rPt, const Size& rSz, sal_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(SvStream &rStream) : m_rStm(rStream) {} + + sal_Bool WriteEMF( const GDIMetaFile& rMtf, FilterConfigItem* pConfigItem = NULL ); +}; + +#endif // _EMFWR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/enhwmf.cxx b/vcl/source/filter/wmf/enhwmf.cxx new file mode 100644 index 000000000000..f8b98845be4e --- /dev/null +++ b/vcl/source/filter/wmf/enhwmf.cxx @@ -0,0 +1,1418 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "winmtf.hxx" +#include <osl/endian.h> +#include <boost/bind.hpp> + +using namespace std; +//=========================== 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 + +#if OSL_DEBUG_LEVEL > 1 +#define EMFP_DEBUG(x) x +#else +#define EMFP_DEBUG(x) +#endif + +//----------------------------------------------------------------------------------- + +#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 ) + { + OSL_FAIL( "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; +} + +EMFP_DEBUG(void dumpWords( SvStream& s, int i ) +{ + sal_uInt32 pos = s.Tell(); + sal_Int16 data; + for( ; i > 0; i -- ) { + s >> data; + EMFP_DEBUG(printf ("\t\t\tdata: %04hx\n", data)); + } + s.Seek (pos); +}); + +void EnhWMFReader::ReadEMFPlusComment(sal_uInt32 length, sal_Bool& bHaveDC) +{ + if (!bEMFPlus) { + pOut->PassEMFPlusHeaderInfo(); + + // debug code - write the stream to debug file /tmp/emf-stream.emf + EMFP_DEBUG(int pos = pWMF->Tell(); + pWMF->Seek(0); + SvFileStream file( rtl::OUString( "/tmp/emf-stream.emf" ), STREAM_WRITE | STREAM_TRUNC ); + + *pWMF >> file; + file.Flush(); + file.Close(); + + pWMF->Seek( pos );) + } + bEMFPlus = true; + + sal_Size pos = pWMF->Tell(); + void *buffer = malloc( length ); + pOut->PassEMFPlus( buffer, pWMF->Read( buffer, length ) ); + free( buffer ); + pWMF->Seek( pos ); + + bHaveDC = false; + + OSL_ASSERT(length >= 4); + //reduce by 32bit length itself, skip in SeekRel if + //impossibly unavailble + sal_uInt32 nRemainder = length >= 4 ? length-4 : length; + + const size_t nRequiredHeaderSize = 12; + while (nRemainder >= nRequiredHeaderSize) + { + sal_uInt16 type(0), flags(0); + sal_uInt32 size(0), dataSize(0); + + *pWMF >> type >> flags >> size >> dataSize; + nRemainder -= nRequiredHeaderSize; + + EMFP_DEBUG(printf ("\t\tEMF+ record type: %d\n", type)); + + // GetDC + if( type == 16388 ) { + bHaveDC = true; + EMFP_DEBUG(printf ("\t\tEMF+ lock DC (device context)\n")); + } + + //Get the length of the remaining data of this record based + //on the alleged size + sal_uInt32 nRemainingRecordData = size >= nRequiredHeaderSize ? + size-nRequiredHeaderSize : 0; + //clip to available size + nRemainingRecordData = std::min(nRemainingRecordData, nRemainder); + pWMF->SeekRel(nRemainingRecordData); + nRemainder -= nRemainingRecordData; + } + pWMF->SeekRel(nRemainder); +} + +/** + * Reads polygons from the stream. + * The <class T> parameter is for the type of the points (sal_uInt32 or sal_uInt16). + * The <class Drawer> parameter is a boost binding for the method that will draw the polygon. + * skipFirst: if the first point read is the 0th point or the 1st point in the array. + * */ +template <class T, class Drawer> +void EnhWMFReader::ReadAndDrawPolygon(Drawer drawer, const sal_Bool skipFirst) +{ + sal_uInt32 nPoints(0), nStartIndex(0); + pWMF->SeekRel( 16 ); + *pWMF >> nPoints; + if (skipFirst) + { + nPoints ++; + nStartIndex ++; + } + + Polygon aPolygon = ReadPolygon<T>(nStartIndex, nPoints); + drawer(pOut, aPolygon, skipFirst, bRecordPath); +} + + +/** + * Reads polygons from the stream. + * The <class T> parameter is for the type of the points + * nStartIndex: which is the starting index in the polygon of the first point read + * nPoints: number of points + * pWMF: the stream containings the polygons + * */ +template <class T> +Polygon EnhWMFReader::ReadPolygon(sal_uInt32 nStartIndex, sal_uInt32 nPoints) +{ + Polygon aPolygon(nPoints); + for (sal_uInt16 i = nStartIndex ; i < nPoints && pWMF->good(); i++ ) + { + T nX, nY; + *pWMF >> nX >> nY; + if (!pWMF->good()) + break; + aPolygon[ i ] = Point( nX, nY ); + } + + return aPolygon; +} + +/** + * Reads a polyline from the WMF file and draws it + * The <class T> parameter refers to the type of the points. (e.g. sal_uInt16 or sal_uInt32) + * */ +template <class T> +void EnhWMFReader::ReadAndDrawPolyLine() +{ + sal_uInt32 nPoints; + sal_Int32 i, nPoly(0), nGesPoints(0); + pWMF->SeekRel( 0x10 ); + // Number of Polygons: + *pWMF >> nPoly >> nGesPoints; + + // taking the amount of points of each polygon, retrieving the total number of points + if ( pWMF->good() && + ( static_cast< sal_uInt32 >(nPoly) < SAL_MAX_UINT32 / sizeof(sal_uInt16) ) && + ( static_cast< sal_uInt32 >( nPoly ) * sizeof(sal_uInt16) ) <= ( nEndPos - pWMF->Tell() ) + ) + { + sal_uInt16* pnPoints = new sal_uInt16[ nPoly ]; + for ( i = 0; i < nPoly && pWMF->good(); i++ ) + { + *pWMF >> nPoints; + pnPoints[ i ] = (sal_uInt16)nPoints; + } + // Get polygon points: + for ( i = 0; ( i < nPoly ) && pWMF->good(); i++ ) + { + Polygon aPolygon = ReadPolygon<T>(0, pnPoints[i]); + pOut->DrawPolyLine( aPolygon, sal_False, bRecordPath ); + } + delete[] pnPoints; + } +} + +/** + * Reads a poly polygon from the WMF file and draws it. + * The <class T> parameter refers to the type of the points. (e.g. sal_uInt16 or sal_uInt32) + * */ +template <class T> +void EnhWMFReader::ReadAndDrawPolyPolygon() +{ + sal_uInt32 i, nPoly, nGesPoints, nPoints; + pWMF->SeekRel( 0x10 ); + // Number of polygons + *pWMF >> nPoly >> nGesPoints; + if ( pWMF->good() && + ( nGesPoints < SAL_MAX_UINT32 / sizeof(Point) ) && //check against numeric overflowing + ( nPoly < SAL_MAX_UINT32 / sizeof(sal_uInt16) ) && + ( ( nPoly * sizeof( sal_uInt16 ) ) <= ( nEndPos - pWMF->Tell() ) )) + { + //Get number of points in each polygon + sal_uInt16 * pnPoints = new sal_uInt16[ nPoly ]; + for ( i = 0; i < nPoly && pWMF->good(); i++ ) + { + *pWMF >> nPoints; + pnPoints[ i ] = (sal_uInt16)nPoints; + } //end for + if ( pWMF->good() && ( nGesPoints * (sizeof(T)+sizeof(T)) ) <= ( nEndPos - pWMF->Tell() ) ) + { + // Get polygon points + Point * pPtAry = new Point[ nGesPoints ]; + for ( i = 0; i < nGesPoints && pWMF->good(); i++ ) + { + T nX, nY; + *pWMF >> nX >> nY; + pPtAry[ i ] = Point( nX, nY ); + } //end for + // Create PolyPolygon Actions + PolyPolygon aPolyPoly( (sal_uInt16)nPoly, pnPoints, pPtAry ); + pOut->DrawPolyPolygon( aPolyPoly, bRecordPath ); + delete[] pPtAry; + } //end if + delete[] pnPoints; + } //end if +} + +sal_Bool EnhWMFReader::ReadEnhWMF() +{ + sal_uInt32 nStretchBltMode = 0; + sal_uInt32 nRecType(0), nRecSize(0), nNextPos(0), + nW(0), nH(0), nColor(0), nIndex(0), + nDat32(0), nNom1(0), nDen1(0), nNom2(0), nDen2(0); + sal_Int32 nX32(0), nY32(0), nx32(0), ny32(0); + + sal_Bool bFlag(sal_False), bStatus = ReadHeader(); + sal_Bool bHaveDC = false; + + static sal_Bool bEnableEMFPlus = ( getenv( "EMF_PLUS_DISABLE" ) == NULL ); + + while( bStatus && nRecordCount-- && pWMF->good()) + { + *pWMF >> nRecType >> nRecSize; + + if ( !pWMF->good() || ( nRecSize < 8 ) || ( nRecSize & 3 ) ) // Parameters are always divisible by 4 + { + bStatus = sal_False; + break; + } + + nNextPos = pWMF->Tell() + ( nRecSize - 8 ); + + if ( !pWMF->good() || nNextPos > nEndPos ) + { + bStatus = sal_False; + break; + } + + if( !aBmpSaveList.empty() + && ( nRecType != EMR_STRETCHBLT ) + && ( nRecType != EMR_STRETCHDIBITS ) + ) + pOut->ResolveBitmapActions( aBmpSaveList ); + + bFlag = sal_False; + + EMFP_DEBUG(printf ("0x%04x-0x%04x record type: %d size: %d\n",(unsigned int) (nNextPos - nRecSize),(unsigned int) nNextPos, (int)nRecType,(int) nRecSize)); + + if( bEnableEMFPlus && nRecType == EMR_GDICOMMENT ) { + sal_uInt32 length; + + *pWMF >> length; + + EMFP_DEBUG(printf ("\tGDI comment\n\t\tlength: %d\n", (int)length)); + + if( pWMF->good() && length >= 4 ) { + sal_uInt32 id; + + *pWMF >> id; + + EMFP_DEBUG(printf ("\t\tbegin %c%c%c%c id: 0x%x\n", (char)(id & 0xff), (char)((id & 0xff00) >> 8), (char)((id & 0xff0000) >> 16), (char)((id & 0xff000000) >> 24), (unsigned int)id)); + + // EMF+ comment (fixme: BE?) + if( id == 0x2B464D45 && nRecSize >= 12 ) + ReadEMFPlusComment( length, bHaveDC ); + // GDIC comment, doesn't do anything useful yet + else if( id == 0x43494447 && nRecSize >= 12 ) { + //ToDo: ReadGDIComment() + } else { + EMFP_DEBUG(printf ("\t\tunknown id: 0x%x\n",(unsigned int) id)); + } + } + } else if( !bEMFPlus || bHaveDC || nRecType == EMR_EOF ) + + switch( nRecType ) + { + case EMR_POLYBEZIERTO : + ReadAndDrawPolygon<sal_Int32>(boost::bind(&WinMtfOutput::DrawPolyBezier, _1, _2, _3, _4), sal_True); + break; + case EMR_POLYBEZIER : + ReadAndDrawPolygon<sal_Int32>(boost::bind(&WinMtfOutput::DrawPolyBezier, _1, _2, _3, _4), sal_False); + break; + + case EMR_POLYGON : + ReadAndDrawPolygon<sal_Int32>(boost::bind(&WinMtfOutput::DrawPolygon, _1, _2, _3, _4), sal_False); + break; + + case EMR_POLYLINETO : + ReadAndDrawPolygon<sal_Int32>(boost::bind(&WinMtfOutput::DrawPolyLine, _1, _2, _3, _4), sal_True); + break; + case EMR_POLYLINE : + ReadAndDrawPolygon<sal_Int32>(boost::bind(&WinMtfOutput::DrawPolyLine, _1, _2, _3, _4), sal_False); + break; + + case EMR_POLYPOLYLINE : + ReadAndDrawPolyLine<sal_Int32>(); + break; + + case EMR_POLYPOLYGON : + ReadAndDrawPolyPolygon<sal_Int32>(); + 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 : + { + sal_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; + sal_uInt32 nStyle; + Size aSize; + //#fdo39428 Remove SvStream operator>>(long&) + sal_Int32 nTmpW(0), nTmpH(0); + + *pWMF >> nStyle >> nTmpW >> nTmpH; + aSize.Width() = nTmpW; + aSize.Height() = nTmpH; + + if ( aSize.Width() ) + aLineInfo.SetWidth( aSize.Width() ); + + sal_Bool bTransparent = sal_False; + sal_uInt16 nDashCount = 0; + sal_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 = 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( 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 : + { + sal_uInt32 nStyle; + *pWMF >> nIndex; + if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) + { + *pWMF >> nStyle; + pOut->CreateObject( nIndex, GDI_BRUSH, new WinMtfFillStyle( ReadColor(), ( nStyle == BS_HOLLOW ) ? sal_True : sal_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 : + { + sal_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 : + { + sal_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 : + { + sal_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 : + { + sal_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 ), sal_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 : + { + sal_Int32 xDest, yDest, cxDest, cyDest, xSrc, ySrc, cxSrc, cySrc; + sal_uInt32 dwRop, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc; + XForm xformSrc; + + sal_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, cyDest ) ); + + 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 = sal_False; + else + { + sal_uInt32 nSize = cbBmiSrc + cbBitsSrc + 14; + if ( nSize <= ( nEndPos - nStartPos ) ) + { + char* pBuf = new char[ nSize ]; + SvMemoryStream aTmp( pBuf, nSize, STREAM_READ | STREAM_WRITE ); + aTmp.ObjectOwnsMemory( sal_True ); + aTmp << (sal_uInt8)'B' + << (sal_uInt8)'M' + << (sal_uInt32)cbBitsSrc + << (sal_uInt16)0 + << (sal_uInt16)0 + << (sal_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, sal_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.push_back( new BSaveStruct( aBitmap, aRect, dwRop, pOut->GetFillStyle () ) ); + } + } + } + break; + + case EMR_STRETCHDIBITS : + { + sal_Int32 xDest, yDest, xSrc, ySrc, cxSrc, cySrc, cxDest, cyDest; + sal_uInt32 offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, iUsageSrc, dwRop; + sal_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, cyDest ) ); + + cxDest = abs( (int)cxDest ); // sj: i37894, size can be negative + cyDest = abs( (int)cyDest ); // and also 122889 + + if ( ((SAL_MAX_UINT32 - 14) < cbBitsSrc) + || ((SAL_MAX_UINT32 - 14) - cbBitsSrc < cbBmiSrc ) + ) + { + bStatus = sal_False; + } + else + { + sal_uInt32 nSize = cbBmiSrc + cbBitsSrc + 14; + if ( nSize <= ( nEndPos - nStartPos ) ) + { + char* pBuf = new char[ nSize ]; + SvMemoryStream aTmp( pBuf, nSize, STREAM_READ | STREAM_WRITE ); + aTmp.ObjectOwnsMemory( sal_True ); + aTmp << (sal_uInt8)'B' + << (sal_uInt8)'M' + << (sal_uInt32)cbBitsSrc + << (sal_uInt16)0 + << (sal_uInt16)0 + << (sal_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, sal_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.push_back( new BSaveStruct( aBitmap, aRect, dwRop, pOut->GetFillStyle () ) ); + } + } + } + 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++ ) + { + sal_uInt16 nChar; + *pWMF >> nChar; + lfFaceName[ i ] = nChar; + } + aLogFont.alfFaceName = rtl::OUString( 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; + sal_Int32* pOldDx = pDX; + pDX = new sal_Int32[ aText.Len() ]; + for ( i = 0, j = 0; i < aText.Len(); i++ ) + { + sal_Unicode cUniChar = aText.GetChar(i); + rtl::OString aCharacter(&cUniChar, 1, pOut->GetCharSet()); + pDX[ i ] = 0; + for (sal_Int32 k = 0; ( k < aCharacter.getLength() ) && ( 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 = rtl::OUString(pBuf, nLen); + delete[] pBuf; + } + } + pOut->DrawText( aPos, aText, pDX, bRecordPath, nGfxMode ); + } + delete[] pDX; + } + break; + + case EMR_POLYBEZIERTO16 : + ReadAndDrawPolygon<sal_Int16>(boost::bind(&WinMtfOutput::DrawPolyBezier, _1, _2, _3, _4), sal_True); + break; + case EMR_POLYBEZIER16 : + ReadAndDrawPolygon<sal_Int16>(boost::bind(&WinMtfOutput::DrawPolyBezier, _1, _2, _3, _4), sal_False); + break; + + case EMR_POLYGON16 : + ReadAndDrawPolygon<sal_Int16>(boost::bind(&WinMtfOutput::DrawPolygon, _1, _2, _3, _4), sal_False); + break; + + case EMR_POLYLINETO16 : + ReadAndDrawPolygon<sal_Int16>(boost::bind(&WinMtfOutput::DrawPolyLine, _1, _2, _3, _4), sal_True); + break; + case EMR_POLYLINE16 : + ReadAndDrawPolygon<sal_Int16>(boost::bind(&WinMtfOutput::DrawPolyLine, _1, _2, _3, _4), sal_False); + break; + + case EMR_POLYPOLYLINE16 : + ReadAndDrawPolyLine<sal_Int16>(); + break; + + case EMR_POLYPOLYGON16 : + ReadAndDrawPolyPolygon<sal_Int16>(); + 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; + + case EMR_CREATEDIBPATTERNBRUSHPT : + { + sal_uInt32 nStart = pWMF->Tell() - 8; + Bitmap aBitmap; + + *pWMF >> nIndex; + + if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) + { + sal_uInt32 usage, offBmi, cbBmi, offBits, cbBits; + + *pWMF >> usage; + *pWMF >> offBmi; + *pWMF >> cbBmi; + *pWMF >> offBits; + *pWMF >> cbBits; + + if ( (cbBits > (SAL_MAX_UINT32 - 14)) || ((SAL_MAX_UINT32 - 14) - cbBits < cbBmi) ) + bStatus = sal_False; + else if ( offBmi ) + { + sal_uInt32 nSize = cbBmi + cbBits + 14; + if ( nSize <= ( nEndPos - nStartPos ) ) + { + char* pBuf = new char[ nSize ]; + + SvMemoryStream aTmp( pBuf, nSize, STREAM_READ | STREAM_WRITE ); + aTmp.ObjectOwnsMemory( sal_True ); + aTmp << (sal_uInt8)'B' + << (sal_uInt8)'M' + << (sal_uInt32)cbBits + << (sal_uInt16)0 + << (sal_uInt16)0 + << (sal_uInt32)cbBmi + 14; + pWMF->Seek( nStart + offBmi ); + pWMF->Read( pBuf + 14, cbBmi ); + pWMF->Seek( nStart + offBits ); + pWMF->Read( pBuf + 14 + cbBmi, cbBits ); + aTmp.Seek( 0 ); + aBitmap.Read( aTmp, sal_True ); + } + } + } + + pOut->CreateObject( nIndex, GDI_BRUSH, new WinMtfFillStyle( aBitmap ) ); + } + 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_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.empty() ) + pOut->ResolveBitmapActions( aBmpSaveList ); + + if ( bStatus ) + pWMF->Seek(nEndPos); + + return bStatus; +}; + +//----------------------------------------------------------------------------------- + +sal_Bool EnhWMFReader::ReadHeader() +{ + sal_uInt32 nsal_uInt32, nHeaderSize, nPalEntries; + sal_Int32 nLeft, nTop, nRight, nBottom; + + // Spare me the METAFILEHEADER here + // Reading the METAHEADER + *pWMF >> nsal_uInt32 >> nHeaderSize; + if ( nsal_uInt32 != 1 ) // Type + return sal_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 >> nsal_uInt32; // signature + + if ( nsal_uInt32 != 0x464d4520 ) + return sal_False; + + *pWMF >> nsal_uInt32; // 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 sal_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 sal_True; +} + +//----------------------------------------------------------------------------------- + +Rectangle EnhWMFReader::ReadRectangle( sal_Int32 x1, sal_Int32 y1, sal_Int32 x2, sal_Int32 y2 ) +{ + Point aTL ( Point( x1, y1 ) ); + Point aBR( Point( --x2, --y2 ) ); + return Rectangle( aTL, aBR ); +} + +EnhWMFReader::~EnhWMFReader() +{ + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/winmtf.cxx b/vcl/source/filter/wmf/winmtf.cxx new file mode 100644 index 000000000000..63b0996b24a3 --- /dev/null +++ b/vcl/source/filter/wmf/winmtf.cxx @@ -0,0 +1,2239 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "winmtf.hxx" +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <vcl/metaact.hxx> +#include <vcl/graphictools.hxx> +#include <vcl/canvastools.hxx> +#include <vcl/metric.hxx> +#include <vcl/svapp.hxx> +#include <rtl/strbuf.hxx> +#include <rtl/tencinfo.h> + +// ------------------------------------------------------------------------ + +#if OSL_DEBUG_LEVEL > 1 +#define EMFP_DEBUG(x) x +#else +#define EMFP_DEBUG(x) +#endif + +void WinMtfClipPath::intersectClipRect( const Rectangle& rRect ) +{ + maClip.intersectRange( + vcl::unotools::b2DRectangleFromRectangle(rRect)); +} + +void WinMtfClipPath::excludeClipRect( const Rectangle& rRect ) +{ + maClip.subtractRange( + vcl::unotools::b2DRectangleFromRectangle(rRect)); +} + +void WinMtfClipPath::setClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode ) +{ + const basegfx::B2DPolyPolygon& rB2DPoly=rPolyPolygon.getB2DPolyPolygon(); + switch ( nClippingMode ) + { + case RGN_OR : + maClip.unionPolyPolygon(rB2DPoly); + break; + case RGN_XOR : + maClip.xorPolyPolygon(rB2DPoly); + break; + case RGN_DIFF : + maClip.subtractPolyPolygon(rB2DPoly); + break; + case RGN_AND : + maClip.intersectPolyPolygon(rB2DPoly); + break; + case RGN_COPY : + maClip = basegfx::tools::B2DClipState(rB2DPoly); + break; + } +} + +void WinMtfClipPath::moveClipRegion( const Size& rSize ) +{ + // what a weird concept. emulate, don't want this in B2DClipState + // API + basegfx::B2DPolyPolygon aCurrClip=maClip.getClipPoly(); + basegfx::B2DHomMatrix aTranslate; + aTranslate.translate(rSize.Width(), rSize.Height()); + + aCurrClip.transform(aTranslate); + maClip = basegfx::tools::B2DClipState( aCurrClip ); +} + +basegfx::B2DPolyPolygon WinMtfClipPath::getClipPath() const +{ + return maClip.getClipPoly(); +} + +// ------------------------------------------------------------------------ + +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 = RTL_TEXTENCODING_MS_1252; + else + eCharSet = rtl_getTextEncodingFromWindowsCharset( rFont.lfCharSet ); + if ( eCharSet == RTL_TEXTENCODING_DONTKNOW ) + eCharSet = RTL_TEXTENCODING_MS_1252; + 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 ) ) + { + rtl::OStringBuffer aText(RTL_CONSTASCII_STRINGPARAM( + "WMF/EMF Import: ")); + if (pAction) + aText.append(pAction); + aText.append(RTL_CONSTASCII_STRINGPARAM( + " needs to be implemented")); + DBG_ASSERT( 0, aText.getStr() ); + } + 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( sal_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( sal_uInt16 nPercent ) +{ + if ( xStatusIndicator.is() ) + xStatusIndicator->setValue( nPercent ); +} + +// ------------------------------------------------------------------------ + +Color WinMtf::ReadColor() +{ + sal_uInt32 nColor; + *pWMF >> nColor; + return Color( (sal_uInt8)nColor, (sal_uInt8)( nColor >> 8 ), (sal_uInt8)( nColor >> 16 ) ); +}; + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +Point WinMtfOutput::ImplMap( const Point& rPt ) +{ + if ( mnWinExtX && mnWinExtY ) + { + double fX = rPt.X(); + double fY = rPt.Y(); + + double fX2 = fX * maXForm.eM11 + fY * maXForm.eM21 + maXForm.eDx; + double fY2 = fX * maXForm.eM12 + fY * maXForm.eM22 + maXForm.eDy; + + if ( mnGfxMode == GM_COMPATIBLE ) + { + switch( mnMapMode ) + { + case MM_TEXT: + fX2 -= mnWinOrgX; + fY2 -= mnWinOrgY; + if( mnDevWidth != 1 || mnDevHeight != 1 ) { + fX2 *= 2540.0/mnUnitsPerInch; + fY2 *= 2540.0/mnUnitsPerInch; + } + fX2 += mnDevOrgX; + fY2 += mnDevOrgY; + fX2 *= (double)mnMillX * 100.0 / (double)mnPixX; + fY2 *= (double)mnMillY * 100.0 / (double)mnPixY; + + break; + 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_TEXT: + if( mnDevWidth != 1 && mnDevHeight != 1 ) { + fWidth *= 2540.0/mnUnitsPerInch; + fHeight*= 2540.0/mnUnitsPerInch; + } else { + fWidth *= (double)mnMillX * 100 / (double)mnPixX; + fHeight *= (double)mnMillY * 100 / (double)mnPixY; + } + break; + 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 ) +{ + sal_uInt16 nPoints = rPolygon.GetSize(); + for ( sal_uInt16 i = 0; i < nPoints; i++ ) + { + rPolygon[ i ] = ImplMap( rPolygon[ i ] ); + } + return rPolygon; +} + +//----------------------------------------------------------------------------------- + +PolyPolygon& WinMtfOutput::ImplMap( PolyPolygon& rPolyPolygon ) +{ + sal_uInt16 nPolys = rPolyPolygon.Count(); + for ( sal_uInt16 i = 0; i < nPolys; ImplMap( rPolyPolygon[ i++ ] ) ) ; + return rPolyPolygon; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SelectObject( sal_Int32 nIndex ) +{ + GDIObj* pGDIObj = NULL; + + if ( nIndex & ENHMETA_STOCK_OBJECT ) + pGDIObj = new GDIObj(); + else + { + nIndex &= 0xffff; // zur Sicherheit: mehr als 65535 nicht zulassen + + if ( (sal_uInt32)nIndex < vGDIObj.size() ) + pGDIObj = vGDIObj[ nIndex ]; + } + + if( pGDIObj == NULL ) + return; + + if ( nIndex & ENHMETA_STOCK_OBJECT ) + { + sal_uInt16 nStockId = (sal_uInt8)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 ), sal_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 ), sal_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; +} + +//----------------------------------------------------------------------------------- + +const Font& WinMtfOutput::GetFont() const +{ + return maFont; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetTextLayoutMode( const sal_uInt32 nTextLayoutMode ) +{ + mnTextLayoutMode = nTextLayoutMode; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetBkMode( sal_uInt32 nMode ) +{ + mnBkMode = nMode; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetBkColor( const Color& rColor ) +{ + maBkColor = rColor; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetTextColor( const Color& rColor ) +{ + maTextColor = rColor; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetTextAlign( sal_uInt32 nAlign ) +{ + mnTextAlign = nAlign; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ImplResizeObjectArry( sal_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 ); + } + } + } + sal_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( sal_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 ( (sal_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: + OSL_FAIL( "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 ) +{ + mbClipNeedsUpdate=true; + aClipPath.intersectClipRect( ImplMap( rRect ) ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ExcludeClipRect( const Rectangle& rRect ) +{ + mbClipNeedsUpdate=true; + aClipPath.excludeClipRect( ImplMap( rRect ) ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::MoveClipRegion( const Size& rSize ) +{ + mbClipNeedsUpdate=true; + aClipPath.moveClipRegion( ImplMap( rSize ) ); +} + +void WinMtfOutput::SetClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode, sal_Bool bIsMapped ) +{ + mbClipNeedsUpdate=true; + 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 ), + mbClipNeedsUpdate ( true ), + mbComplexClip ( false ), + mnGfxMode ( GM_COMPATIBLE ), + mnMapMode ( MM_TEXT ), + mnUnitsPerInch ( 96 ), + 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( RTL_TEXTENCODING_MS_1252 ); // 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 ( sal_uInt32 i = 0; i < vGDIObj.size(); i++ ) + delete vGDIObj[ i ]; +}; + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::UpdateClipRegion() +{ + if ( mbClipNeedsUpdate ) + { + mbClipNeedsUpdate = false; + mbComplexClip = false; + + mpGDIMetaFile->AddAction( new MetaPopAction() ); // taking the orignal clipregion + mpGDIMetaFile->AddAction( new MetaPushAction( PUSH_CLIPREGION ) ); // + + // skip for 'no clipping at all' case + if( !aClipPath.isEmpty() ) + { + const basegfx::B2DPolyPolygon& rClipPoly( aClipPath.getClipPath() ); + mpGDIMetaFile->AddAction( + new MetaISectRectClipRegionAction( + vcl::unotools::rectangleFromB2DRectangle( + rClipPoly.getB2DRange()))); + + mbComplexClip = rClipPoly.count() > 1 + || !basegfx::tools::isRectangle(rClipPoly); + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ImplSetNonPersistentLineColorTransparenz() +{ + Color aColor( COL_TRANSPARENT); + WinMtfLineStyle aTransparentLine( aColor, sal_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; + if (maFillStyle.aType == FillStyleSolid) + mpGDIMetaFile->AddAction( new MetaFillColorAction( maFillStyle.aFillColor, !maFillStyle.bTransparent ) ); + } +} + +//----------------------------------------------------------------------------------- + +sal_uInt32 WinMtfOutput::SetRasterOp( sal_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 ), sal_True ); + maLineStyle = WinMtfLineStyle( Color( COL_TRANSPARENT ), sal_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(), sal_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 ) + { + // fdo#57353 create new subpath for subsequent moves + if ( aPathObj.Count() ) + if ( aPathObj[ aPathObj.Count() - 1 ].GetSize() ) + aPathObj.Insert( Polygon(), POLYPOLY_APPEND ); + 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::DrawRect( const Rectangle& rRect, sal_Bool bEdge ) +{ + UpdateClipRegion(); + UpdateFillStyle(); + + if ( mbComplexClip ) + { + Polygon aPoly( ImplMap( rRect ) ); + PolyPolygon aPolyPolyRect( aPoly ); + PolyPolygon aDest; + PolyPolygon(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, sal_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 ( mbComplexClip ) + { + PolyPolygon aPolyPoly( rPolygon ); + PolyPolygon aDest; + PolyPolygon(aClipPath.getClipPath()).GetIntersection( aPolyPoly, aDest ); + ImplDrawClippedPolyPolygon( aDest ); + } + else + { + if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) ) + { + sal_uInt16 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(); + + if (maLatestFillStyle.aType != FillStylePattern) + mpGDIMetaFile->AddAction( new MetaPolygonAction( rPolygon ) ); + else { + SvtGraphicFill aFill = SvtGraphicFill( PolyPolygon( rPolygon ), + Color(), + 0.0, + SvtGraphicFill::fillNonZero, + SvtGraphicFill::fillTexture, + SvtGraphicFill::Transform(), + true, + SvtGraphicFill::hatchSingle, + Color(), + SvtGraphicFill::gradientLinear, + Color(), + Color(), + 0, + Graphic (maLatestFillStyle.aBmp) ); + + SvMemoryStream aMemStm; + + aMemStm << aFill; + + mpGDIMetaFile->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_BEGIN", 0, + static_cast<const sal_uInt8*>(aMemStm.GetData()), + aMemStm.Seek( STREAM_SEEK_TO_END ) ) ); + mpGDIMetaFile->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_END" ) ); + } + + } + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawPolyPolygon( PolyPolygon& rPolyPolygon, sal_Bool bRecordPath ) +{ + UpdateClipRegion(); + + ImplMap( rPolyPolygon ); + + if ( bRecordPath ) + aPathObj.AddPolyPolygon( rPolyPolygon ); + else + { + UpdateFillStyle(); + + if ( mbComplexClip ) + { + PolyPolygon aDest; + PolyPolygon(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++ ) + { + if ( i ) { + pDXArry[ i - 1 ] = ImplMap( Size( nSum, 0 ) ).Width(); + } + nSum += pDXArry[ i ]; + } + } + 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 ) + { + sal_uInt32 nLen = rText.Len(); + nTextWidth = pVDev->GetTextWidth( rtl::OUString(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 ) + { + SolarMutexGuard aGuard; + + 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 ( mbComplexClip ) + { + 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( sal_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( BSaveStructList_impl& rSaveList ) +{ + UpdateClipRegion(); + + size_t nObjects = rSaveList.size(); + size_t nObjectsLeft = nObjects; + + while ( nObjectsLeft ) + { + size_t i; + size_t nObjectsOfSameSize = 0; + size_t nObjectStartIndex = nObjects - nObjectsLeft; + + BSaveStruct* pSave = rSaveList[ nObjectStartIndex ]; + Rectangle aRect( pSave->aOutRect ); + + for ( i = nObjectStartIndex; i < nObjects; ) + { + nObjectsOfSameSize++; + if ( ++i < nObjects ) + { + pSave = rSaveList[ i ]; + if ( pSave->aOutRect != aRect ) + break; + } + } + Point aPos( ImplMap( aRect.TopLeft() ) ); + Size aSize( ImplMap( aRect.GetSize() ) ); + + for ( i = nObjectStartIndex; i < ( nObjectStartIndex + nObjectsOfSameSize ); i++ ) + { + pSave = rSaveList[ 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) && nWinRop != PATINVERT ) + { // patterns aren't well supported yet + sal_uInt32 nOldRop = SetRasterOp( ROP_OVERPAINT ); // in this case nRasterOperation is either 0 or 0xff + UpdateFillStyle(); + DrawRect( aRect, sal_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 = rSaveList[ 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, sal_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, sal_False ); + } + } + break; + + case 0x4 : + case 0xb : + { + SetRasterOp( R2_NOT ); + DrawRect( aRect, sal_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, sal_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, sal_False ); + } + } + break; + case 0x6 : + case 0x9 : + { + SetRasterOp( R2_XORPEN ); + ImplDrawBitmap( aPos, aSize, aBitmap ); + if ( nOperation == 0x9 ) + { + SetRasterOp( R2_NOT ); + DrawRect( aRect, sal_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, sal_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, sal_False ); + } + case 0xa : // no operation + break; + } + SetRasterOp( nOldRop ); + Pop(); + } + } + } + nObjectsLeft -= nObjectsOfSameSize; + } + + for( size_t i = 0, n = rSaveList.size(); i < n; ++i ) + delete rSaveList[ i ]; + rSaveList.clear(); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetDevOrg( const Point& rPoint ) +{ + mnDevOrgX = rPoint.X(); + mnDevOrgY = rPoint.Y(); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetDevOrgOffset( sal_Int32 nXAdd, sal_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( sal_Int32 nXAdd, sal_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::SetUnitsPerInch( sal_uInt16 nUnitsPerInch ) +{ + if( nUnitsPerInch != 0 ) + mnUnitsPerInch = nUnitsPerInch; +} + +//----------------------------------------------------------------------------------- + +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, sal_uInt32 nMode ) +{ + switch( nMode ) + { + case MWT_IDENTITY : + { + maXForm.eM11 = maXForm.eM12 = maXForm.eM21 = maXForm.eM22 = 1.0f; + maXForm.eDx = maXForm.eDy = 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.empty() ) + { + // 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; + mbClipNeedsUpdate = true; + } + if ( meLatestRasterOp != meRasterOp ) + mpGDIMetaFile->AddAction( new MetaRasterOpAction( meRasterOp ) ); + vSaveStack.pop_back(); + } +} + +void WinMtfOutput::AddFromGDIMetaFile( GDIMetaFile& rGDIMetaFile ) +{ + rGDIMetaFile.Play( *mpGDIMetaFile, 0xFFFFFFFF ); +} + +void WinMtfOutput::PassEMFPlusHeaderInfo() +{ + EMFP_DEBUG(printf ("\t\t\tadd EMF_PLUS header info\n")); + + SvMemoryStream mem; + sal_Int32 nLeft, nRight, nTop, nBottom; + + nLeft = mrclFrame.Left(); + nTop = mrclFrame.Top(); + nRight = mrclFrame.Right(); + nBottom = mrclFrame.Bottom(); + + // emf header info + mem << nLeft << nTop << nRight << nBottom; + mem << mnPixX << mnPixY << mnMillX << mnMillY; + + float one, zero; + + one = 1; + zero = 0; + + // add transformation matrix to be used in vcl's metaact.cxx for + // rotate and scale operations + mem << one << zero << zero << one << zero << zero; + + // need to flush the stream, otherwise GetEndOfData will return 0 + // on windows where the function parameters are probably resolved in reverse order + mem.Flush(); + + mpGDIMetaFile->AddAction( new MetaCommentAction( "EMF_PLUS_HEADER_INFO", 0, (const sal_uInt8*) mem.GetData(), mem.GetEndOfData() ) ); + mpGDIMetaFile->UseCanvas( sal_True ); +} + +void WinMtfOutput::PassEMFPlus( void* pBuffer, sal_uInt32 nLength ) +{ + EMFP_DEBUG(printf ("\t\t\tadd EMF_PLUS comment length %04x\n",(unsigned int) nLength)); + mpGDIMetaFile->AddAction( new MetaCommentAction( "EMF_PLUS", 0, static_cast<const sal_uInt8*>(pBuffer), nLength ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/winmtf.hxx b/vcl/source/filter/wmf/winmtf.hxx new file mode 100644 index 000000000000..bc368e6e6baa --- /dev/null +++ b/vcl/source/filter/wmf/winmtf.hxx @@ -0,0 +1,890 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef _WINMTF_HXX +#define _WINMTF_HXX + +#ifdef DBG_UTIL +#define WIN_MTF_ASSERT +#endif + +#include <sot/object.hxx> +#include <boost/shared_ptr.hpp> +#include <vcl/graph.hxx> +#include <vcl/virdev.hxx> +#include <basegfx/tools/b2dclipstate.hxx> +#include <vcl/font.hxx> +#include <vcl/bmpacc.hxx> +#include <vcl/lineinfo.hxx> +#include <svtools/fltcall.hxx> + +#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 +{ + sal_Int32 lfHeight; + sal_Int32 lfWidth; + sal_Int32 lfEscapement; + sal_Int32 lfOrientation; + sal_Int32 lfWeight; + sal_uInt8 lfItalic; + sal_uInt8 lfUnderline; + sal_uInt8 lfStrikeOut; + sal_uInt8 lfCharSet; + sal_uInt8 lfOutPrecision; + sal_uInt8 lfClipPrecision; + sal_uInt8 lfQuality; + sal_uInt8 lfPitchAndFamily; + String alfFaceName; +}; +struct WMF_EXTERNALHEADER; + +#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 + +class WinMtfClipPath +{ + basegfx::tools::B2DClipState maClip; + +public : + WinMtfClipPath(): maClip() {}; + + void setClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode ); + void intersectClipRect( const Rectangle& rRect ); + void excludeClipRect( const Rectangle& rRect ); + void moveClipRegion( const Size& rSize ); + + bool isEmpty() const { return maClip.isCleared(); } + + basegfx::B2DPolyPolygon getClipPath() const; + + bool operator==( const WinMtfClipPath& rPath ) const + { + return maClip == rPath.maClip; + }; +}; + +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 ); +}; + +// ----------------------------------------------------------------------------- + +typedef enum { + FillStyleSolid, + FillStylePattern +} WinMtfFillStyleType; + +struct WinMtfFillStyle +{ + Color aFillColor; + sal_Bool bTransparent; + WinMtfFillStyleType aType; + Bitmap aBmp; + + WinMtfFillStyle() + : aFillColor(Color(COL_BLACK)) + , bTransparent(sal_False) + , aType(FillStyleSolid) + { + } + + WinMtfFillStyle( const Color& rColor, sal_Bool bTrans = sal_False ) + : aFillColor(rColor) + , bTransparent(bTrans) + , aType(FillStyleSolid) + { + } + + WinMtfFillStyle(Bitmap& rBmp) + : aType(FillStylePattern) + , aBmp(rBmp) + { + } + + sal_Bool operator==( const WinMtfFillStyle& rStyle ) + { + return ( ( aFillColor == rStyle.aFillColor ) + && ( bTransparent == rStyle.bTransparent ) + && ( aType == rStyle.aType ) + ); + } + sal_Bool operator==( WinMtfFillStyle* pStyle ) + { + return ( ( aFillColor == pStyle->aFillColor ) + && ( bTransparent == pStyle->bTransparent ) + && ( aType == pStyle->aType ) + ); + } + WinMtfFillStyle& operator=( const WinMtfFillStyle& rStyle ) + { + aFillColor = rStyle.aFillColor; + bTransparent = rStyle.bTransparent; + aBmp = rStyle.aBmp; + aType = rStyle.aType; + return *this; + } + WinMtfFillStyle& operator=( WinMtfFillStyle* pStyle ) + { + aFillColor = pStyle->aFillColor; + bTransparent = pStyle->bTransparent; + aBmp = pStyle->aBmp; + aType = pStyle->aType; + return *this; + } +}; + +// ----------------------------------------------------------------------------- + +struct WinMtfLineStyle +{ + Color aLineColor; + LineInfo aLineInfo; + sal_Bool bTransparent; + + WinMtfLineStyle() : + aLineColor ( COL_BLACK ), + bTransparent( sal_False ) {} + + WinMtfLineStyle( const Color& rColor, sal_Bool bTrans = sal_False ) : + aLineColor ( rColor ), + bTransparent( bTrans ) {} + + WinMtfLineStyle( const Color& rColor, const LineInfo& rStyle, sal_Bool bTrans = sal_False ) : + aLineColor ( rColor ), + aLineInfo ( rStyle ), + bTransparent( bTrans ) {} + + sal_Bool operator==( const WinMtfLineStyle& rStyle ) + { + return ( ( aLineColor == rStyle.aLineColor ) + && ( bTransparent == rStyle.bTransparent ) + && ( aLineInfo == rStyle.aLineInfo ) + ); + } + sal_Bool operator==( WinMtfLineStyle* pStyle ) + { + return ( ( aLineColor == pStyle->aLineColor ) + && ( bTransparent == pStyle->bTransparent ) + && ( aLineInfo == pStyle->aLineInfo ) + ); + } + WinMtfLineStyle& operator=( const WinMtfLineStyle& rStyle ) + { + aLineColor = rStyle.aLineColor; + bTransparent = rStyle.bTransparent; + aLineInfo = rStyle.aLineInfo; + return *this; + } + + WinMtfLineStyle& operator=( WinMtfLineStyle* pStyle ) + { + aLineColor = pStyle->aLineColor; + bTransparent = pStyle->bTransparent; + aLineInfo = pStyle->aLineInfo; + return *this; + } +}; + +// ----------------------------------------------------------------------------- + +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; + sal_uInt32 nWinRop; + WinMtfFillStyle aStyle; + + BSaveStruct( + const Bitmap& rBmp, + const Rectangle& rOutRect, + sal_uInt32 nRop, + WinMtfFillStyle& rStyle + ) + : aBmp( rBmp ) + , aOutRect( rOutRect ) + , nWinRop( nRop ) + , aStyle ( rStyle ) + {} +}; + +typedef ::std::vector< BSaveStruct* > BSaveStructList_impl; + +// ----------------------------------------------------------------------------- + +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: + OSL_FAIL( "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; + sal_Bool mbClipNeedsUpdate; + sal_Bool mbComplexClip; + + std::vector< SaveStructPtr > vSaveStack; + + sal_uInt32 mnGfxMode; + sal_uInt32 mnMapMode; + sal_uInt16 mnUnitsPerInch; + + 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( sal_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( sal_Int32 nXAdd, sal_Int32 nYAdd ); + void SetDevExt( const Size& rSize ); + void ScaleDevExt( double fX, double fY ); + + void SetWinOrg( const Point& rPoint ); + void SetWinOrgOffset( sal_Int32 nX, sal_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 SetUnitsPerInch( sal_uInt16 nUnitsPerInch ); + void SetWorldTransform( const XForm& rXForm ); + void ModifyWorldTransform( const XForm& rXForm, sal_uInt32 nMode ); + + void Push(); + void Pop(); + + sal_uInt32 SetRasterOp( sal_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( sal_uInt32 nMode ); + void SetBkColor( const Color& rColor ); + void SetTextColor( const Color& rColor ); + void SetTextAlign( sal_uInt32 nAlign ); + void CreateObject( GDIObjectType, void* pStyle = NULL ); + void CreateObject( sal_Int32 nIndex, GDIObjectType, void* pStyle = NULL ); + void DeleteObject( sal_Int32 nIndex ); + void SelectObject( sal_Int32 nIndex ); + CharSet GetCharSet(){ return maFont.GetCharSet(); }; + WinMtfFillStyle& GetFillStyle () { return maFillStyle; } + const Font& GetFont() const; + void SetTextLayoutMode( const sal_uInt32 nLayoutMode ); + + 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 DrawRect( const Rectangle& rRect, sal_Bool bEdge = sal_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, + sal_Bool bDrawTo = sal_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 DrawPolygon( Polygon& rPolygon, sal_Bool /*bDrawTo*/, sal_Bool bRecordPath) + { + //For ReadAndDrawPolygon template compatibility + DrawPolygon(rPolygon, bRecordPath); + } + 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( BSaveStructList_impl& 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 ); + + void PassEMFPlus( void* pBuffer, sal_uInt32 nLength ); + void PassEMFPlusHeaderInfo(); + + WinMtfOutput( GDIMetaFile& rGDIMetaFile ); + virtual ~WinMtfOutput(); +}; + +// ----------------------------------------------------------------------------- + +class WinMtf +{ +protected: + + WinMtfOutput* pOut; + SvStream* pWMF; // Die einzulesende WMF/EMF-Datei + + sal_uInt32 nStartPos, nEndPos; + BSaveStructList_impl 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( sal_uInt16 nPercent ); + + WinMtf( + WinMtfOutput* pOut, + SvStream& rStreamWMF, + FilterConfigItem* pConfigItem = NULL + ); + ~WinMtf(); +}; + +//============================ EMFReader ================================== + +class EnhWMFReader : public WinMtf +{ + sal_Bool bRecordPath; + sal_Int32 nRecordCount; + sal_Bool bEMFPlus; + + + sal_Bool ReadHeader(); + // Liesst und konvertiert ein Rechteck + Rectangle ReadRectangle( sal_Int32, sal_Int32, sal_Int32, sal_Int32 ); + void ImplExtTextOut( sal_Bool bWideCharakter ); + +public: + EnhWMFReader( + SvStream& rStreamWMF, + GDIMetaFile& rGDIMetaFile, + FilterConfigItem* pConfigItem = NULL + ) + : WinMtf( new WinMtfOutput( rGDIMetaFile ) + , rStreamWMF + , pConfigItem ) + , bRecordPath( sal_False ) + , bEMFPlus( sal_False ) + {}; + ~EnhWMFReader(); + + sal_Bool ReadEnhWMF(); + void ReadEMFPlusComment(sal_uInt32 length, sal_Bool& bHaveDC); +private: + template <class T> void ReadAndDrawPolyPolygon(); + template <class T> void ReadAndDrawPolyLine(); + template <class T> Polygon ReadPolygon(sal_uInt32 nStartIndex, sal_uInt32 nPoints); + template <class T, class Drawer> void ReadAndDrawPolygon(Drawer drawer, const sal_Bool skipFirst); +}; + +//============================ WMFReader ================================== + +class WMFReader : public WinMtf +{ +private: + + VirtualDevice aVDev; // just for the purpose of "IsFontAvailable" + sal_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; + + WMF_EXTERNALHEADER* pExternalHeader; + + // Liesst den Kopf der WMF-Datei + sal_Bool ReadHeader(); + + // Liesst die Parameter des Rocords mit der Funktionsnummer nFunction. + void ReadRecordParams( sal_uInt16 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, + WMF_EXTERNALHEADER* pExtHeader = NULL + ) + : WinMtf( new WinMtfOutput( rGDIMetaFile ), rStreamWMF, pConfigItem ) + , pEMFStream(NULL), + pExternalHeader(pExtHeader) + {} + + ~WMFReader(); + + // Liesst aus dem Stream eine WMF-Datei und fuellt das GDIMetaFile + void ReadWMF(); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/winwmf.cxx b/vcl/source/filter/wmf/winwmf.cxx new file mode 100644 index 000000000000..f9f38e09eb92 --- /dev/null +++ b/vcl/source/filter/wmf/winwmf.cxx @@ -0,0 +1,1503 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "winmtf.hxx" +#include <boost/scoped_array.hpp> +#include <vcl/gdimtf.hxx> +#include <svtools/wmf.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 + +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 ); +} + +//=================== Methods of WMFReader ============================== + +inline Point WMFReader::ReadPoint() +{ + short nX = 0, nY = 0; + *pWMF >> nX >> nY; + return Point( nX, nY ); +} + +// ------------------------------------------------------------------------ + +inline Point WMFReader::ReadYX() +{ + short nX = 0, nY = 0; + *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=0, nH=0; + *pWMF >> nH >> nW; + return Size( nW, nH ); +} + +// ------------------------------------------------------------------------ + +void WMFReader::ReadRecordParams( sal_uInt16 nFunc ) +{ + switch( nFunc ) + { + case W_META_SETBKCOLOR: + { + pOut->SetBkColor( ReadColor() ); + } + break; + + case W_META_SETBKMODE: + { + sal_uInt16 nDat = 0; + *pWMF >> nDat; + pOut->SetBkMode( nDat ); + } + break; + + // !!! + case W_META_SETMAPMODE: + { + sal_Int16 nMapMode = 0; + *pWMF >> nMapMode; + pOut->SetMapMode( nMapMode ); + } + break; + + case W_META_SETROP2: + { + sal_uInt16 nROP2 = 0; + *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 = 0, nHeight = 0; + *pWMF >> nHeight >> nWidth; + pOut->SetWinExt( Size( nWidth, nHeight ) ); + } + break; + + case W_META_OFFSETWINDOWORG: + { + short nXAdd = 0, nYAdd = 0; + *pWMF >> nYAdd >> nXAdd; + pOut->SetWinOrgOffset( nXAdd, nYAdd ); + } + break; + + case W_META_SCALEWINDOWEXT: + { + short nXNum = 0, nXDenom = 0, nYNum = 0, nYDenom = 0; + *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 = 0, nYAdd = 0; + *pWMF >> nYAdd >> nXAdd; + pOut->SetDevOrgOffset( nXAdd, nYAdd ); + } + break; + + case W_META_SCALEVIEWPORTEXT: + { + short nXNum = 0, nXDenom = 0, nYNum = 0, nYDenom = 0; + *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: + { + sal_uInt16 nPoints = 0; + *pWMF >> nPoints; + Polygon aPoly( nPoints ); + for( sal_uInt16 i = 0; i < nPoints; i++ ) + aPoly[ i ] = ReadPoint(); + pOut->DrawPolygon( aPoly ); + } + break; + + case W_META_POLYPOLYGON: + { + bool bRecordOk = true; + sal_uInt16 nPoly = 0; + Point* pPtAry; + // Number of polygons: + *pWMF >> nPoly; + // Number of points of each polygon. Determine total number of points + boost::scoped_array<sal_uInt16> xPolygonPointCounts(new sal_uInt16[nPoly]); + sal_uInt16* pnPoints = xPolygonPointCounts.get(); + sal_uInt16 nPoints = 0; + for(sal_uInt16 i = 0; i < nPoly; i++ ) + { + *pWMF >> pnPoints[i]; + + if (pnPoints[i] > SAL_MAX_UINT16 - nPoints) + { + bRecordOk = false; + break; + } + + nPoints += pnPoints[i]; + } + + SAL_WARN_IF(!bRecordOk, "svtools.filter", "polypolygon record has more polygons than we can handle"); + + bRecordOk &= pWMF->good(); + + if (!bRecordOk) + { + pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); + break; + } + + // Polygon points are: + boost::scoped_array<Point> xPolygonPoints(new Point[nPoints]); + pPtAry = xPolygonPoints.get(); + for (sal_uInt16 i = 0; i < nPoints; i++ ) + pPtAry[ i ] = ReadPoint(); + + bRecordOk &= pWMF->good(); + + if (!bRecordOk) + { + pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); + break; + } + + // Produce PolyPolygon Actions + PolyPolygon aPolyPoly( nPoly, pnPoints, pPtAry ); + pOut->DrawPolyPolygon( aPolyPoly ); + } + break; + + case W_META_POLYLINE: + { + sal_uInt16 nPoints = 0; + *pWMF >> nPoints; + Polygon aPoly( nPoints ); + for(sal_uInt16 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: + { + sal_uInt16 nLength = 0; + *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_uInt16 nLen = 0, nOptions = 0; + sal_Int32 nRecordPos, nRecordSize = 0, 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 = sal_False; + + if ( ( ( nDxAryEntries % nOriginalTextLen ) == 0 ) && ( nNewTextLen <= nOriginalTextLen ) ) + { + sal_Int16 nDx = 0, nDxTmp = 0; + sal_uInt16 i; //needed just outside the for + pDXAry = new sal_Int32[ nNewTextLen ]; + for (i = 0; i < nNewTextLen; i++ ) + { + if ( pWMF->Tell() >= nMaxStreamPos ) + break; + *pWMF >> nDx; + if ( nNewTextLen != nOriginalTextLen ) + { + sal_Unicode nUniChar = aText.GetChar(i); + rtl::OString aTmp(&nUniChar, 1, pOut->GetCharSet()); + if ( aTmp.getLength() > 1 ) + { + sal_Int32 nDxCount = aTmp.getLength() - 1; + if ( ( ( nDxCount * 2 ) + pWMF->Tell() ) > nMaxStreamPos ) + break; + while ( nDxCount-- ) + { + *pWMF >> nDxTmp; + nDx = nDx + nDxTmp; + } + } + } + pDXAry[ i ] = nDx; + } + if ( i == nNewTextLen ) + bUseDXAry = sal_True; + } + if ( pDXAry && bUseDXAry ) + pOut->DrawText( aPosition, aText, pDXAry ); + else + pOut->DrawText( aPosition, aText ); + } + } + delete[] pDXAry; + + } + break; + + case W_META_SELECTOBJECT: + { + sal_Int16 nObjIndex = 0; + *pWMF >> nObjIndex; + pOut->SelectObject( nObjIndex ); + } + break; + + case W_META_SETTEXTALIGN: + { + sal_uInt16 nAlign = 0; + *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 = 0; + sal_uInt16 nSx = 0, nSy = 0, nSxe = 0, nSye = 0, nDontKnow = 0, nWidth = 0, nHeight = 0, nBytesPerScan = 0; + 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 ) + { + for (sal_uInt16 y = 0; y < nHeight; y++ ) + { + sal_uInt16 x = 0; + for (sal_uInt16 scan = 0; scan < nBytesPerScan; scan++ ) + { + sal_Int8 nEightPixels = 0; + *pWMF >> nEightPixels; + for (sal_Int8 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.push_back( new BSaveStruct( aBmp, aDestRect, nWinROP, pOut->GetFillStyle () ) ); + } + } + } + break; + + case W_META_STRETCHBLT: + case W_META_DIBBITBLT: + case W_META_DIBSTRETCHBLT: + case W_META_STRETCHDIB: + { + sal_Int32 nWinROP = 0; + sal_uInt16 nSx = 0, nSy = 0, nSxe = 0, nSye = 0, nUsage = 0; + 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 they are set to zero, it is as indicator not to scale the bitmap later + // + if( nFunc == W_META_STRETCHDIB || nFunc == W_META_STRETCHBLT || nFunc == W_META_DIBSTRETCHBLT ) + *pWMF >> nSye >> nSxe; + + // 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 ), sal_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, sal_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.push_back( new BSaveStruct( aBmp, aDestRect, nWinROP, pOut->GetFillStyle () ) ); + } + } + } + break; + + case W_META_DIBCREATEPATTERNBRUSH: + { + Bitmap aBmp; + BitmapReadAccess* pBmp; + sal_uInt32 nRed = 0, nGreen = 0, nBlue = 0, nCount = 1; + sal_uInt16 nFunction = 0; + + *pWMF >> nFunction >> nFunction; + + aBmp.Read( *pWMF, sal_False ); + pBmp = aBmp.AcquireReadAccess(); + if ( pBmp ) + { + for ( sal_Int32 y = 0; y < pBmp->Height(); y++ ) + { + for ( sal_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( (sal_uInt8)( nRed / nCount ), (sal_uInt8)( nGreen / nCount ), (sal_uInt8)( nBlue / nCount ) ); + pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( aColor, sal_False ) ); + } + break; + + case W_META_DELETEOBJECT: + { + sal_Int16 nIndex = 0; + *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 ), sal_False ) ); + } + break; + + case W_META_CREATEPATTERNBRUSH: + { + pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ), sal_False ) ); + } + break; + + case W_META_CREATEPENINDIRECT: + { + LineInfo aLineInfo; + sal_uInt16 nStyle = 0, nWidth = 0, nHeight = 0; + + *pWMF >> nStyle >> nWidth >> nHeight; + + if ( nWidth ) + aLineInfo.SetWidth( nWidth ); + + sal_Bool bTransparent = sal_False; + sal_uInt16 nDashCount = 0; + sal_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 = 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( GDI_PEN, new WinMtfLineStyle( ReadColor(), aLineInfo, bTransparent ) ); + } + break; + + case W_META_CREATEBRUSHINDIRECT: + { + sal_uInt16 nStyle = 0; + *pWMF >> nStyle; + pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( ReadColor(), ( nStyle == BS_HOLLOW ) ? sal_True : sal_False ) ); + } + break; + + case W_META_CREATEFONTINDIRECT: + { + Size aFontSize; + char lfFaceName[ LF_FACESIZE ]; + sal_Int16 lfEscapement = 0, lfOrientation = 0, lfWeight = 0; // ( formerly sal_uInt16 ) + + 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 = osl_getThreadTextEncoding(); + else + eCharSet = rtl_getTextEncodingFromWindowsCharset( aLogFont.lfCharSet ); + if ( eCharSet == RTL_TEXTENCODING_DONTKNOW ) + eCharSet = osl_getThreadTextEncoding(); + 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: + { + sal_uInt32 nROP = 0, nOldROP = 0; + *pWMF >> nROP; + Size aSize = ReadYXExt(); + nOldROP = pOut->SetRasterOp( nROP ); + pOut->DrawRect( Rectangle( ReadYX(), aSize ), sal_False ); + pOut->SetRasterOp( nOldROP ); + } + break; + + case W_META_SELECTCLIPREGION: + { + sal_Int16 nObjIndex = 0; + *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 = 0, nLen = 0; + *pWMF >> nMode + >> nLen; + if ( ( nMode == W_MFCOMMENT ) && ( nLen >= 4 ) ) + { + sal_uInt32 nNewMagic = 0; // we have to read int32 for + *pWMF >> nNewMagic; // META_ESCAPE_ENHANCED_METAFILE CommentIdentifier + + if( nNewMagic == 0x2c2a4f4f && nLen >= 14 ) + { + sal_uInt16 nMagic2 = 0; + *pWMF >> nMagic2; + if( nMagic2 == 0x0a ) // 2nd half of magic + { // continue with private escape + sal_uInt32 nCheck = 0, nEsc = 0; + *pWMF >> nCheck + >> nEsc; + + sal_uInt32 nEscLen = nLen - 14; + if ( nEscLen <= ( nRecSize * 2 ) ) + { +#ifdef OSL_BIGENDIAN + sal_uInt32 nTmp = OSL_SWAPDWORD( 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 nStringLen, nDXCount; + sal_Int32* pDXAry = NULL; + SvMemoryStream aMemoryStream( nEscLen ); + aMemoryStream.Write( pData, nEscLen ); + aMemoryStream.Seek( STREAM_SEEK_TO_BEGIN ); + //#fdo39428 SvStream no longer supports operator>>(long&) + sal_Int32 nTmpX(0), nTmpY(0); + aMemoryStream >> nTmpX + >> nTmpY + >> nStringLen; + aPt.X() = nTmpX; + aPt.Y() = nTmpY; + + if ( ( static_cast< sal_uInt64 >( nStringLen ) * sizeof( sal_Unicode ) ) < ( nEscLen - aMemoryStream.Tell() ) ) + { + + aString = read_uInt16s_ToOUString(aMemoryStream, nStringLen); + aMemoryStream >> nDXCount; + if ( ( static_cast< sal_uInt64 >( nDXCount ) * sizeof( sal_Int32 ) ) >= ( nEscLen - aMemoryStream.Tell() ) ) + nDXCount = 0; + if ( nDXCount ) + pDXAry = new sal_Int32[ nDXCount ]; + for (sal_uInt32 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 = 0, nVersion = 0, nFlags = 0, nComRecCount = 0, + nCurRecSize = 0, nRemainingSize = 0, nEMFTotalSize = 0; + sal_uInt16 nCheck = 0; + + *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; + } +} + +// ------------------------------------------------------------------------ + +sal_Bool WMFReader::ReadHeader() +{ + sal_Size nStrmPos = pWMF->Tell(); + + sal_uInt32 nPlaceableMetaKey(0); + // Einlesen des METAFILEHEADER, falls vorhanden + *pWMF >> nPlaceableMetaKey; + if (!pWMF->good()) + return false; + + Rectangle aPlaceableBound; + + if (nPlaceableMetaKey == 0x9ac6cdd7L) + { //TODO do some real error handling here + sal_Int16 nVal; + + // Skip reserved bytes + 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 ); + + // Skip and don't check the checksum + 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 ); + if ( pExternalHeader != NULL && ( pExternalHeader->mapMode == MM_ISOTROPIC + || pExternalHeader->mapMode == MM_ANISOTROPIC ) ) + { + // #n417818#: If we have an external header then overwrite the bounds! + Rectangle aExtRect(0, 0, + pExternalHeader->xExt*567*nUnitsPerInch/1440/1000, + pExternalHeader->yExt*567*nUnitsPerInch/1440/1000); + GetWinExtMax( aExtRect, aPlaceableBound, pExternalHeader->mapMode ); + pOut->SetMapMode( pExternalHeader->mapMode ); + } + } + + pOut->SetUnitsPerInch( nUnitsPerInch ); + pOut->SetWinOrg( aPlaceableBound.TopLeft() ); + Size aWMFSize( 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 + sal_uInt32 nMetaKey(0); + *pWMF >> nMetaKey; // Typ und Headergroesse + if (!pWMF->good()) + return false; + if (nMetaKey != 0x00090001) + { + sal_uInt16 aNextWord(0); + *pWMF >> aNextWord; + if (nMetaKey != 0x10000 || aNextWord != 0x09) + { + 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 pWMF->good(); +} + +void WMFReader::ReadWMF() +{ + sal_uInt16 nFunction; + sal_uLong nPos, nPercent, nLastPercent; + + nSkipActions = 0; + nCurrentAction = 0; + nUnicodeEscapeAction = 0; + + pEMFStream = NULL; + nEMFRecCount = 0; + nEMFRec = 0; + nEMFSize = 0; + + sal_Bool bEMFAvailable = sal_False; + + 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( (sal_uInt16) ( nLastPercent = 0 ) ); + + if ( ReadHeader( ) ) + { + + nPos = pWMF->Tell(); + + if( nEndPos - nStartPos ) + { + while( sal_True ) + { + nCurrentAction++; + nPercent = ( nPos - nStartPos ) * 100 / ( nEndPos - nStartPos ); + + if( nLastPercent + 4 <= nPercent ) + { + Callback( (sal_uInt16) 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 ( !bEMFAvailable ) + { + if( !aBmpSaveList.empty() + && ( 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 ); + bEMFAvailable = pEMFReader->ReadEnhWMF(); + delete pEMFReader; // destroy first!!! + + if( bEMFAvailable ) + { + pOut->AddFromGDIMetaFile( aMeta ); + pOut->SetrclFrame( Rectangle( Point(0, 0), aMeta.GetPrefSize())); + + // the stream needs to be set to the wmf end position, + // otherwise the GfxLink that is created will be incorrect + // (leading to graphic loss after swapout/swapin). + // so we will proceed normally, but are ignoring further wmf + // records + } + 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.empty() ) + pOut->ResolveBitmapActions( aBmpSaveList ); + } + if ( pWMF->GetError() ) + pWMF->Seek( nStartPos ); +} + +// ------------------------------------------------------------------------ + +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_uInt32 nPos = pStm->Tell(); + sal_uInt32 nEnd = pStm->Seek( STREAM_SEEK_TO_END ); + + pStm->Seek( nPos ); + + if( nEnd - nPos ) + { + sal_Int16 nMapMode = MM_ANISOTROPIC; + sal_uInt16 nFunction; + sal_uInt32 nRSize; + + 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: + { + sal_Int16 nWidth(0), nHeight(0); + *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: + ReadYXExt(); // size + GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode ); + break; + + case W_META_ARC: + case W_META_PIE: + case W_META_CHORD: + ReadYX(); // end + ReadYX(); // start + GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode ); + break; + + case W_META_POLYGON: + { + sal_uInt16 nPoints; + *pStm >> nPoints; + for(sal_uInt16 i = 0; i < nPoints; i++ ) + GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode ); + } + break; + + case W_META_POLYPOLYGON: + { + bool bRecordOk = true; + sal_uInt16 nPoly, nPoints = 0; + *pStm >> nPoly; + for(sal_uInt16 i = 0; i < nPoly; i++ ) + { + sal_uInt16 nP = 0; + *pStm >> nP; + if (nP > SAL_MAX_UINT16 - nPoints) + { + bRecordOk = false; + break; + } + nPoints += nP; + } + + SAL_WARN_IF(!bRecordOk, "svtools.filter", "polypolygon record has more polygons than we can handle"); + + bRecordOk &= pStm->good(); + + if (!bRecordOk) + { + pStm->SetError( SVSTREAM_FILEFORMAT_ERROR ); + bRet = sal_False; + break; + } + + for (sal_uInt16 i = 0; i < nPoints; i++ ) + GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode ); + + bRecordOk &= pStm->good(); + + if (!bRecordOk) + { + pStm->SetError( SVSTREAM_FILEFORMAT_ERROR ); + bRet = sal_False; + break; + } + } + break; + + case W_META_POLYLINE: + { + sal_uInt16 nPoints; + *pStm >> nPoints; + for(sal_uInt16 i = 0; i < nPoints; i++ ) + GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode ); + } + break; + + case W_META_SETPIXEL: + { + ReadColor(); + GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode ); + } + break; + + case W_META_TEXTOUT: + { + sal_uInt16 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; + Point aPosition; + + 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 ), sal_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: + { + sal_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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/wmf.cxx b/vcl/source/filter/wmf/wmf.cxx new file mode 100644 index 000000000000..9c3b7e6dc0e7 --- /dev/null +++ b/vcl/source/filter/wmf/wmf.cxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "winmtf.hxx" +#include "emfwr.hxx" +#include "wmfwr.hxx" +#include <svtools/wmf.hxx> +#include <comphelper/scopeguard.hxx> + +// ----------------------------------------------------------------------------- + +sal_Bool ConvertWMFToGDIMetaFile( SvStream & rStreamWMF, GDIMetaFile & rGDIMetaFile, FilterConfigItem* pConfigItem, WMF_EXTERNALHEADER *pExtHeader ) +{ + sal_uInt32 nMetaType; + sal_uInt32 nOrgPos = rStreamWMF.Tell(); + sal_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() == sal_False ) + rStreamWMF.SetError( SVSTREAM_FILEFORMAT_ERROR ); + } + else + { + WMFReader( rStreamWMF, rGDIMetaFile, pConfigItem, pExtHeader ).ReadWMF( ); + } + rStreamWMF.SetNumberFormatInt( nOrigNumberFormat ); + return !rStreamWMF.GetError(); +} + +// ----------------------------------------------------------------------------- + +sal_Bool ReadWindowMetafile( SvStream& rStream, GDIMetaFile& rMTF, FilterConfigItem* pFilterConfigItem ) +{ + sal_uInt32 nMetaType(0); + sal_uInt32 nOrgPos = rStream.Tell(); + + sal_uInt16 nOrigNumberFormat = rStream.GetNumberFormatInt(); + rStream.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + //exception-safe reset nOrigNumberFormat at end of scope + const ::comphelper::ScopeGuard aScopeGuard( + boost::bind(&SvStream::SetNumberFormatInt, ::boost::ref(rStream), + nOrigNumberFormat)); + + rStream.Seek( 0x28 ); + rStream >> nMetaType; + rStream.Seek( nOrgPos ); + + if (!rStream.good()) + return false; + + if ( nMetaType == 0x464d4520 ) + { + if ( EnhWMFReader( rStream, rMTF, NULL ).ReadEnhWMF() == sal_False ) + rStream.SetError( SVSTREAM_FILEFORMAT_ERROR ); + } + else + { + WMFReader( rStream, rMTF, pFilterConfigItem ).ReadWMF(); + } + + return rStream.good(); +} + +// ----------------------------------------------------------------------------- + +sal_Bool ConvertGDIMetaFileToWMF( const GDIMetaFile & rMTF, SvStream & rTargetStream, + FilterConfigItem* pConfigItem, sal_Bool bPlaceable) +{ + WMFWriter aWMFWriter; + return aWMFWriter.WriteWMF( rMTF, rTargetStream, pConfigItem, bPlaceable ); +} + +// ----------------------------------------------------------------------------- + +sal_Bool ConvertGDIMetaFileToEMF( const GDIMetaFile & rMTF, SvStream & rTargetStream, + FilterConfigItem* pConfigItem ) +{ + EMFWriter aEMFWriter(rTargetStream); + return aEMFWriter.WriteEMF( rMTF, pConfigItem ); +} + +// ----------------------------------------------------------------------------- + +sal_Bool WriteWindowMetafileBits( SvStream& rStream, const GDIMetaFile& rMTF ) +{ + return WMFWriter().WriteWMF( rMTF, rStream, NULL, sal_False ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/wmfwr.cxx b/vcl/source/filter/wmf/wmfwr.cxx new file mode 100644 index 000000000000..c9baef6b36f5 --- /dev/null +++ b/vcl/source/filter/wmf/wmfwr.cxx @@ -0,0 +1,2052 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "wmfwr.hxx" +#include <unotools/fontcvt.hxx> +#include "emfwr.hxx" +#include <rtl/crc.h> +#include <rtl/tencinfo.h> +#include <tools/bigint.hxx> +#include <tools/helpers.hxx> +#include <tools/tenccvt.hxx> +#include <osl/endian.h> +#include <i18nutil/unicode.hxx> //unicode::getUnicodeScriptType + +#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 + +//========================== Methoden von WMFWriter ========================== + +void WMFWriter::MayCallback() +{ + if ( xStatusIndicator.is() ) + { + sal_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 ) +{ + size_t nAction, nActionCount; + + nActionCount = rMTF.GetActionSize(); + + 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 << (sal_uInt8) rColor.GetRed() << (sal_uInt8) rColor.GetGreen() << (sal_uInt8) rColor.GetBlue() << (sal_uInt8) 0; +} + + +void WMFWriter::WriteRecordHeader(sal_uInt32 nSizeWords, sal_uInt16 nType) +{ + nActRecordPos=pWMF->Tell(); + if (nSizeWords>nMaxRecordSize) nMaxRecordSize=nSizeWords; + *pWMF << nSizeWords << nType; +} + + +void WMFWriter::UpdateRecordHeader() +{ + sal_uLong nPos; + sal_uInt32 nSize; + + nPos=pWMF->Tell(); nSize=nPos-nActRecordPos; + if ((nSize & 1)!=0) { + *pWMF << (sal_uInt8)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 << (sal_uInt16) W_BS_HOLLOW; + else + *pWMF << (sal_uInt16) W_BS_SOLID; + + WriteColor( rColor ); + *pWMF << (sal_uInt16) 0; +} + + +void WMFWriter::WMFRecord_CreateFontIndirect(const Font & rFont) +{ + sal_uInt16 nWeight,i; + sal_uInt8 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 << (sal_uInt8)0; else *pWMF << (sal_uInt8)1; + if (rFont.GetUnderline()==UNDERLINE_NONE) *pWMF << (sal_uInt8)0; else *pWMF << (sal_uInt8)1; + if (rFont.GetStrikeout()==STRIKEOUT_NONE) *pWMF << (sal_uInt8)0; else *pWMF << (sal_uInt8)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 << (sal_uInt8)0 << (sal_uInt8)0 << (sal_uInt8)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; + + rtl::OString aFontName(rtl::OUStringToOString(rFont.GetName(), eFontNameEncoding)); + for ( i = 0; i < W_LF_FACESIZE; i++ ) + { + sal_Char nChar = ( i < aFontName.getLength() ) ? aFontName[i] : 0; + *pWMF << nChar; + } + UpdateRecordHeader(); +} + +void WMFWriter::WMFRecord_CreatePenIndirect(const Color& rColor, const LineInfo& rLineInfo ) +{ + WriteRecordHeader(0x00000008,W_META_CREATEPENINDIRECT); + sal_uInt16 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(sal_uInt16 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 = OSL_SWAPDWORD( 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(); + rtl::OString aByteStr(rtl::OUStringToOString(rUniStr, aTextEncodingOrg)); + rtl::OUString aUniStr2(rtl::OStringToOUString(aByteStr, aTextEncodingOrg)); + const sal_Unicode* pConversion = aUniStr2.getStr(); // 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 = getBestMSEncodingByChar(*pCheckChar); // try the first character + for ( i = 1; i < nStringLen; i++) + { + if (aTextEncoding != aTextEncodingOrg) // found something + break; + pCheckChar++; + aTextEncoding = getBestMSEncodingByChar(*pCheckChar); // try the next character + } + + aByteStr = rtl::OUStringToOString(rUniStr, aTextEncoding); + aUniStr2 = rtl::OStringToOUString(aByteStr, aTextEncoding); + pConversion = aUniStr2.getStr(); // 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 << static_cast<sal_Int32>(aPt.X()) + << static_cast<sal_Int32>(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(); + rtl::OString aByteString(rtl::OUStringToOString(rString, eChrSet)); + TrueExtTextOut(rPoint,rString,aByteString,pDXAry); +} + +void WMFWriter::TrueExtTextOut( const Point & rPoint, const String & rString, + const rtl::OString& rByteString, const sal_Int32 * pDXAry ) +{ + WriteRecordHeader( 0, W_META_EXTTEXTOUT ); + WritePointYX( rPoint ); + sal_uInt16 nNewTextLen = static_cast<sal_uInt16>(rByteString.getLength()); + *pWMF << nNewTextLen << (sal_uInt16)0; + write_uInt8s_FromOString(*pWMF, rByteString, nNewTextLen); + 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 (sal_uInt16 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 (sal_uInt16 i = 0; i < nOriginalTextLen; ++i) + { + sal_Int16 nDx = pConvertedDXAry[ i ]; + *pWMF << nDx; + if ( nOriginalTextLen < nNewTextLen ) + { + sal_Unicode nUniChar = rString.GetChar(i); + rtl::OString aTemp(&nUniChar, 1, aSrcFont.GetCharSet()); + j = aTemp.getLength(); + 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) +{ + sal_uInt16 nSize,i; + + Polygon aSimplePoly; + if ( rPoly.HasFlags() ) + rPoly.AdaptiveSubdivide( aSimplePoly ); + else + aSimplePoly = rPoly; + nSize = aSimplePoly.GetSize(); + WriteRecordHeader(((sal_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) +{ + sal_uInt16 nSize,i; + Polygon aSimplePoly; + if ( rPoly.HasFlags() ) + rPoly.AdaptiveSubdivide( aSimplePoly ); + else + aSimplePoly = rPoly; + nSize=aSimplePoly.GetSize(); + WriteRecordHeader(((sal_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; + sal_uInt16 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 << ((sal_uInt16)(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(sal_uInt16 nObjectHandle) +{ + WriteRecordHeader(0x00000004,W_META_SELECTOBJECT); + *pWMF << nObjectHandle; +} + + +void WMFWriter::WMFRecord_SetBkMode(sal_Bool bTransparent) +{ + WriteRecordHeader(0x00000004,W_META_SETBKMODE); + if (bTransparent==sal_True) *pWMF << (sal_uInt16)W_TRANSPARENT; + else *pWMF << (sal_uInt16)W_OPAQUE; +} + +void WMFWriter::WMFRecord_SetStretchBltMode() +{ + WriteRecordHeader( 0x00000004, W_META_SETSTRETCHBLTMODE ); + *pWMF << (sal_uInt16) 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) +{ + sal_uInt16 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, sal_uInt32 eHorTextAlign) +{ + sal_uInt16 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 ) +{ + sal_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 << (sal_Int32)0 << (sal_Int32)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(); + rtl::OString aString(rtl::OUStringToOString(rStr, eChrSet)); + TrueTextOut(rPoint, aString); +} + +void WMFWriter::TrueTextOut(const Point & rPoint, const rtl::OString& rString) +{ + WriteRecordHeader(0,W_META_TEXTOUT); + + write_lenPrefixed_uInt8s_FromOString<sal_uInt16>(*pWMF, rString); + sal_Int32 nLen = rString.getLength(); + if ((nLen&1)!=0) *pWMF << (sal_uInt8)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); +} + + +sal_uInt16 WMFWriter::AllocHandle() +{ + sal_uInt16 i; + + for (i=0; i<MAXOBJECTHANDLES; i++) { + if (bHandleAllocated[i]==sal_False) { + bHandleAllocated[i]=sal_True; + return i; + } + } + bStatus=sal_False; + return 0xffff; +} + + +void WMFWriter::FreeHandle(sal_uInt16 nObjectHandle) +{ + if (nObjectHandle<MAXOBJECTHANDLES) bHandleAllocated[nObjectHandle]=sal_False; +} + + +void WMFWriter::CreateSelectDeletePen( const Color& rColor, const LineInfo& rLineInfo ) +{ + sal_uInt16 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) +{ + sal_uInt16 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) +{ + sal_uInt16 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==sal_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 ) +{ + MetaAction* pMA; + + if( bStatus ) + { + size_t nACount = rMTF.GetActionSize(); + + WMFRecord_SetStretchBltMode(); + + for( size_t 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.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() ); + + size_t nCount = aGDIMetaFile.GetActionSize(); + for ( size_t 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: + { + OSL_FAIL( "Unsupported action: MetaMask...Action!" ); + } + break; + + case META_CLIPREGION_ACTION: + break; + + case META_ISECTREGIONCLIPREGION_ACTION: + { + OSL_FAIL( "Unsupported action: MetaISectRegionClipRegionAction!" ); + } + break; + + case META_MOVECLIPREGION_ACTION: + { + OSL_FAIL( "Unsupported action: MetaMoveClipRegionAction!" ); + } + break; + + default: + { + OSL_FAIL( "Unsupported meta action!" ); + } + break; + } + + nWrittenActions++; + MayCallback(); + + if (pWMF->GetError()) + bStatus=sal_False; + + if(bStatus==sal_False) + break; + } + } +} + +// ------------------------------------------------------------------------ + +void WMFWriter::WriteHeader( const GDIMetaFile &, sal_Bool bPlaceable ) +{ + if( bPlaceable ) + { + sal_uInt16 nCheckSum, nValue; + Size aSize( pVirDev->LogicToLogic(Size(1,1),MapMode(MAP_INCH), aTargetMapMode) ); + sal_uInt16 nUnitsPerInch = (sal_uInt16) ( ( 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=(sal_uInt16) aTargetSize.Width(); nCheckSum^=nValue; *pWMF << nValue; + nValue=(sal_uInt16) 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() +{ + sal_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 << (sal_uInt8)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); +} + +// ------------------------------------------------------------------------ + +sal_Bool WMFWriter::WriteWMF( const GDIMetaFile& rMTF, SvStream& rTargetStream, + FilterConfigItem* pFConfigItem, sal_Bool bPlaceable ) +{ + WMFWriterAttrStackMember * pAt; + + bEmbedEMF = sal_True; + bStatus=sal_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 (sal_uInt16 i=0; i<MAXOBJECTHANDLES; i++) + bHandleAllocated[i]=sal_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( sal_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 = sal_False; + + Font aFont; + aFont.SetCharSet( GetExtendedTextEncoding( RTL_TEXTENCODING_MS_1252 ) ); + 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; +} + +// ------------------------------------------------------------------------ + +sal_uInt16 WMFWriter::CalcSaveTargetMapMode(MapMode& rMapMode, + const Size& rPrefSize) +{ + Fraction aDivFrac(2, 1); + sal_uInt16 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 ) +{ + SvMemoryStream aStream; + EMFWriter aEMFWriter(aStream); + + if( aEMFWriter.WriteEMF( rMTF ) ) + { + 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(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/wmfwr.hxx b/vcl/source/filter/wmf/wmfwr.hxx new file mode 100644 index 000000000000..f71abaa8ea93 --- /dev/null +++ b/vcl/source/filter/wmf/wmfwr.hxx @@ -0,0 +1,220 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef _WMFWR_HXX +#define _WMFWR_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: + + sal_Bool bStatus; + + sal_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; + sal_uInt16 nTargetDivisor; + + sal_uLong nMetafileHeaderPos; + sal_uInt32 nMaxRecordSize; // in Worten + sal_uLong nActRecordPos; + + // Aktuelle Attribute im Quell-Metafile: + Color aSrcLineColor; + Color aSrcFillColor; + Color aSrcTextColor; + LineInfo aSrcLineInfo; + RasterOp eSrcRasterOp; + FontAlign eSrcTextAlign; + Font aSrcFont; + MapMode aSrcMapMode; + sal_Bool bSrcIsClipping; + Region aSrcClipRegion; + WMFWriterAttrStackMember * pAttrStack; + + sal_uInt32 eSrcHorTextAlign; + + // Aktuelle Attribute im Ziel-Metafile: + Color aDstLineColor; + Color aDstFillColor; + Color aDstTextColor; + LineInfo aDstLineInfo; + RasterOp eDstROP2; + FontAlign eDstTextAlign; + Font aDstFont; + + sal_uInt32 eDstHorTextAlign; + + sal_Bool bDstIsClipping; // ???: derzeit unberuecksichtigt + Region aDstClipRegion; // ???: derzeit unberuecksichtigt + sal_Bool bHandleAllocated[MAXOBJECTHANDLES]; // Welche Handles vergeben sind + sal_uInt16 nDstPenHandle,nDstFontHandle,nDstBrushHandle; // Welche Handles die jeweiligen + // Selected-Objects besitzen + // 0xffff = keines: + + // Damit nicht bei jeder Operation alle Attribute verglichen werden muessen: + + sal_uLong nNumberOfActions; // Anzahl der Actions im GDIMetafile + sal_uLong nNumberOfBitmaps; // Anzahl der Bitmaps + sal_uLong nWrittenActions; // Anzahl der bereits verarbeiteten Actions beim Schreiben der Orders + sal_uLong nWrittenBitmaps; // Anzahl der bereits geschriebenen Bitmaps + sal_uLong nActBitmapPercent; // Wieviel Prozent die naechste Bitmap schon geschrieben ist. + + sal_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(sal_uInt16 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 rtl::OString& rByteString, const sal_Int32 * pDXAry); + void TrueTextOut(const Point & rPoint, const rtl::OString& 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(sal_uInt16 nObjectHandle); + void WMFRecord_SetBkMode(sal_Bool bTransparent); + void WMFRecord_SetStretchBltMode(); + void WMFRecord_SetPixel(const Point & rPoint, const Color & rColor); + void WMFRecord_SetROP2(RasterOp eROP); + void WMFRecord_SetTextAlign(FontAlign eFontAlign, sal_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); + + sal_uInt16 AllocHandle(); + void FreeHandle(sal_uInt16 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, sal_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 ); + + sal_uInt16 CalcSaveTargetMapMode(MapMode& rMapMode, const Size& rPrefSize); + +public: + + WMFWriter() {} + + sal_Bool WriteWMF(const GDIMetaFile & rMTF, SvStream & rTargetStream, FilterConfigItem* pFilterConfigItem, sal_Bool bPlaceable=sal_True); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |