/* -*- 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 #include #include #include #include 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 namespace { const char * record_type_name(sal_uInt32 nRecType) { #ifndef SAL_LOG_INFO (void) nRecType; return ""; #else switch( nRecType ) { case EMR_HEADER: return "HEADER"; case EMR_POLYBEZIER: return "POLYBEZIER"; case EMR_POLYGON: return "POLYGON"; case EMR_POLYLINE: return "POLYLINE"; case EMR_POLYBEZIERTO: return "POLYBEZIERTO"; case EMR_POLYLINETO: return "POLYLINETO"; case EMR_POLYPOLYLINE: return "POLYPOLYLINE"; case EMR_POLYPOLYGON: return "POLYPOLYGON"; case EMR_SETWINDOWEXTEX: return "SETWINDOWEXTEX"; case EMR_SETWINDOWORGEX: return "SETWINDOWORGEX"; case EMR_SETVIEWPORTEXTEX: return "SETVIEWPORTEXTEX"; case EMR_SETVIEWPORTORGEX: return "SETVIEWPORTORGEX"; case EMR_SETBRUSHORGEX: return "SETBRUSHORGEX"; case EMR_EOF: return "EOF"; case EMR_SETPIXELV: return "SETPIXELV"; case EMR_SETMAPPERFLAGS: return "SETMAPPERFLAGS"; case EMR_SETMAPMODE: return "SETMAPMODE"; case EMR_SETBKMODE: return "SETBKMODE"; case EMR_SETPOLYFILLMODE: return "SETPOLYFILLMODE"; case EMR_SETROP2: return "SETROP2"; case EMR_SETSTRETCHBLTMODE: return "SETSTRETCHBLTMODE"; case EMR_SETTEXTALIGN: return "SETTEXTALIGN"; case EMR_SETCOLORADJUSTMENT: return "SETCOLORADJUSTMENT"; case EMR_SETTEXTCOLOR: return "SETTEXTCOLOR"; case EMR_SETBKCOLOR: return "SETBKCOLOR"; case EMR_OFFSETCLIPRGN: return "OFFSETCLIPRGN"; case EMR_MOVETOEX: return "MOVETOEX"; case EMR_SETMETARGN: return "SETMETARGN"; case EMR_EXCLUDECLIPRECT: return "EXCLUDECLIPRECT"; case EMR_INTERSECTCLIPRECT: return "INTERSECTCLIPRECT"; case EMR_SCALEVIEWPORTEXTEX: return "SCALEVIEWPORTEXTEX"; case EMR_SCALEWINDOWEXTEX: return "SCALEWINDOWEXTEX"; case EMR_SAVEDC: return "SAVEDC"; case EMR_RESTOREDC: return "RESTOREDC"; case EMR_SETWORLDTRANSFORM: return "SETWORLDTRANSFORM"; case EMR_MODIFYWORLDTRANSFORM: return "MODIFYWORLDTRANSFORM"; case EMR_SELECTOBJECT: return "SELECTOBJECT"; case EMR_CREATEPEN: return "CREATEPEN"; case EMR_CREATEBRUSHINDIRECT: return "CREATEBRUSHINDIRECT"; case EMR_DELETEOBJECT: return "DELETEOBJECT"; case EMR_ANGLEARC: return "ANGLEARC"; case EMR_ELLIPSE: return "ELLIPSE"; case EMR_RECTANGLE: return "RECTANGLE"; case EMR_ROUNDRECT: return "ROUNDRECT"; case EMR_ARC: return "ARC"; case EMR_CHORD: return "CHORD"; case EMR_PIE: return "PIE"; case EMR_SELECTPALETTE: return "SELECTPALETTE"; case EMR_CREATEPALETTE: return "CREATEPALETTE"; case EMR_SETPALETTEENTRIES: return "SETPALETTEENTRIES"; case EMR_RESIZEPALETTE: return "RESIZEPALETTE"; case EMR_REALIZEPALETTE: return "REALIZEPALETTE"; case EMR_EXTFLOODFILL: return "EXTFLOODFILL"; case EMR_LINETO: return "LINETO"; case EMR_ARCTO: return "ARCTO"; case EMR_POLYDRAW: return "POLYDRAW"; case EMR_SETARCDIRECTION: return "SETARCDIRECTION"; case EMR_SETMITERLIMIT: return "SETMITERLIMIT"; case EMR_BEGINPATH: return "BEGINPATH"; case EMR_ENDPATH: return "ENDPATH"; case EMR_CLOSEFIGURE: return "CLOSEFIGURE"; case EMR_FILLPATH: return "FILLPATH"; case EMR_STROKEANDFILLPATH: return "STROKEANDFILLPATH"; case EMR_STROKEPATH: return "STROKEPATH"; case EMR_FLATTENPATH: return "FLATTENPATH"; case EMR_WIDENPATH: return "WIDENPATH"; case EMR_SELECTCLIPPATH: return "SELECTCLIPPATH"; case EMR_ABORTPATH: return "ABORTPATH"; case EMR_GDICOMMENT: return "GDICOMMENT"; case EMR_FILLRGN: return "FILLRGN"; case EMR_FRAMERGN: return "FRAMERGN"; case EMR_INVERTRGN: return "INVERTRGN"; case EMR_PAINTRGN: return "PAINTRGN"; case EMR_EXTSELECTCLIPRGN: return "EXTSELECTCLIPRGN"; case EMR_BITBLT: return "BITBLT"; case EMR_STRETCHBLT: return "STRETCHBLT"; case EMR_MASKBLT: return "MASKBLT"; case EMR_PLGBLT: return "PLGBLT"; case EMR_SETDIBITSTODEVICE: return "SETDIBITSTODEVICE"; case EMR_STRETCHDIBITS: return "STRETCHDIBITS"; case EMR_EXTCREATEFONTINDIRECTW: return "EXTCREATEFONTINDIRECTW"; case EMR_EXTTEXTOUTA: return "EXTTEXTOUTA"; case EMR_EXTTEXTOUTW: return "EXTTEXTOUTW"; case EMR_POLYBEZIER16: return "POLYBEZIER16"; case EMR_POLYGON16: return "POLYGON16"; case EMR_POLYLINE16: return "POLYLINE16"; case EMR_POLYBEZIERTO16: return "POLYBEZIERTO16"; case EMR_POLYLINETO16: return "POLYLINETO16"; case EMR_POLYPOLYLINE16: return "POLYPOLYLINE16"; case EMR_POLYPOLYGON16: return "POLYPOLYGON16"; case EMR_POLYDRAW16: return "POLYDRAW16"; case EMR_CREATEMONOBRUSH: return "CREATEMONOBRUSH"; case EMR_CREATEDIBPATTERNBRUSHPT: return "CREATEDIBPATTERNBRUSHPT"; case EMR_EXTCREATEPEN: return "EXTCREATEPEN"; case EMR_POLYTEXTOUTA: return "POLYTEXTOUTA"; case EMR_POLYTEXTOUTW: return "POLYTEXTOUTW"; case EMR_SETICMMODE: return "SETICMMODE"; case EMR_CREATECOLORSPACE: return "CREATECOLORSPACE"; case EMR_SETCOLORSPACE: return "SETCOLORSPACE"; case EMR_DELETECOLORSPACE: return "DELETECOLORSPACE"; case EMR_GLSRECORD: return "GLSRECORD"; case EMR_GLSBOUNDEDRECORD: return "GLSBOUNDEDRECORD"; case EMR_PIXELFORMAT: return "PIXELFORMAT"; case EMR_DRAWESCAPE: return "DRAWESCAPE"; case EMR_EXTESCAPE: return "EXTESCAPE"; case EMR_STARTDOC: return "STARTDOC"; case EMR_SMALLTEXTOUT: return "SMALLTEXTOUT"; case EMR_FORCEUFIMAPPING: return "FORCEUFIMAPPING"; case EMR_NAMEDESCAPE: return "NAMEDESCAPE"; case EMR_COLORCORRECTPALETTE: return "COLORCORRECTPALETTE"; case EMR_SETICMPROFILEA: return "SETICMPROFILEA"; case EMR_SETICMPROFILEW: return "SETICMPROFILEW"; case EMR_ALPHABLEND: return "ALPHABLEND"; case EMR_ALPHADIBBLEND: return "ALPHADIBBLEND"; case EMR_TRANSPARENTBLT: return "TRANSPARENTBLT"; case EMR_TRANSPARENTDIB: return "TRANSPARENTDIB"; case EMR_GRADIENTFILL: return "GRADIENTFILL"; case EMR_SETLINKEDUFIS: return "SETLINKEDUFIS"; case EMR_SETTEXTJUSTIFICATION: return "SETTEXTJUSTIFICATION"; default: // Yes, return a pointer to a static buffer. This is a very // local debugging output function, so no big deal. static char buffer[11]; sprintf(buffer, "0x%08" SAL_PRIxUINT32, nRecType); return buffer; } #endif } #ifdef OSL_BIGENDIAN // little endian <-> big endian switch static float GetSwapFloat(SvStream& rStream) { float fTmp; sal_Int8* pPtr = (sal_Int8*)&fTmp; rStream.ReadSChar(pPtr[3]); rStream.ReadSChar(pPtr[2]); rStream.ReadSChar(pPtr[1]); rStream.ReadSChar(pPtr[0]); return fTmp; } #endif struct BLENDFUNCTION { unsigned char aBlendOperation; unsigned char aBlendFlags; unsigned char aSrcConstantAlpha; unsigned char aAlphaFormat; friend SvStream& operator>>(SvStream& rInStream, BLENDFUNCTION& rBlendFun); }; SvStream& operator>>(SvStream& rInStream, BLENDFUNCTION& rBlendFun) { rInStream.ReadUChar(rBlendFun.aBlendOperation); rInStream.ReadUChar(rBlendFun.aBlendFlags); rInStream.ReadUChar(rBlendFun.aSrcConstantAlpha); rInStream.ReadUChar(rBlendFun.aAlphaFormat); return rInStream; } SvStream& operator>>(SvStream& rInStream, XForm& rXForm) { if (sizeof(float) != 4) { OSL_FAIL( "EnhWMFReader::sizeof( float ) != 4" ); rXForm = XForm(); } else { #ifdef OSL_BIGENDIAN rXForm.eM11 = GetSwapFloat(rInStream); rXForm.eM12 = GetSwapFloat(rInStream); rXForm.eM21 = GetSwapFloat(rInStream); rXForm.eM22 = GetSwapFloat(rInStream); rXForm.eDx = GetSwapFloat(rInStream); rXForm.eDy = GetSwapFloat(rInStream); #else rInStream.ReadFloat(rXForm.eM11); rInStream.ReadFloat(rXForm.eM12); rInStream.ReadFloat(rXForm.eM21); rInStream.ReadFloat(rXForm.eM22); rInStream.ReadFloat(rXForm.eDx); rInStream.ReadFloat(rXForm.eDy); #endif } return rInStream; } static bool ImplReadRegion( tools::PolyPolygon& rPolyPoly, SvStream& rStream, sal_uInt32 nLen ) { if (nLen == 0) return false; sal_uInt32 nHdSize, nType, nCount, nRgnSize, i; rStream.ReadUInt32(nHdSize); rStream.ReadUInt32(nType); rStream.ReadUInt32(nCount); rStream.ReadUInt32(nRgnSize); if ( nCount > 0 && nType == RDH_RECTANGLES && nLen >= ((nCount << 4) + (nHdSize - 16))) { sal_Int32 nx1, ny1, nx2, ny2; for (i = 0; i < nCount; i++) { rStream.ReadInt32(nx1); rStream.ReadInt32(ny1); rStream.ReadInt32(nx2); rStream.ReadInt32(ny2); Rectangle aRectangle(Point(nx1, ny1), Point(nx2, ny2)); Polygon aPolygon(aRectangle); tools::PolyPolygon aPolyPolyOr1(aPolygon); tools::PolyPolygon aPolyPolyOr2(rPolyPoly); rPolyPoly.GetUnion(aPolyPolyOr1, aPolyPolyOr2); rPolyPoly = aPolyPolyOr2; } return true; } return false; } } // anonymous namespace EnhWMFReader::EnhWMFReader(SvStream& rStream,GDIMetaFile& rGDIMetaFile,FilterConfigItem* pConfigItem) : WinMtf(new WinMtfOutput(rGDIMetaFile), rStream , pConfigItem) , bRecordPath(false) , nRecordCount(0) , bEMFPlus(false) {} EnhWMFReader::~EnhWMFReader() {} void EnhWMFReader::ReadEMFPlusComment(sal_uInt32 length, bool& bHaveDC) { if (!bEMFPlus) { pOut->PassEMFPlusHeaderInfo(); #if OSL_DEBUG_LEVEL > 1 // debug code - write the stream to debug file /tmp/emf-stream.emf int pos = pWMF->Tell(); pWMF->Seek(0); SvFileStream file( OUString( "/tmp/emf-stream.emf" ), StreamMode::WRITE | StreamMode::TRUNC ); pWMF->WriteStream(file); file.Flush(); file.Close(); pWMF->Seek( pos ); #endif } 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 unavailable 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->ReadUInt16( type ).ReadUInt16( flags ).ReadUInt32( size ).ReadUInt32( dataSize ); nRemainder -= nRequiredHeaderSize; SAL_INFO ("vcl.emf", "\t\tEMF+ record type: " << std::hex << type << std::dec); // GetDC if( type == 16388 ) { bHaveDC = true; SAL_INFO ("vcl.emf", "\t\tEMF+ lock DC (device context)"); } // 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 \ parameter is for the type of the points (sal_uInt32 or sal_uInt16). * The \ 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 void EnhWMFReader::ReadAndDrawPolygon(Drawer drawer, const bool skipFirst) { sal_uInt32 nPoints(0), nStartIndex(0); pWMF->SeekRel( 16 ); pWMF->ReadUInt32( nPoints ); if (skipFirst) { nPoints ++; nStartIndex ++; } Polygon aPolygon = ReadPolygon(nStartIndex, nPoints); drawer(pOut, aPolygon, skipFirst, bRecordPath); } /** * Reads polygons from the stream. * The \ 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 Polygon EnhWMFReader::ReadPolygon(sal_uInt32 nStartIndex, sal_uInt32 nPoints) { bool bRecordOk = nPoints <= SAL_MAX_UINT16; SAL_WARN_IF(!bRecordOk, "vcl.filter", "polygon record has more polygons than we can handle"); if (!bRecordOk) return Polygon(); 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 \ parameter refers to the type of the points. (e.g. sal_uInt16 or sal_uInt32) * */ template void EnhWMFReader::ReadAndDrawPolyLine() { sal_uInt32 nPoints; sal_Int32 i, nPoly(0), nGesPoints(0); pWMF->SeekRel( 0x10 ); // Number of Polygons: pWMF->ReadInt32( nPoly ).ReadInt32( 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() ) ) { std::unique_ptr pnPoints(new sal_uInt16[ nPoly ]); for ( i = 0; i < nPoly && pWMF->good(); i++ ) { pWMF->ReadUInt32( nPoints ); pnPoints[ i ] = (sal_uInt16)nPoints; } // Get polygon points: for ( i = 0; ( i < nPoly ) && pWMF->good(); i++ ) { Polygon aPolygon = ReadPolygon(0, pnPoints[i]); pOut->DrawPolyLine( aPolygon, false, bRecordPath ); } } } // these are referenced from inside the templates SvStream& operator>>(SvStream& rStream, sal_Int16 &n) { return rStream.ReadInt16(n); } SvStream& operator>>(SvStream& rStream, sal_Int32 &n) { return rStream.ReadInt32(n); } /** * Reads a poly polygon from the WMF file and draws it. * The \ parameter refers to the type of the points. (e.g. sal_uInt16 or sal_uInt32) * */ template void EnhWMFReader::ReadAndDrawPolyPolygon() { sal_uInt32 nPoly(0), nGesPoints(0), nReadPoints(0); pWMF->SeekRel( 0x10 ); // Number of polygons pWMF->ReadUInt32( nPoly ).ReadUInt32( 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 std::unique_ptr pnPoints(new sal_uInt16[ nPoly ]); for (sal_uInt32 i = 0; i < nPoly && pWMF->good(); ++i) { sal_uInt32 nPoints(0); pWMF->ReadUInt32( nPoints ); pnPoints[ i ] = (sal_uInt16)nPoints; } if ( pWMF->good() && ( nGesPoints * (sizeof(T)+sizeof(T)) ) <= ( nEndPos - pWMF->Tell() ) ) { // Get polygon points tools::PolyPolygon aPolyPoly(nPoly, nPoly); for (sal_uInt32 i = 0; i < nPoly && pWMF->good(); ++i) { const sal_uInt16 nPointCount(pnPoints[i]); std::unique_ptr pPtAry(new Point[nPointCount]); for (sal_uInt16 j = 0; j < nPointCount && pWMF->good(); ++j) { T nX(0), nY(0); *pWMF >> nX >> nY; pPtAry[ j ] = Point( nX, nY ); ++nReadPoints; } aPolyPoly.Insert(Polygon(nPointCount, pPtAry.get())); } pOut->DrawPolyPolygon( aPolyPoly, bRecordPath ); } OSL_ENSURE(nReadPoints == nGesPoints, "The number Points processed from EMR_POLYPOLYGON is unequal imported number (!)"); } } 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); bool bStatus = ReadHeader(); bool bHaveDC = false; static bool bEnableEMFPlus = ( getenv( "EMF_PLUS_DISABLE" ) == NULL ); while( bStatus && nRecordCount-- && pWMF->good()) { pWMF->ReadUInt32( nRecType ).ReadUInt32( nRecSize ); if ( !pWMF->good() || ( nRecSize < 8 ) || ( nRecSize & 3 ) ) // Parameters are always divisible by 4 { bStatus = false; break; } nNextPos = pWMF->Tell() + ( nRecSize - 8 ); if ( !pWMF->good() || nNextPos > nEndPos ) { bStatus = false; break; } if( !aBmpSaveList.empty() && ( nRecType != EMR_STRETCHBLT ) && ( nRecType != EMR_STRETCHDIBITS ) ) { pOut->ResolveBitmapActions( aBmpSaveList ); } bool bFlag = false; SAL_INFO ("vcl.emf", "0x" << std::hex << (nNextPos - nRecSize) << "-0x" << nNextPos << " " << record_type_name(nRecType) << " size: " << nRecSize << std::dec); if( bEnableEMFPlus && nRecType == EMR_GDICOMMENT ) { sal_uInt32 length; pWMF->ReadUInt32( length ); SAL_INFO("vcl.emf", "\tGDI comment, length: " << length); if( pWMF->good() && length >= 4 ) { sal_uInt32 id; pWMF->ReadUInt32( id ); SAL_INFO ("vcl.emf", "\t\tbegin " << (char)(id & 0xff) << (char)((id & 0xff00) >> 8) << (char)((id & 0xff0000) >> 16) << (char)((id & 0xff000000) >> 24) << " id: 0x" << std::hex << id << std::dec); // 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 { SAL_INFO ("vcl.emf", "\t\tunknown id: 0x" << std::hex << id << std::dec); } } } else if( !bEMFPlus || bHaveDC || nRecType == EMR_EOF ) { switch( nRecType ) { case EMR_POLYBEZIERTO : ReadAndDrawPolygon(boost::bind(&WinMtfOutput::DrawPolyBezier, _1, _2, _3, _4), true); break; case EMR_POLYBEZIER : ReadAndDrawPolygon(boost::bind(&WinMtfOutput::DrawPolyBezier, _1, _2, _3, _4), false); break; case EMR_POLYGON : ReadAndDrawPolygon(boost::bind(&WinMtfOutput::DrawPolygon, _1, _2, _3, _4), false); break; case EMR_POLYLINETO : ReadAndDrawPolygon(boost::bind(&WinMtfOutput::DrawPolyLine, _1, _2, _3, _4), true); break; case EMR_POLYLINE : ReadAndDrawPolygon(boost::bind(&WinMtfOutput::DrawPolyLine, _1, _2, _3, _4), false); break; case EMR_POLYPOLYLINE : ReadAndDrawPolyLine(); break; case EMR_POLYPOLYGON : ReadAndDrawPolyPolygon(); break; case EMR_SETWINDOWEXTEX : { // #75383# pWMF->ReadUInt32( nW ).ReadUInt32( nH ); pOut->SetWinExt( Size( nW, nH ), true); } break; case EMR_SETWINDOWORGEX : { pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ); pOut->SetWinOrg( Point( nX32, nY32 ), true); } break; case EMR_SCALEWINDOWEXTEX : { pWMF->ReadUInt32( nNom1 ).ReadUInt32( nDen1 ).ReadUInt32( nNom2 ).ReadUInt32( nDen2 ); pOut->ScaleWinExt( (double)nNom1 / nDen1, (double)nNom2 / nDen2 ); } break; case EMR_SETVIEWPORTORGEX : { pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ); pOut->SetDevOrg( Point( nX32, nY32 ) ); } break; case EMR_SCALEVIEWPORTEXTEX : { pWMF->ReadUInt32( nNom1 ).ReadUInt32( nDen1 ).ReadUInt32( nNom2 ).ReadUInt32( nDen2 ); pOut->ScaleDevExt( (double)nNom1 / nDen1, (double)nNom2 / nDen2 ); } break; case EMR_SETVIEWPORTEXTEX : { pWMF->ReadUInt32( nW ).ReadUInt32( nH ); pOut->SetDevExt( Size( nW, nH ) ); } break; case EMR_EOF : nRecordCount = 0; // #76846# break; case EMR_SETPIXELV : { pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ); pOut->DrawPixel( Point( nX32, nY32 ), ReadColor() ); } break; case EMR_SETMAPMODE : { sal_uInt32 nMapMode; pWMF->ReadUInt32( nMapMode ); pOut->SetMapMode( nMapMode ); } break; case EMR_SETBKMODE : { pWMF->ReadUInt32( nDat32 ); pOut->SetBkMode( static_cast(nDat32) ); } break; case EMR_SETPOLYFILLMODE : break; case EMR_SETROP2 : { pWMF->ReadUInt32( nDat32 ); pOut->SetRasterOp( nDat32 ); } break; case EMR_SETSTRETCHBLTMODE : { pWMF->ReadUInt32( nStretchBltMode ); } break; case EMR_SETTEXTALIGN : { pWMF->ReadUInt32( nDat32 ); pOut->SetTextAlign( nDat32 ); } break; case EMR_SETTEXTCOLOR : { pOut->SetTextColor( ReadColor() ); } break; case EMR_SETBKCOLOR : { pOut->SetBkColor( ReadColor() ); } break; case EMR_OFFSETCLIPRGN : { pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ); pOut->MoveClipRegion( Size( nX32, nY32 ) ); } break; case EMR_MOVETOEX : { pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ); pOut->MoveTo( Point( nX32, nY32 ), bRecordPath ); } break; case EMR_INTERSECTCLIPRECT : { pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( 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; pWMF->ReadUInt32( nMode ); pOut->ModifyWorldTransform( aTempXForm, nMode ); } break; case EMR_SELECTOBJECT : { pWMF->ReadUInt32( nIndex ); pOut->SelectObject( nIndex ); } break; case EMR_CREATEPEN : { pWMF->ReadUInt32( 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->ReadUInt32( nStyle ).ReadInt32( nTmpW ).ReadInt32( nTmpH ); aSize.Width() = nTmpW; aSize.Height() = nTmpH; if ( aSize.Width() ) aLineInfo.SetWidth( aSize.Width() ); bool bTransparent = false; switch( nStyle & 0xFF ) { case PS_DASHDOTDOT : aLineInfo.SetStyle( LINE_DASH ); aLineInfo.SetDashCount( 1 ); aLineInfo.SetDotCount( 2 ); aLineInfo.SetDashLen( 150 ); aLineInfo.SetDotLen( 30 ); aLineInfo.SetDistance( 50 ); break; case PS_DASHDOT : aLineInfo.SetStyle( LINE_DASH ); aLineInfo.SetDashCount( 1 ); aLineInfo.SetDotCount( 1 ); aLineInfo.SetDashLen( 150 ); aLineInfo.SetDotLen( 30 ); aLineInfo.SetDistance( 90 ); break; case PS_DOT : aLineInfo.SetStyle( LINE_DASH ); aLineInfo.SetDashCount( 0 ); aLineInfo.SetDotCount( 1 ); aLineInfo.SetDotLen( 30 ); aLineInfo.SetDistance( 50 ); break; case PS_DASH : aLineInfo.SetStyle( LINE_DASH ); aLineInfo.SetDashCount( 1 ); aLineInfo.SetDotCount( 0 ); aLineInfo.SetDashLen( 225 ); aLineInfo.SetDistance( 100 ); break; case PS_NULL : bTransparent = true; aLineInfo.SetStyle( LINE_NONE ); break; case PS_INSIDEFRAME : case PS_SOLID : default : aLineInfo.SetStyle( LINE_SOLID ); } switch( nStyle & 0xF00 ) { case PS_ENDCAP_ROUND : if ( aSize.Width() ) { aLineInfo.SetLineCap( com::sun::star::drawing::LineCap_ROUND ); break; } case PS_ENDCAP_SQUARE : if ( aSize.Width() ) { aLineInfo.SetLineCap( com::sun::star::drawing::LineCap_SQUARE ); break; } case PS_ENDCAP_FLAT : default : aLineInfo.SetLineCap( com::sun::star::drawing::LineCap_BUTT ); } switch( nStyle & 0xF000 ) { case PS_JOIN_ROUND : aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::Round ); break; case PS_JOIN_MITER : aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::Miter ); break; case PS_JOIN_BEVEL : aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::Bevel ); break; default : aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::NONE ); } 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->ReadUInt32( nIndex ); if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) { pWMF->ReadUInt32( offBmi ).ReadUInt32( cbBmi ).ReadUInt32( offBits ).ReadUInt32( cbBits ). ReadUInt32( nStyle ).ReadUInt32( nWidth ).ReadUInt32( nBrushStyle ); aColorRef = ReadColor(); pWMF->ReadInt32( elpHatch ).ReadUInt32( elpNumEntries ); LineInfo aLineInfo; if ( nWidth ) aLineInfo.SetWidth( nWidth ); bool bTransparent = 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 = true; aLineInfo.SetStyle( LINE_NONE ); break; case PS_INSIDEFRAME : case PS_SOLID : default : 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->ReadUInt32( nIndex ); if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) { pWMF->ReadUInt32( nStyle ); pOut->CreateObject( nIndex, GDI_BRUSH, new WinMtfFillStyle( ReadColor(), ( nStyle == BS_HOLLOW ) ) ); } } break; case EMR_DELETEOBJECT : { pWMF->ReadUInt32( nIndex ); if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) pOut->DeleteObject( nIndex ); } break; case EMR_ELLIPSE : { pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ); pOut->DrawEllipse( ReadRectangle( nX32, nY32, nx32, ny32 ) ); } break; case EMR_RECTANGLE : { pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ); pOut->DrawRect( ReadRectangle( nX32, nY32, nx32, ny32 ) ); } break; case EMR_ROUNDRECT : { pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ).ReadUInt32( nW ).ReadUInt32( 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->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ).ReadUInt32( nStartX ).ReadUInt32( nStartY ).ReadUInt32( nEndX ).ReadUInt32( 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->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ).ReadUInt32( nStartX ).ReadUInt32( nStartY ).ReadUInt32( nEndX ).ReadUInt32( 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->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ).ReadUInt32( nStartX ).ReadUInt32( nStartY ).ReadUInt32( nEndX ).ReadUInt32( 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->ReadInt32( nX32 ).ReadInt32( nY32 ); pOut->LineTo( Point( nX32, nY32 ), bRecordPath ); } break; case EMR_ARCTO : { sal_uInt32 nStartX, nStartY, nEndX, nEndY; pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ).ReadUInt32( nStartX ).ReadUInt32( nStartY ).ReadUInt32( nEndX ).ReadUInt32( nEndY ); pOut->DrawArc( ReadRectangle( nX32, nY32, nx32, ny32 ), Point( nStartX, nStartY ), Point( nEndX, nEndY ), true ); } break; case EMR_BEGINPATH : { pOut->ClearPath(); bRecordPath = true; } break; case EMR_ABORTPATH : pOut->ClearPath(); case EMR_ENDPATH : bRecordPath = false; break; case EMR_CLOSEFIGURE : pOut->ClosePath(); break; case EMR_FILLPATH : pOut->StrokeAndFillPath( false, true ); break; case EMR_STROKEANDFILLPATH : pOut->StrokeAndFillPath( true, true ); break; case EMR_STROKEPATH : pOut->StrokeAndFillPath( true, false ); break; case EMR_SELECTCLIPPATH : { sal_Int32 nClippingMode; pWMF->ReadInt32(nClippingMode); pOut->SetClipPath(pOut->GetPathObj(), nClippingMode, true); } break; case EMR_EXTSELECTCLIPRGN : { sal_Int32 nClippingMode, cbRgnData; pWMF->ReadInt32(cbRgnData); pWMF->ReadInt32(nClippingMode); // This record's region data should be ignored if mode // is RGN_COPY - see EMF spec section 2.3.2.2 if (nClippingMode == RGN_COPY) { pOut->SetDefaultClipPath(); } else { tools::PolyPolygon aPolyPoly; if (cbRgnData) ImplReadRegion(aPolyPoly, *pWMF, nRecSize); pOut->SetClipPath(aPolyPoly, nClippingMode, false); } } break; case EMR_ALPHABLEND: { sal_Int32 xDest(0), yDest(0), cxDest(0), cyDest(0); BLENDFUNCTION aFunc; sal_Int32 xSrc(0), ySrc(0), cxSrc(0), cySrc(0); XForm xformSrc; sal_uInt32 BkColorSrc(0), iUsageSrc(0), offBmiSrc(0); sal_uInt32 cbBmiSrc(0), offBitsSrc(0), cbBitsSrc(0); sal_uInt32 nStart = pWMF->Tell() - 8; pWMF->SeekRel( 0x10 ); pWMF->ReadInt32( xDest ).ReadInt32( yDest ).ReadInt32( cxDest ).ReadInt32( cyDest ); *pWMF >> aFunc; pWMF->ReadInt32( xSrc ).ReadInt32( ySrc ); *pWMF >> xformSrc; pWMF->ReadUInt32( BkColorSrc ).ReadUInt32( iUsageSrc ).ReadUInt32( offBmiSrc ).ReadUInt32( cbBmiSrc ) .ReadUInt32( offBitsSrc ).ReadUInt32( cbBitsSrc ).ReadInt32( cxSrc ).ReadInt32( cySrc ) ; sal_uInt32 dwRop = SRCAND|SRCINVERT; Bitmap aBitmap; Rectangle aRect( Point( xDest, yDest ), Size( cxDest+1, cyDest+1 ) ); if ( (cbBitsSrc > (SAL_MAX_UINT32 - 14)) || ((SAL_MAX_UINT32 - 14) - cbBitsSrc < cbBmiSrc) ) bStatus = false; else { sal_uInt32 nSize = cbBmiSrc + cbBitsSrc + 14; if ( nSize <= ( nEndPos - nStartPos ) ) { char* pBuf = new char[ nSize ]; SvMemoryStream aTmp( pBuf, nSize, StreamMode::READ | StreamMode::WRITE ); aTmp.ObjectOwnsMemory( true ); aTmp.WriteUChar( 'B' ) .WriteUChar( 'M' ) .WriteUInt32( cbBitsSrc ) .WriteUInt16( 0 ) .WriteUInt16( 0 ) .WriteUInt32( cbBmiSrc + 14 ); pWMF->Seek( nStart + offBmiSrc ); pWMF->Read( pBuf + 14, cbBmiSrc ); pWMF->Seek( nStart + offBitsSrc ); pWMF->Read( pBuf + 14 + cbBmiSrc, cbBitsSrc ); aTmp.Seek( 0 ); ReadDIB(aBitmap, aTmp, true); // test if it is sensible to crop if ( ( cxSrc > 0 ) && ( cySrc > 0 ) && ( xSrc >= 0 ) && ( ySrc >= 0 ) && ( xSrc + cxSrc <= aBitmap.GetSizePixel().Width() ) && ( ySrc + cySrc <= aBitmap.GetSizePixel().Height() ) ) { Rectangle aCropRect( Point( xSrc, ySrc ), Size( cxSrc, cySrc ) ); aBitmap.Crop( aCropRect ); } aBmpSaveList.push_back( new BSaveStruct( aBitmap, aRect, dwRop, pOut->GetFillStyle () ) ); } } } 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->ReadInt32( xDest ).ReadInt32( yDest ).ReadInt32( cxDest ).ReadInt32( cyDest ).ReadUInt32( dwRop ).ReadInt32( xSrc ).ReadInt32( ySrc ) >> xformSrc; pWMF->ReadUInt32( nColor ).ReadUInt32( iUsageSrc ).ReadUInt32( offBmiSrc ).ReadUInt32( cbBmiSrc ) .ReadUInt32( offBitsSrc ).ReadUInt32( cbBitsSrc ); if ( nRecType == EMR_STRETCHBLT ) pWMF->ReadInt32( cxSrc ).ReadInt32( 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 = false; else { sal_uInt32 nSize = cbBmiSrc + cbBitsSrc + 14; if ( nSize <= ( nEndPos - nStartPos ) ) { char* pBuf = new char[ nSize ]; SvMemoryStream aTmp( pBuf, nSize, StreamMode::READ | StreamMode::WRITE ); aTmp.ObjectOwnsMemory( true ); aTmp.WriteUChar( 'B' ) .WriteUChar( 'M' ) .WriteUInt32( cbBitsSrc ) .WriteUInt16( 0 ) .WriteUInt16( 0 ) .WriteUInt32( cbBmiSrc + 14 ); pWMF->Seek( nStart + offBmiSrc ); pWMF->Read( pBuf + 14, cbBmiSrc ); pWMF->Seek( nStart + offBitsSrc ); pWMF->Read( pBuf + 14 + cbBmiSrc, cbBitsSrc ); aTmp.Seek( 0 ); ReadDIB(aBitmap, aTmp, true); // test if it is sensible to crop if ( ( cxSrc > 0 ) && ( cySrc > 0 ) && ( xSrc >= 0 ) && ( ySrc >= 0 ) && ( xSrc + cxSrc <= aBitmap.GetSizePixel().Width() ) && ( ySrc + cySrc <= aBitmap.GetSizePixel().Height() ) ) { Rectangle aCropRect( Point( xSrc, ySrc ), Size( cxSrc, cySrc ) ); aBitmap.Crop( aCropRect ); } aBmpSaveList.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->ReadInt32( xDest ) .ReadInt32( yDest ) .ReadInt32( xSrc ) .ReadInt32( ySrc ) .ReadInt32( cxSrc ) .ReadInt32( cySrc ) .ReadUInt32( offBmiSrc ) .ReadUInt32( cbBmiSrc ) .ReadUInt32( offBitsSrc ) .ReadUInt32( cbBitsSrc ) .ReadUInt32( iUsageSrc ) .ReadUInt32( dwRop ) .ReadInt32( cxDest ) .ReadInt32( 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 = false; } else { sal_uInt32 nSize = cbBmiSrc + cbBitsSrc + 14; if ( nSize <= ( nEndPos - nStartPos ) ) { char* pBuf = new char[ nSize ]; SvMemoryStream aTmp( pBuf, nSize, StreamMode::READ | StreamMode::WRITE ); aTmp.ObjectOwnsMemory( true ); aTmp.WriteUChar( 'B' ) .WriteUChar( 'M' ) .WriteUInt32( cbBitsSrc ) .WriteUInt16( 0 ) .WriteUInt16( 0 ) .WriteUInt32( cbBmiSrc + 14 ); pWMF->Seek( nStart + offBmiSrc ); pWMF->Read( pBuf + 14, cbBmiSrc ); pWMF->Seek( nStart + offBitsSrc ); pWMF->Read( pBuf + 14 + cbBmiSrc, cbBitsSrc ); aTmp.Seek( 0 ); ReadDIB(aBitmap, aTmp, true); // test if it is sensible to crop if ( ( cxSrc > 0 ) && ( cySrc > 0 ) && ( xSrc >= 0 ) && ( ySrc >= 0 ) && ( xSrc + cxSrc <= aBitmap.GetSizePixel().Width() ) && ( ySrc + cySrc <= aBitmap.GetSizePixel().Height() ) ) { Rectangle aCropRect( Point( xSrc, ySrc ), Size( cxSrc, cySrc ) ); aBitmap.Crop( aCropRect ); } aBmpSaveList.push_back( new BSaveStruct( aBitmap, aRect, dwRop, pOut->GetFillStyle () ) ); } } } break; case EMR_EXTCREATEFONTINDIRECTW : { pWMF->ReadUInt32( nIndex ); if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) { LOGFONTW aLogFont; pWMF->ReadInt32( aLogFont.lfHeight ) .ReadInt32( aLogFont.lfWidth ) .ReadInt32( aLogFont.lfEscapement ) .ReadInt32( aLogFont.lfOrientation ) .ReadInt32( aLogFont.lfWeight ) .ReadUChar( aLogFont.lfItalic ) .ReadUChar( aLogFont.lfUnderline ) .ReadUChar( aLogFont.lfStrikeOut ) .ReadUChar( aLogFont.lfCharSet ) .ReadUChar( aLogFont.lfOutPrecision ) .ReadUChar( aLogFont.lfClipPrecision ) .ReadUChar( aLogFont.lfQuality ) .ReadUChar( aLogFont.lfPitchAndFamily ); sal_Unicode lfFaceName[LF_FACESIZE+1]; lfFaceName[LF_FACESIZE] = 0; for (int i = 0; i < LF_FACESIZE; ++i) { sal_uInt16 nChar(0); pWMF->ReadUInt16(nChar); lfFaceName[i] = nChar; } aLogFont.alfFaceName = OUString( lfFaceName ); // #i123216# Not used in the test case of #121382# (always identity in XForm), also // no hints in ms docu if FontSize should be scaled with WT. Using with the example // from #i123216# creates errors, so removing. // // #i121382# Need to apply WorldTransform to FontHeight/Width; this should be completely // // changed to basegfx::B2DHomMatrix instead of 'struct XForm', but not now due to time // // constraints and dangers // const XForm& rXF = pOut->GetWorldTransform(); // const basegfx::B2DHomMatrix aWT(rXF.eM11, rXF.eM21, rXF.eDx, rXF.eM12, rXF.eM22, rXF.eDy); // const basegfx::B2DVector aTransVec(aWT * basegfx::B2DVector(aLogFont.lfWidth, aLogFont.lfHeight)); // aLogFont.lfWidth = aTransVec.getX(); // aLogFont.lfHeight = aTransVec.getY(); pOut->CreateObject( nIndex, GDI_FONT, new WinMtfFontStyle( aLogFont ) ); } } break; case EMR_EXTTEXTOUTA : bFlag = true; case EMR_EXTTEXTOUTW : { sal_Int32 nLeft, nTop, nRight, nBottom, ptlReferenceX, ptlReferenceY, nGfxMode, nXScale, nYScale; sal_uInt32 nCurPos, nOffString, nOptions, offDx; sal_Int32 nLen; long* pDX = NULL; nCurPos = pWMF->Tell() - 8; pWMF->ReadInt32( nLeft ).ReadInt32( nTop ).ReadInt32( nRight ).ReadInt32( nBottom ).ReadInt32( nGfxMode ).ReadInt32( nXScale ).ReadInt32( nYScale ) .ReadInt32( ptlReferenceX ).ReadInt32( ptlReferenceY ).ReadInt32( nLen ).ReadUInt32( nOffString ).ReadUInt32( nOptions ); pWMF->SeekRel( 0x10 ); pWMF->ReadUInt32( offDx ); ComplexTextLayoutMode 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 < static_cast( 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 long[ nLen ]; sal_Int32 i; sal_Int32 val; for ( i = 0; i < nLen; i++ ) { pWMF->ReadInt32( val ); pDX[ i ] = val; } } } pWMF->Seek( nCurPos + nOffString ); OUString aText; if ( bFlag ) { if ( nLen <= static_cast( nEndPos - pWMF->Tell() ) ) { std::unique_ptr pBuf(new sal_Char[ nLen ]); pWMF->Read( pBuf.get(), nLen ); aText = OUString( pBuf.get(), (sal_uInt16)nLen, pOut->GetCharSet() ); pBuf.reset(); if ( aText.getLength() != nLen ) { sal_uInt16 i, j; long* pOldDx = pDX; pDX = new long[ aText.getLength() ]; for ( i = 0, j = 0; i < aText.getLength(); i++ ) { sal_Unicode cUniChar = aText[i]; OString aCharacter(&cUniChar, 1, pOut->GetCharSet()); pDX[ i ] = 0; for (sal_Int32 k = 0; ( k < aCharacter.getLength() ) && ( j < nLen ) && ( i < aText.getLength() ); ++k) pDX[ i ] += pOldDx[ j++ ]; } delete[] pOldDx; } } } else { if ( ( nLen * sizeof(sal_Unicode) ) <= ( nEndPos - pWMF->Tell() ) ) { std::unique_ptr pBuf(new sal_Unicode[ nLen ]); pWMF->Read( pBuf.get(), nLen << 1 ); #ifdef OSL_BIGENDIAN sal_Char nTmp, *pTmp = (sal_Char*)( pBuf.get() + nLen ); while ( pTmp-- != (sal_Char*)pBuf.get() ) { nTmp = *pTmp--; pTmp[ 1 ] = *pTmp; *pTmp = nTmp; } #endif aText = OUString(pBuf.get(), nLen); } } pOut->DrawText( aPos, aText, pDX, bRecordPath, nGfxMode ); } delete[] pDX; } break; case EMR_POLYBEZIERTO16 : ReadAndDrawPolygon(boost::bind(&WinMtfOutput::DrawPolyBezier, _1, _2, _3, _4), true); break; case EMR_POLYBEZIER16 : ReadAndDrawPolygon(boost::bind(&WinMtfOutput::DrawPolyBezier, _1, _2, _3, _4), false); break; case EMR_POLYGON16 : ReadAndDrawPolygon(boost::bind(&WinMtfOutput::DrawPolygon, _1, _2, _3, _4), false); break; case EMR_POLYLINETO16 : ReadAndDrawPolygon(boost::bind(&WinMtfOutput::DrawPolyLine, _1, _2, _3, _4), true); break; case EMR_POLYLINE16 : ReadAndDrawPolygon(boost::bind(&WinMtfOutput::DrawPolyLine, _1, _2, _3, _4), false); break; case EMR_POLYPOLYLINE16 : ReadAndDrawPolyLine(); break; case EMR_POLYPOLYGON16 : ReadAndDrawPolyPolygon(); break; case EMR_FILLRGN : { sal_uInt32 nLen; tools::PolyPolygon aPolyPoly; pWMF->SeekRel( 0x10 ); pWMF->ReadUInt32( nLen ).ReadUInt32( nIndex ); if ( ImplReadRegion( aPolyPoly, *pWMF, nRecSize ) ) { pOut->Push(); pOut->SelectObject( nIndex ); pOut->DrawPolyPolygon( aPolyPoly, false ); pOut->Pop(); } } break; case EMR_CREATEDIBPATTERNBRUSHPT : { sal_uInt32 nStart = pWMF->Tell() - 8; Bitmap aBitmap; pWMF->ReadUInt32( nIndex ); if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) { sal_uInt32 usage, offBmi, cbBmi, offBits, cbBits; pWMF->ReadUInt32( usage ); pWMF->ReadUInt32( offBmi ); pWMF->ReadUInt32( cbBmi ); pWMF->ReadUInt32( offBits ); pWMF->ReadUInt32( cbBits ); if ( (cbBits > (SAL_MAX_UINT32 - 14)) || ((SAL_MAX_UINT32 - 14) - cbBits < cbBmi) ) bStatus = false; else if ( offBmi ) { sal_uInt32 nSize = cbBmi + cbBits + 14; if ( nSize <= ( nEndPos - nStartPos ) ) { char* pBuf = new char[ nSize ]; SvMemoryStream aTmp( pBuf, nSize, StreamMode::READ | StreamMode::WRITE ); aTmp.ObjectOwnsMemory( true ); aTmp.WriteUChar( 'B' ) .WriteUChar( 'M' ) .WriteUInt32( cbBits ) .WriteUInt16( 0 ) .WriteUInt16( 0 ) .WriteUInt32( cbBmi + 14 ); pWMF->Seek( nStart + offBmi ); pWMF->Read( pBuf + 14, cbBmi ); pWMF->Seek( nStart + offBits ); pWMF->Read( pBuf + 14 + cbBmi, cbBits ); aTmp.Seek( 0 ); ReadDIB(aBitmap, aTmp, true); } } } pOut->CreateObject( nIndex, GDI_BRUSH, new WinMtfFillStyle( aBitmap ) ); } break; case EMR_MASKBLT : SAL_INFO("vcl.emf", "not implemented 'MaskBlt'"); break; case EMR_PLGBLT : SAL_INFO("vcl.emf", "not implemented 'PlgBlt'"); break; case EMR_SETDIBITSTODEVICE : SAL_INFO("vcl.emf", "not implemented 'SetDIBitsToDevice'"); break; case EMR_FRAMERGN : SAL_INFO("vcl.emf", "not implemented 'FrameRgn'"); break; case EMR_INVERTRGN : SAL_INFO("vcl.emf", "not implemented 'InvertRgn'"); break; case EMR_PAINTRGN : SAL_INFO("vcl.emf", "not implemented 'PaintRgn'"); break; case EMR_FLATTENPATH : SAL_INFO("vcl.emf", "not implemented 'FlattenPath'"); break; case EMR_WIDENPATH : SAL_INFO("vcl.emf", "not implemented 'WidenPath'"); break; case EMR_POLYDRAW : SAL_INFO("vcl.emf", "not implemented 'Polydraw'"); break; case EMR_SETARCDIRECTION : SAL_INFO("vcl.emf", "not implemented 'SetArcDirection'"); break; case EMR_SETPALETTEENTRIES : SAL_INFO("vcl.emf", "not implemented 'SetPaletteEntries'"); break; case EMR_RESIZEPALETTE : SAL_INFO("vcl.emf", "not implemented 'ResizePalette'"); break; case EMR_EXTFLOODFILL : SAL_INFO("vcl.emf", "not implemented 'ExtFloodFill'"); break; case EMR_ANGLEARC : SAL_INFO("vcl.emf", "not implemented 'AngleArc'"); break; case EMR_SETCOLORADJUSTMENT : SAL_INFO("vcl.emf", "not implemented 'SetColorAdjustment'"); break; case EMR_POLYDRAW16 : SAL_INFO("vcl.emf", "not implemented 'PolyDraw16'"); break; case EMR_POLYTEXTOUTA : SAL_INFO("vcl.emf", "not implemented 'PolyTextOutA'"); break; case EMR_POLYTEXTOUTW : SAL_INFO("vcl.emf", "not implemented 'PolyTextOutW'"); break; case EMR_CREATECOLORSPACE : SAL_INFO("vcl.emf", "not implemented 'CreateColorSpace'"); break; case EMR_SETCOLORSPACE : SAL_INFO("vcl.emf", "not implemented 'SetColorSpace'"); break; case EMR_DELETECOLORSPACE : SAL_INFO("vcl.emf", "not implemented 'DeleteColorSpace'"); break; case EMR_GLSRECORD : SAL_INFO("vcl.emf", "not implemented 'GlsRecord'"); break; case EMR_GLSBOUNDEDRECORD : SAL_INFO("vcl.emf", "not implemented 'GlsBoundRecord'"); break; case EMR_PIXELFORMAT : SAL_INFO("vcl.emf", "not implemented 'PixelFormat'"); break; case EMR_DRAWESCAPE : SAL_INFO("vcl.emf", "not implemented 'DrawEscape'"); break; case EMR_EXTESCAPE : SAL_INFO("vcl.emf", "not implemented 'ExtEscape'"); break; case EMR_STARTDOC : SAL_INFO("vcl.emf", "not implemented 'StartDoc'"); break; case EMR_SMALLTEXTOUT : SAL_INFO("vcl.emf", "not implemented 'SmallTextOut'"); break; case EMR_FORCEUFIMAPPING : SAL_INFO("vcl.emf", "not implemented 'ForceUFIMapping'"); break; case EMR_NAMEDESCAPE : SAL_INFO("vcl.emf", "not implemented 'NamedEscape'"); break; case EMR_COLORCORRECTPALETTE : SAL_INFO("vcl.emf", "not implemented 'ColorCorrectPalette'"); break; case EMR_SETICMPROFILEA : SAL_INFO("vcl.emf", "not implemented 'SetICMProfileA'"); break; case EMR_SETICMPROFILEW : SAL_INFO("vcl.emf", "not implemented 'SetICMProfileW'"); break; case EMR_TRANSPARENTBLT : SAL_INFO("vcl.emf", "not implemented 'TransparenBlt'"); break; case EMR_TRANSPARENTDIB : SAL_INFO("vcl.emf", "not implemented 'TransparenDib'"); break; case EMR_GRADIENTFILL : SAL_INFO("vcl.emf", "not implemented 'GradientFill'"); break; case EMR_SETLINKEDUFIS : SAL_INFO("vcl.emf", "not implemented 'SetLinkedUFIS'"); break; case EMR_SETMAPPERFLAGS : SAL_INFO("vcl.emf", "not implemented 'SetMapperFlags'"); break; case EMR_SETICMMODE : SAL_INFO("vcl.emf", "not implemented 'SetICMMode'"); break; case EMR_CREATEMONOBRUSH : SAL_INFO("vcl.emf", "not implemented 'CreateMonoBrush'"); break; case EMR_SETBRUSHORGEX : SAL_INFO("vcl.emf", "not implemented 'SetBrushOrgEx'"); break; case EMR_SETMETARGN : SAL_INFO("vcl.emf", "not implemented 'SetMetArgn'"); break; case EMR_SETMITERLIMIT : SAL_INFO("vcl.emf", "not implemented 'SetMiterLimit'"); break; case EMR_EXCLUDECLIPRECT : SAL_INFO("vcl.emf", "not implemented 'ExcludeClipRect'"); break; case EMR_REALIZEPALETTE : SAL_INFO("vcl.emf", "not implemented 'RealizePalette'"); break; case EMR_SELECTPALETTE : SAL_INFO("vcl.emf", "not implemented 'SelectPalette'"); break; case EMR_CREATEPALETTE : SAL_INFO("vcl.emf", "not implemented 'CreatePalette'"); break; case EMR_ALPHADIBBLEND : SAL_INFO("vcl.emf", "not implemented 'AlphaDibBlend'"); break; case EMR_SETTEXTJUSTIFICATION : SAL_INFO("vcl.emf", "not implemented 'SetTextJustification'"); break; case EMR_GDICOMMENT : case EMR_HEADER : // has already been read at ReadHeader() break; default : SAL_INFO("vcl.emf", "Unknown Meta Action"); break; } } pWMF->Seek( nNextPos ); } if( !aBmpSaveList.empty() ) pOut->ResolveBitmapActions( aBmpSaveList ); if ( bStatus ) pWMF->Seek(nEndPos); return bStatus; }; bool EnhWMFReader::ReadHeader() { sal_uInt32 nType, nSignature, nVersion; sal_uInt32 nHeaderSize, nPalEntries; // Spare me the METAFILEHEADER here // Reading the METAHEADER - EMR_HEADER ([MS-EMF] section 2.3.4.2 EMR_HEADER Record Types) pWMF->ReadUInt32( nType ).ReadUInt32( nHeaderSize ); if (nType != 0x00000001) { // per [MS-EMF] 2.3.4.2 EMF Header Record Types, type MUST be 0x00000001 SAL_WARN("vcl.emf", "EMF header type is not set to 0x00000001 - possibly corrupted file?"); return false; } // Start reading the EMR_HEADER Header object // bound size (RectL object, see [MS-WMF] section 2.2.2.19) Rectangle rclBounds = ReadRectangle(); // rectangle in logical units // picture frame size (RectL object) Rectangle rclFrame = ReadRectangle(); // rectangle in device units 1/100th mm pWMF->ReadUInt32( nSignature ); // nSignature MUST be the ASCII characters "FME", see [WS-EMF] 2.2.9 Header Object // and 2.1.14 FormatSignature Enumeration if (nSignature != 0x464d4520) { SAL_WARN("vcl.emf", "EMF\t\tSignature is not 0x464d4520 (\"FME\") - possibly corrupted file?"); return false; } pWMF->ReadUInt32(nVersion); // according to [WS-EMF] 2.2.9, this SHOULD be 0x0001000, however // Microsoft note that not even Windows checks this... if (nVersion != 0x00010000) { SAL_WARN("vcl.emf", "EMF\t\tThis really should be 0x00010000, though not absolutely essential..."); } pWMF->ReadUInt32(nEndPos); // size of metafile nEndPos += nStartPos; sal_uInt32 nStrmPos = pWMF->Tell(); // checking if nEndPos is valid pWMF->Seek(STREAM_SEEK_TO_END); sal_uInt32 nActualFileSize = pWMF->Tell(); if ( nActualFileSize < nEndPos ) { SAL_WARN("vcl.emf", "EMF\t\tEMF Header object records number of bytes as " << nEndPos << ", however the file size is actually " << nActualFileSize << " bytes. Possible file corruption?"); nEndPos = nActualFileSize; } pWMF->Seek(nStrmPos); pWMF->ReadInt32(nRecordCount); if (nRecordCount == 0) { SAL_WARN("vcl.emf", "EMF\t\tEMF Header object shows record counter as 0! This shouldn't " "be possible... indicator of possible file corruption?"); return false; } // the number of "handles", or graphics objects used in the metafile sal_uInt16 nHandlesCount; pWMF->ReadUInt16(nHandlesCount); // the next 2 bytes are reserved, but according to [MS-EMF] section 2.2.9 // it MUST be 0x000 and MUST be ignored... the thing is, having such a specific // value is actually pretty useful in checking if there is possible corruption sal_uInt16 nReserved; pWMF->ReadUInt16(nReserved); if ( nReserved != 0x0000 ) { SAL_WARN("vcl.emf", "EMF\t\tEMF Header object's reserved field is NOT 0x0000... possible " "corruption?"); } // The next 4 bytes specifies the number of characters in the metafile description. // The 4 bytes after that specific the offset from this record that contains the // metafile description... zero means no description string. // For now, we ignore it. pWMF->SeekRel(0x8); sal_Int32 nPixX, nPixY, nMillX, nMillY; pWMF->ReadUInt32(nPalEntries); pWMF->ReadInt32(nPixX); pWMF->ReadInt32(nPixY); pWMF->ReadInt32(nMillX); pWMF->ReadInt32(nMillY); pOut->SetrclFrame(rclFrame); pOut->SetrclBounds(rclBounds); pOut->SetRefPix(Size( nPixX, nPixY ) ); pOut->SetRefMill(Size( nMillX, nMillY ) ); pWMF->Seek(nStartPos + nHeaderSize); return true; } Rectangle EnhWMFReader::ReadRectangle() { sal_Int32 nLeft, nTop, nRight, nBottom; pWMF->ReadInt32(nLeft); pWMF->ReadInt32(nTop); pWMF->ReadInt32(nRight); pWMF->ReadInt32(nBottom); return Rectangle(nLeft, nTop, nRight, nBottom); } 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 ); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */