/************************************************************** * * 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 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_svtools.hxx" #include "winmtf.hxx" #include #include #include #include #include #include //====================== MS-Windows-defines =============================== #define W_META_SETBKCOLOR 0x0201 #define W_META_SETBKMODE 0x0102 #define W_META_SETMAPMODE 0x0103 #define W_META_SETROP2 0x0104 #define W_META_SETRELABS 0x0105 #define W_META_SETPOLYFILLMODE 0x0106 #define W_META_SETSTRETCHBLTMODE 0x0107 #define W_META_SETTEXTCHAREXTRA 0x0108 #define W_META_SETTEXTCOLOR 0x0209 #define W_META_SETTEXTJUSTIFICATION 0x020A #define W_META_SETWINDOWORG 0x020B #define W_META_SETWINDOWEXT 0x020C #define W_META_SETVIEWPORTORG 0x020D #define W_META_SETVIEWPORTEXT 0x020E #define W_META_OFFSETWINDOWORG 0x020F #define W_META_SCALEWINDOWEXT 0x0410 #define W_META_OFFSETVIEWPORTORG 0x0211 #define W_META_SCALEVIEWPORTEXT 0x0412 #define W_META_LINETO 0x0213 #define W_META_MOVETO 0x0214 #define W_META_EXCLUDECLIPRECT 0x0415 #define W_META_INTERSECTCLIPRECT 0x0416 #define W_META_ARC 0x0817 #define W_META_ELLIPSE 0x0418 #define W_META_FLOODFILL 0x0419 #define W_META_PIE 0x081A #define W_META_RECTANGLE 0x041B #define W_META_ROUNDRECT 0x061C #define W_META_PATBLT 0x061D #define W_META_SAVEDC 0x001E #define W_META_SETPIXEL 0x041F #define W_META_OFFSETCLIPRGN 0x0220 #define W_META_TEXTOUT 0x0521 #define W_META_BITBLT 0x0922 #define W_META_STRETCHBLT 0x0B23 #define W_META_POLYGON 0x0324 #define W_META_POLYLINE 0x0325 #define W_META_ESCAPE 0x0626 #define W_META_RESTOREDC 0x0127 #define W_META_FILLREGION 0x0228 #define W_META_FRAMEREGION 0x0429 #define W_META_INVERTREGION 0x012A #define W_META_PAINTREGION 0x012B #define W_META_SELECTCLIPREGION 0x012C #define W_META_SELECTOBJECT 0x012D #define W_META_SETTEXTALIGN 0x012E #define W_META_DRAWTEXT 0x062F #define W_META_CHORD 0x0830 #define W_META_SETMAPPERFLAGS 0x0231 #define W_META_EXTTEXTOUT 0x0a32 #define W_META_SETDIBTODEV 0x0d33 #define W_META_SELECTPALETTE 0x0234 #define W_META_REALIZEPALETTE 0x0035 #define W_META_ANIMATEPALETTE 0x0436 #define W_META_SETPALENTRIES 0x0037 #define W_META_POLYPOLYGON 0x0538 #define W_META_RESIZEPALETTE 0x0139 #define W_META_DIBBITBLT 0x0940 #define W_META_DIBSTRETCHBLT 0x0b41 #define W_META_DIBCREATEPATTERNBRUSH 0x0142 #define W_META_STRETCHDIB 0x0f43 #define W_META_EXTFLOODFILL 0x0548 #define W_META_RESETDC 0x014C #define W_META_STARTDOC 0x014D #define W_META_STARTPAGE 0x004F #define W_META_ENDPAGE 0x0050 #define W_META_ABORTDOC 0x0052 #define W_META_ENDDOC 0x005E #define W_META_DELETEOBJECT 0x01f0 #define W_META_CREATEPALETTE 0x00f7 #define W_META_CREATEBRUSH 0x00F8 #define W_META_CREATEPATTERNBRUSH 0x01F9 #define W_META_CREATEPENINDIRECT 0x02FA #define W_META_CREATEFONTINDIRECT 0x02FB #define W_META_CREATEBRUSHINDIRECT 0x02FC #define W_META_CREATEBITMAPINDIRECT 0x02FD #define W_META_CREATEBITMAP 0x06FE #define W_META_CREATEREGION 0x06FF //=================== Methoden von WMFReader ============================== inline Point WMFReader::ReadPoint() { short nX, nY; *pWMF >> nX >> nY; return Point( nX, nY ); } // ------------------------------------------------------------------------ inline Point WMFReader::ReadYX() { short nX, nY; *pWMF >> nY >> nX; return Point( nX, nY ); } // ------------------------------------------------------------------------ Rectangle WMFReader::ReadRectangle() { Point aBR, aTL; aBR = ReadYX(); aTL = ReadYX(); aBR.X()--; aBR.Y()--; return Rectangle( aTL, aBR ); } // ------------------------------------------------------------------------ Size WMFReader::ReadYXExt() { short nW, nH; *pWMF >> nH >> nW; return Size( nW, nH ); } // ------------------------------------------------------------------------ void WMFReader::ReadRecordParams( sal_uInt16 nFunc ) { switch( nFunc ) { case W_META_SETBKCOLOR: { pOut->SetBkColor( ReadColor() ); } break; case W_META_SETBKMODE: { sal_uInt16 nDat; *pWMF >> nDat; pOut->SetBkMode( nDat ); } break; // !!! case W_META_SETMAPMODE: { sal_Int16 nMapMode; *pWMF >> nMapMode; pOut->SetMapMode( nMapMode ); } break; case W_META_SETROP2: { sal_uInt16 nROP2; *pWMF >> nROP2; pOut->SetRasterOp( nROP2 ); } break; case W_META_SETTEXTCOLOR: { pOut->SetTextColor( ReadColor() ); } break; case W_META_SETWINDOWORG: { pOut->SetWinOrg( ReadYX() ); } break; case W_META_SETWINDOWEXT: { short nWidth, nHeight; *pWMF >> nHeight >> nWidth; pOut->SetWinExt( Size( nWidth, nHeight ) ); } break; case W_META_OFFSETWINDOWORG: { short nXAdd, nYAdd; *pWMF >> nYAdd >> nXAdd; pOut->SetWinOrgOffset( nXAdd, nYAdd ); } break; case W_META_SCALEWINDOWEXT: { short nXNum, nXDenom, nYNum, nYDenom; *pWMF >> nYDenom >> nYNum >> nXDenom >> nXNum; pOut->ScaleWinExt( (double)nXNum / nXDenom, (double)nYNum / nYDenom ); } break; case W_META_SETVIEWPORTORG: case W_META_SETVIEWPORTEXT: break; case W_META_OFFSETVIEWPORTORG: { short nXAdd, nYAdd; *pWMF >> nYAdd >> nXAdd; pOut->SetDevOrgOffset( nXAdd, nYAdd ); } break; case W_META_SCALEVIEWPORTEXT: { short nXNum, nXDenom, nYNum, nYDenom; *pWMF >> nYDenom >> nYNum >> nXDenom >> nXNum; pOut->ScaleDevExt( (double)nXNum / nXDenom, (double)nYNum / nYDenom ); } break; case W_META_LINETO: { pOut->LineTo( ReadYX() ); } break; case W_META_MOVETO: { pOut->MoveTo( ReadYX() ); } break; case W_META_INTERSECTCLIPRECT: { pOut->IntersectClipRect( ReadRectangle() ); } break; case W_META_RECTANGLE: { pOut->DrawRect( ReadRectangle() ); } break; case W_META_ROUNDRECT: { Size aSize( ReadYXExt() ); pOut->DrawRoundRect( ReadRectangle(), Size( aSize.Width() / 2, aSize.Height() / 2 ) ); } break; case W_META_ELLIPSE: { pOut->DrawEllipse( ReadRectangle() ); } break; case W_META_ARC: { Point aEnd( ReadYX() ); Point aStart( ReadYX() ); Rectangle aRect( ReadRectangle() ); aRect.Justify(); pOut->DrawArc( aRect, aStart, aEnd ); } break; case W_META_PIE: { Point aEnd( ReadYX() ); Point aStart( ReadYX() ); Rectangle aRect( ReadRectangle() ); aRect.Justify(); // #i73608# OutputDevice deviates from WMF // semantics. start==end means full ellipse here. if( aStart == aEnd ) pOut->DrawEllipse( aRect ); else pOut->DrawPie( aRect, aStart, aEnd ); } break; case W_META_CHORD: { Point aEnd( ReadYX() ); Point aStart( ReadYX() ); Rectangle aRect( ReadRectangle() ); aRect.Justify(); pOut->DrawChord( aRect, aStart, aEnd ); } break; case W_META_POLYGON: { sal_uInt16 i,nPoints; *pWMF >> nPoints; Polygon aPoly( nPoints ); for( i = 0; i < nPoints; i++ ) aPoly[ i ] = ReadPoint(); pOut->DrawPolygon( aPoly ); } break; case W_META_POLYPOLYGON: { sal_uInt16 nPolyCount(0); // get number of polygons *pWMF >> nPolyCount; if(nPolyCount && !pWMF->IsEof()) { sal_uInt16* pnPoints = new sal_uInt16[nPolyCount]; sal_uInt16 a(0); PolyPolygon aPolyPoly(nPolyCount, nPolyCount); for(a = 0; a < nPolyCount && !pWMF->IsEof(); a++) { *pWMF >> pnPoints[a]; } for(a = 0; a < nPolyCount && !pWMF->IsEof(); a++) { const sal_uInt16 nPointCount(pnPoints[a]); Point* pPtAry = new Point[nPointCount]; for(sal_uInt16 b(0); b < nPointCount && !pWMF->IsEof(); b++) { pPtAry[b] = ReadPoint(); } aPolyPoly.Insert(Polygon(nPointCount, pPtAry)); delete[] pPtAry; } delete[] pnPoints; pOut->DrawPolyPolygon(aPolyPoly); } } break; case W_META_POLYLINE: { sal_uInt16 i,nPoints; *pWMF >> nPoints; Polygon aPoly( nPoints ); for( i = 0; i < nPoints; i++ ) aPoly[ i ] = ReadPoint(); pOut->DrawPolyLine( aPoly ); } break; case W_META_SAVEDC: { pOut->Push(); } break; case W_META_RESTOREDC: { pOut->Pop(); } break; case W_META_SETPIXEL: { const Color aColor = ReadColor(); pOut->DrawPixel( ReadYX(), aColor ); } break; case W_META_OFFSETCLIPRGN: { pOut->MoveClipRegion( ReadYXExt() ); } break; case W_META_TEXTOUT: { sal_uInt16 nLength; *pWMF >> nLength; if ( nLength ) { char* pChar = new char[ ( nLength + 1 ) &~ 1 ]; pWMF->Read( pChar, ( nLength + 1 ) &~ 1 ); String aText( pChar, nLength, pOut->GetCharSet() ); delete[] pChar; Point aPosition( ReadYX() ); pOut->DrawText( aPosition, aText ); } } break; case W_META_EXTTEXTOUT: { sal_Int16 nDx, nDxTmp; sal_uInt16 i, nLen, nOptions; sal_Int32 nRecordPos, nRecordSize, nOriginalTextLen, nNewTextLen; Point aPosition; Rectangle aRect; sal_Int32* pDXAry = NULL; pWMF->SeekRel(-6); nRecordPos = pWMF->Tell(); *pWMF >> nRecordSize; pWMF->SeekRel(2); aPosition = ReadYX(); *pWMF >> nLen >> nOptions; sal_Int32 nTextLayoutMode = TEXT_LAYOUT_DEFAULT; if ( nOptions & ETO_RTLREADING ) nTextLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT; pOut->SetTextLayoutMode( nTextLayoutMode ); DBG_ASSERT( ( nOptions & ( ETO_PDY | ETO_GLYPH_INDEX ) ) == 0, "SJ: ETO_PDY || ETO_GLYPH_INDEX in WMF" ); // Nur wenn der Text auch Zeichen enthaelt, macht die Ausgabe Sinn if( nLen ) { nOriginalTextLen = nLen; if( nOptions & ETO_CLIPPED ) { const Point aPt1( ReadPoint() ); const Point aPt2( ReadPoint() ); aRect = Rectangle( aPt1, aPt2 ); } char* pChar = new char[ ( nOriginalTextLen + 1 ) &~ 1 ]; pWMF->Read( pChar, ( nOriginalTextLen + 1 ) &~ 1 ); String aText( pChar, (sal_uInt16)nOriginalTextLen, pOut->GetCharSet() );// after this conversion the text may contain nNewTextLen = aText.Len(); // less character (japanese version), so the delete[] pChar; // dxAry will not fit if ( nNewTextLen ) { sal_uInt32 nMaxStreamPos = nRecordPos + ( nRecordSize << 1 ); sal_Int32 nDxArySize = nMaxStreamPos - pWMF->Tell(); sal_Int32 nDxAryEntries = nDxArySize >> 1; sal_Bool bUseDXAry = sal_False; if ( ( ( nDxAryEntries % nOriginalTextLen ) == 0 ) && ( nNewTextLen <= nOriginalTextLen ) ) { pDXAry = new sal_Int32[ nNewTextLen ]; for ( i = 0; i < nNewTextLen; i++ ) { if ( pWMF->Tell() >= nMaxStreamPos ) break; *pWMF >> nDx; if ( nNewTextLen != nOriginalTextLen ) { ByteString aTmp( aText.GetChar( i ), pOut->GetCharSet() ); if ( aTmp.Len() > 1 ) { sal_Int32 nDxCount = aTmp.Len() - 1; if ( ( ( nDxCount * 2 ) + pWMF->Tell() ) > nMaxStreamPos ) break; while ( nDxCount-- ) { *pWMF >> nDxTmp; nDx = nDx + nDxTmp; } } } pDXAry[ i ] = nDx; } if ( i == nNewTextLen ) bUseDXAry = 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; *pWMF >> nObjIndex; pOut->SelectObject( nObjIndex ); } break; case W_META_SETTEXTALIGN: { sal_uInt16 nAlign; *pWMF >> nAlign; pOut->SetTextAlign( nAlign ); } break; case W_META_BITBLT: { // 0-3 : nWinROP #93454# // 4-5 : y offset of source bitmap // 6-7 : x offset of source bitmap // 8-9 : used height of source bitmap // 10-11 : used width of source bitmap // 12-13 : destination position y (in pixel) // 14-15 : destination position x (in pixel) // 16-17 : dont know // 18-19 : Width Bitmap in Pixel // 20-21 : Height Bitmap in Pixel // 22-23 : bytes per scanline // 24 : planes // 25 : bitcount sal_Int32 nWinROP; sal_uInt16 nSx, nSy, nSxe, nSye, nDontKnow, nWidth, nHeight, nBytesPerScan; sal_uInt8 nPlanes, nBitCount; *pWMF >> nWinROP >> nSy >> nSx >> nSye >> nSxe; Point aPoint( ReadYX() ); *pWMF >> nDontKnow >> nWidth >> nHeight >> nBytesPerScan >> nPlanes >> nBitCount; if ( nWidth && nHeight && ( nPlanes == 1 ) && ( nBitCount == 1 ) ) { Bitmap aBmp( Size( nWidth, nHeight ), nBitCount ); BitmapWriteAccess* pAcc; pAcc = aBmp.AcquireWriteAccess(); if ( pAcc ) { sal_uInt16 y, x, scan; sal_Int8 i, nEightPixels; for ( y = 0; y < nHeight; y++ ) { x = 0; for ( scan = 0; scan < nBytesPerScan; scan++ ) { *pWMF >> nEightPixels; for ( i = 7; i >= 0; i-- ) { if ( x < nWidth ) { pAcc->SetPixelIndex( y, x, (nEightPixels>>i)&1 ); } x++; } } } aBmp.ReleaseAccess( pAcc ); if ( nSye && nSxe && ( ( nSx + nSxe ) <= aBmp.GetSizePixel().Width() ) && ( ( nSy + nSye <= aBmp.GetSizePixel().Height() ) ) ) { Rectangle aCropRect( Point( nSx, nSy ), Size( nSxe, nSye ) ); aBmp.Crop( aCropRect ); } Rectangle aDestRect( aPoint, Size( nSxe, nSye ) ); aBmpSaveList.Insert( new BSaveStruct( aBmp, aDestRect, nWinROP ), LIST_APPEND ); } } } break; case W_META_STRETCHBLT: case W_META_DIBBITBLT: case W_META_DIBSTRETCHBLT: case W_META_STRETCHDIB: { sal_Int32 nWinROP; sal_uInt16 nSx, nSy, nSxe, nSye, nUsage; Bitmap aBmp; *pWMF >> nWinROP; if( nFunc == W_META_STRETCHDIB ) *pWMF >> nUsage; // nSye and nSxe is the number of pixels that has to been used if( nFunc == W_META_STRETCHDIB || nFunc == W_META_STRETCHBLT || nFunc == W_META_DIBSTRETCHBLT ) *pWMF >> nSye >> nSxe; else nSye = nSxe = 0; // set this to zero as indicator not to scale the bitmap later // nSy and nx is the offset of the first pixel *pWMF >> nSy >> nSx; if( nFunc == W_META_STRETCHDIB || nFunc == W_META_DIBBITBLT || nFunc == W_META_DIBSTRETCHBLT ) { if ( nWinROP == PATCOPY ) *pWMF >> nUsage; // i don't know anything of this parameter, so its called nUsage // pOut->DrawRect( Rectangle( ReadYX(), aDestSize ), 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 ) ReadDIB(aBmp, *pWMF, false); // test if it is sensible to crop if ( nSye && nSxe && ( ( nSx + nSxe ) <= aBmp.GetSizePixel().Width() ) && ( ( nSy + nSye <= aBmp.GetSizePixel().Height() ) ) ) { Rectangle aCropRect( Point( nSx, nSy ), Size( nSxe, nSye ) ); aBmp.Crop( aCropRect ); } aBmpSaveList.Insert( new BSaveStruct( aBmp, aDestRect, nWinROP ), LIST_APPEND ); } } } break; case W_META_DIBCREATEPATTERNBRUSH: { Bitmap aBmp; BitmapReadAccess* pBmp; sal_uInt32 nRed = 0, nGreen = 0, nBlue = 0, nCount = 1; sal_uInt16 nFunction; *pWMF >> nFunction >> nFunction; ReadDIB(aBmp, *pWMF, 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; *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, nWidth, nHeight; *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; *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, lfOrientation, lfWeight; // ( ehemals 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 = gsl_getSystemTextEncoding(); else eCharSet = rtl_getTextEncodingFromWindowsCharset( aLogFont.lfCharSet ); if ( eCharSet == RTL_TEXTENCODING_DONTKNOW ) eCharSet = gsl_getSystemTextEncoding(); if ( eCharSet == RTL_TEXTENCODING_SYMBOL ) eCharSet = RTL_TEXTENCODING_MS_1252; aLogFont.alfFaceName = UniString( lfFaceName, eCharSet ); pOut->CreateObject( GDI_FONT, new WinMtfFontStyle( aLogFont ) ); } break; case W_META_CREATEBITMAPINDIRECT: { pOut->CreateObject( GDI_DUMMY ); } break; case W_META_CREATEBITMAP: { pOut->CreateObject( GDI_DUMMY ); } break; case W_META_CREATEREGION: { pOut->CreateObject( GDI_DUMMY ); } break; case W_META_EXCLUDECLIPRECT : { pOut->ExcludeClipRect( ReadRectangle() ); } break; case W_META_PATBLT: { sal_uInt32 nROP, nOldROP; *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; *pWMF >> nObjIndex; if ( !nObjIndex ) { PolyPolygon aEmptyPolyPoly; pOut->SetClipPath( aEmptyPolyPoly, RGN_COPY, sal_True ); } } break; case W_META_ESCAPE : { // nRecSize has been checked previously to be greater than 3 sal_uInt64 nMetaRecSize = static_cast< sal_uInt64 >( nRecSize - 2 ) * 2; sal_uInt64 nMetaRecEndPos = pWMF->Tell() + nMetaRecSize; // taking care that nRecSize does not exceed the maximal stream position if ( nMetaRecEndPos > nEndPos ) { pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); break; } if ( nRecSize >= 4 ) // minimal escape lenght { sal_uInt16 nMode, nLen; *pWMF >> nMode >> nLen; if ( ( nMode == W_MFCOMMENT ) && ( nLen >= 4 ) ) { sal_uInt32 nNewMagic; // we have to read int32 for *pWMF >> nNewMagic; // META_ESCAPE_ENHANCED_METAFILE CommentIdentifier if( nNewMagic == 0x2c2a4f4f && nLen >= 14 ) { sal_uInt16 nMagic2; *pWMF >> nMagic2; if( nMagic2 == 0x0a ) // 2nd half of magic { // continue with private escape sal_uInt32 nCheck, nEsc; *pWMF >> nCheck >> nEsc; sal_uInt32 nEscLen = nLen - 14; if ( nEscLen <= ( nRecSize * 2 ) ) { #ifdef OSL_BIGENDIAN sal_uInt32 nTmp = SWAPLONG( nEsc ); sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 ); #else sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 ); #endif sal_Int8* pData = NULL; if ( ( static_cast< sal_uInt64 >( nEscLen ) + pWMF->Tell() ) > nMetaRecEndPos ) { pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); break; } if ( nEscLen > 0 ) { pData = new sal_Int8[ nEscLen ]; pWMF->Read( pData, nEscLen ); nCheckSum = rtl_crc32( nCheckSum, pData, nEscLen ); } if ( nCheck == nCheckSum ) { switch( nEsc ) { case PRIVATE_ESCAPE_UNICODE : { // we will use text instead of polygons only if we have the correct font if ( Application::GetDefaultDevice()->IsFontAvailable( pOut->GetFont().GetName() ) ) { Point aPt; String aString; sal_uInt32 i, nStringLen, nDXCount; sal_Int32* pDXAry = NULL; SvMemoryStream aMemoryStream( nEscLen ); aMemoryStream.Write( pData, nEscLen ); aMemoryStream.Seek( STREAM_SEEK_TO_BEGIN ); aMemoryStream >> aPt.X() >> aPt.Y() >> nStringLen; if ( ( static_cast< sal_uInt64 >( nStringLen ) * sizeof( sal_Unicode ) ) < ( nEscLen - aMemoryStream.Tell() ) ) { sal_Unicode* pBuf = aString.AllocBuffer( (xub_StrLen)nStringLen ); for ( i = 0; i < nStringLen; i++ ) aMemoryStream >> pBuf[ i ]; aMemoryStream >> nDXCount; if ( ( static_cast< sal_uInt64 >( nDXCount ) * sizeof( sal_Int32 ) ) >= ( nEscLen - aMemoryStream.Tell() ) ) nDXCount = 0; if ( nDXCount ) pDXAry = new sal_Int32[ nDXCount ]; for ( i = 0; i < nDXCount; i++ ) aMemoryStream >> pDXAry[ i ]; aMemoryStream >> nSkipActions; pOut->DrawText( aPt, aString, pDXAry ); delete[] pDXAry; } } } break; } } delete[] pData; } } } else if ( (nNewMagic == static_cast< sal_uInt32 >(0x43464D57)) && (nLen >= 34) && ( (sal_Int32)(nLen + 10) <= (sal_Int32)(nRecSize * 2) )) { sal_uInt32 nComType, nVersion, nFlags, nComRecCount, nCurRecSize, nRemainingSize, nEMFTotalSize; sal_uInt16 nCheck; *pWMF >> nComType >> nVersion >> nCheck >> nFlags >> nComRecCount >> nCurRecSize >> nRemainingSize >> nEMFTotalSize; // the nRemainingSize is not mentioned in MSDN documentation // but it seems to be required to read in data produced by OLE if( nComType == 0x01 && nVersion == 0x10000 && nComRecCount ) { if( !nEMFRec ) { // first EMF comment nEMFRecCount = nComRecCount; nEMFSize = nEMFTotalSize; pEMFStream = new SvMemoryStream( nEMFSize ); } else if( ( nEMFRecCount != nComRecCount ) || ( nEMFSize != nEMFTotalSize ) ) // add additional checks here { // total records should be the same as in previous comments nEMFRecCount = 0xFFFFFFFF; delete pEMFStream; pEMFStream = NULL; } nEMFRec++; if( pEMFStream && nCurRecSize + 34 > nLen ) { nEMFRecCount = 0xFFFFFFFF; delete pEMFStream; pEMFStream = NULL; } if( pEMFStream ) { sal_Int8* pBuf = new sal_Int8[ nCurRecSize ]; sal_uInt32 nCount = pWMF->Read( pBuf, nCurRecSize ); if( nCount == nCurRecSize ) pEMFStream->Write( pBuf, nCount ); delete[] pBuf; } } } } } } break; case W_META_SETRELABS: case W_META_SETPOLYFILLMODE: case W_META_SETSTRETCHBLTMODE: case W_META_SETTEXTCHAREXTRA: case W_META_SETTEXTJUSTIFICATION: case W_META_FLOODFILL : case W_META_FILLREGION: case W_META_FRAMEREGION: case W_META_INVERTREGION: case W_META_PAINTREGION: case W_META_DRAWTEXT: case W_META_SETMAPPERFLAGS: case W_META_SETDIBTODEV: case W_META_SELECTPALETTE: case W_META_REALIZEPALETTE: case W_META_ANIMATEPALETTE: case W_META_SETPALENTRIES: case W_META_RESIZEPALETTE: case W_META_EXTFLOODFILL: case W_META_RESETDC: case W_META_STARTDOC: case W_META_STARTPAGE: case W_META_ENDPAGE: case W_META_ABORTDOC: case W_META_ENDDOC: break; } } // ------------------------------------------------------------------------ sal_Bool WMFReader::ReadHeader() { Rectangle aPlaceableBound; sal_uInt32 nl, nStrmPos = pWMF->Tell(); // Einlesen des METAFILEHEADER, falls vorhanden *pWMF >> nl; Size aWMFSize; if ( nl == 0x9ac6cdd7L ) { sal_Int16 nVal; // hmf (Unused) ueberlesen wir pWMF->SeekRel(2); // BoundRect *pWMF >> nVal; aPlaceableBound.Left() = nVal; *pWMF >> nVal; aPlaceableBound.Top() = nVal; *pWMF >> nVal; aPlaceableBound.Right() = nVal; *pWMF >> nVal; aPlaceableBound.Bottom() = nVal; // inch *pWMF >> nUnitsPerInch; // reserved pWMF->SeekRel( 4 ); // checksum pruefen wir lieber nicht pWMF->SeekRel( 2 ); } else { nUnitsPerInch = 96; pWMF->Seek( nStrmPos + 18 ); // set the streampos to the start of the metaactions GetPlaceableBound( aPlaceableBound, pWMF ); pWMF->Seek( nStrmPos ); } pOut->SetWinOrg( aPlaceableBound.TopLeft() ); aWMFSize = Size( labs( aPlaceableBound.GetWidth() ), labs( aPlaceableBound.GetHeight() ) ); pOut->SetWinExt( aWMFSize ); Size aDevExt( 10000, 10000 ); if( ( labs( aWMFSize.Width() ) > 1 ) && ( labs( aWMFSize.Height() ) > 1 ) ) { const Fraction aFrac( 1, nUnitsPerInch ); MapMode aWMFMap( MAP_INCH, Point(), aFrac, aFrac ); Size aSize100( OutputDevice::LogicToLogic( aWMFSize, aWMFMap, MAP_100TH_MM ) ); aDevExt = Size( labs( aSize100.Width() ), labs( aSize100.Height() ) ); } pOut->SetDevExt( aDevExt ); // Einlesen des METAHEADER *pWMF >> nl; // Typ und Headergroesse if( nl != 0x00090001 ) { pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); return sal_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 sal_True; } 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.Count() && ( nFunction != W_META_STRETCHDIB ) && ( nFunction != W_META_DIBBITBLT ) && ( nFunction != W_META_DIBSTRETCHBLT ) ) { pOut->ResolveBitmapActions( aBmpSaveList ); } if ( !nSkipActions ) ReadRecordParams( nFunction ); else nSkipActions--; if( pEMFStream && nEMFRecCount == nEMFRec ) { GDIMetaFile aMeta; pEMFStream->Seek( 0 ); EnhWMFReader* pEMFReader = new EnhWMFReader ( *pEMFStream, aMeta ); bEMFAvailable = pEMFReader->ReadEnhWMF(); delete pEMFReader; // destroy first!!! if( bEMFAvailable ) { pOut->AddFromGDIMetaFile( aMeta ); pOut->SetrclFrame( Rectangle(0, 0, aMeta.GetPrefSize().Width(), aMeta.GetPrefSize().Height() )); // 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.Count() ) pOut->ResolveBitmapActions( aBmpSaveList ); } if ( pWMF->GetError() ) pWMF->Seek( nStartPos ); } // ------------------------------------------------------------------------ static void GetWinExtMax( const Point& rSource, Rectangle& rPlaceableBound, const sal_Int16 nMapMode ) { Point aSource( rSource ); if ( nMapMode == MM_HIMETRIC ) aSource.Y() = -rSource.Y(); if ( aSource.X() < rPlaceableBound.Left() ) rPlaceableBound.Left() = aSource.X(); if ( aSource.X() > rPlaceableBound.Right() ) rPlaceableBound.Right() = aSource.X(); if ( aSource.Y() < rPlaceableBound.Top() ) rPlaceableBound.Top() = aSource.Y(); if ( aSource.Y() > rPlaceableBound.Bottom() ) rPlaceableBound.Bottom() = aSource.Y(); } static void GetWinExtMax( const Rectangle& rSource, Rectangle& rPlaceableBound, const sal_Int16 nMapMode ) { GetWinExtMax( rSource.TopLeft(), rPlaceableBound, nMapMode ); GetWinExtMax( rSource.BottomRight(), rPlaceableBound, nMapMode ); } sal_Bool WMFReader::GetPlaceableBound( Rectangle& rPlaceableBound, SvStream* pStm ) { sal_Bool bRet = sal_True; rPlaceableBound.Left() = (sal_Int32)0x7fffffff; rPlaceableBound.Top() = (sal_Int32)0x7fffffff; rPlaceableBound.Right() = (sal_Int32)0x80000000; rPlaceableBound.Bottom() = (sal_Int32)0x80000000; sal_Int16 nMapMode = MM_ANISOTROPIC; sal_uInt16 nFunction; sal_uInt32 nRSize; sal_uInt32 nPos = pStm->Tell(); sal_uInt32 nEnd = pStm->Seek( STREAM_SEEK_TO_END ); pStm->Seek( nPos ); if( nEnd - nPos ) { while( bRet ) { *pStm >> nRSize >> nFunction; if( pStm->GetError() || ( nRSize < 3 ) || ( nRSize==3 && nFunction==0 ) || pStm->IsEof() ) { if( pStm->IsEof() ) { pStm->SetError( SVSTREAM_FILEFORMAT_ERROR ); bRet = sal_False; } break; } switch( nFunction ) { case W_META_SETWINDOWORG: { Point aWinOrg; aWinOrg = ReadYX(); rPlaceableBound.SetPos( aWinOrg ); } break; case W_META_SETWINDOWEXT: { Point aPos0( 0, 0 ); sal_Int16 nWidth, nHeight; *pStm >> nHeight >> nWidth; rPlaceableBound.SetSize( Size( nWidth, nHeight ) ); } break; case W_META_SETMAPMODE : *pStm >> nMapMode; break; case W_META_MOVETO: case W_META_LINETO: GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode ); break; case W_META_RECTANGLE: case W_META_INTERSECTCLIPRECT: case W_META_EXCLUDECLIPRECT : case W_META_ELLIPSE: GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode ); break; case W_META_ROUNDRECT: { Size aSize( ReadYXExt() ); GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode ); } break; case W_META_ARC: case W_META_PIE: case W_META_CHORD: { Point aEnd( ReadYX() ); Point aStart( ReadYX() ); GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode ); } break; case W_META_POLYGON: { sal_uInt16 i,nPoints; *pStm >> nPoints; for( i = 0; i < nPoints; i++ ) GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode ); } break; case W_META_POLYPOLYGON: { sal_uInt16 i, nPoly, nPoints = 0; *pStm >> nPoly; for( i = 0; i < nPoly; i++ ) { sal_uInt16 nP; *pStm >> nP; nPoints = nPoints + nP; } for ( i = 0; i < nPoints; i++ ) GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode ); } break; case W_META_POLYLINE: { sal_uInt16 i,nPoints; *pStm >> nPoints; for( i = 0; i < nPoints; i++ ) GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode ); } break; case W_META_SETPIXEL: { const Color aColor = ReadColor(); GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode ); } break; case W_META_TEXTOUT: { 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; sal_Int32 nRecordPos, nRecordSize; Point aPosition; Rectangle aRect; pStm->SeekRel(-6); nRecordPos = pStm->Tell(); *pStm >> nRecordSize; pStm->SeekRel(2); aPosition = ReadYX(); *pStm >> nLen >> nOptions; // todo: we also have to take care of the text width if( nLen ) GetWinExtMax( aPosition, rPlaceableBound, nMapMode ); } break; case W_META_BITBLT: case W_META_STRETCHBLT: case W_META_DIBBITBLT: case W_META_DIBSTRETCHBLT: case W_META_STRETCHDIB: { sal_Int32 nWinROP; sal_uInt16 nSx, nSy, nSxe, nSye, nUsage; *pStm >> nWinROP; if( nFunction == W_META_STRETCHDIB ) *pStm >> nUsage; // nSye and nSxe is the number of pixels that has to been used if( nFunction == W_META_STRETCHDIB || nFunction == W_META_STRETCHBLT || nFunction == W_META_DIBSTRETCHBLT ) *pStm >> nSye >> nSxe; else nSye = nSxe = 0; // set this to zero as indicator not to scale the bitmap later // nSy and nx is the offset of the first pixel *pStm >> nSy >> nSx; if( nFunction == W_META_STRETCHDIB || nFunction == W_META_DIBBITBLT || nFunction == W_META_DIBSTRETCHBLT ) { if ( nWinROP == PATCOPY ) *pStm >> nUsage; // i don't know anything of this parameter, so its called nUsage // pOut->DrawRect( Rectangle( ReadYX(), aDestSize ), 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; }