Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / source / filter / wmf / winwmf.cxx
blob1f4cd7d383ed923cbb0d4bc4f10cf314f572185d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "winmtf.hxx"
22 #include <boost/scoped_array.hpp>
23 #include <boost/optional.hpp>
24 #include <vcl/gdimtf.hxx>
25 #include <vcl/wmf.hxx>
26 #include <rtl/crc.h>
27 #include <rtl/tencinfo.h>
28 #include <osl/endian.h>
29 #include <vcl/svapp.hxx>
30 #include <vcl/dibtools.hxx>
31 #include <tools/fract.hxx>
33 // MS Windows defines
35 #define W_META_SETBKCOLOR 0x0201
36 #define W_META_SETBKMODE 0x0102
37 #define W_META_SETMAPMODE 0x0103
38 #define W_META_SETROP2 0x0104
39 #define W_META_SETRELABS 0x0105
40 #define W_META_SETPOLYFILLMODE 0x0106
41 #define W_META_SETSTRETCHBLTMODE 0x0107
42 #define W_META_SETTEXTCHAREXTRA 0x0108
43 #define W_META_SETTEXTCOLOR 0x0209
44 #define W_META_SETTEXTJUSTIFICATION 0x020A
45 #define W_META_SETWINDOWORG 0x020B
46 #define W_META_SETWINDOWEXT 0x020C
47 #define W_META_SETVIEWPORTORG 0x020D
48 #define W_META_SETVIEWPORTEXT 0x020E
49 #define W_META_OFFSETWINDOWORG 0x020F
50 #define W_META_SCALEWINDOWEXT 0x0410
51 #define W_META_OFFSETVIEWPORTORG 0x0211
52 #define W_META_SCALEVIEWPORTEXT 0x0412
53 #define W_META_LINETO 0x0213
54 #define W_META_MOVETO 0x0214
55 #define W_META_EXCLUDECLIPRECT 0x0415
56 #define W_META_INTERSECTCLIPRECT 0x0416
57 #define W_META_ARC 0x0817
58 #define W_META_ELLIPSE 0x0418
59 #define W_META_FLOODFILL 0x0419
60 #define W_META_PIE 0x081A
61 #define W_META_RECTANGLE 0x041B
62 #define W_META_ROUNDRECT 0x061C
63 #define W_META_PATBLT 0x061D
64 #define W_META_SAVEDC 0x001E
65 #define W_META_SETPIXEL 0x041F
66 #define W_META_OFFSETCLIPRGN 0x0220
67 #define W_META_TEXTOUT 0x0521
68 #define W_META_BITBLT 0x0922
69 #define W_META_STRETCHBLT 0x0B23
70 #define W_META_POLYGON 0x0324
71 #define W_META_POLYLINE 0x0325
72 #define W_META_ESCAPE 0x0626
73 #define W_META_RESTOREDC 0x0127
74 #define W_META_FILLREGION 0x0228
75 #define W_META_FRAMEREGION 0x0429
76 #define W_META_INVERTREGION 0x012A
77 #define W_META_PAINTREGION 0x012B
78 #define W_META_SELECTCLIPREGION 0x012C
79 #define W_META_SELECTOBJECT 0x012D
80 #define W_META_SETTEXTALIGN 0x012E
81 #define W_META_DRAWTEXT 0x062F
82 #define W_META_CHORD 0x0830
83 #define W_META_SETMAPPERFLAGS 0x0231
84 #define W_META_EXTTEXTOUT 0x0a32
85 #define W_META_SETDIBTODEV 0x0d33
86 #define W_META_SELECTPALETTE 0x0234
87 #define W_META_REALIZEPALETTE 0x0035
88 #define W_META_ANIMATEPALETTE 0x0436
89 #define W_META_SETPALENTRIES 0x0037
90 #define W_META_POLYPOLYGON 0x0538
91 #define W_META_RESIZEPALETTE 0x0139
92 #define W_META_DIBBITBLT 0x0940
93 #define W_META_DIBSTRETCHBLT 0x0b41
94 #define W_META_DIBCREATEPATTERNBRUSH 0x0142
95 #define W_META_STRETCHDIB 0x0f43
96 #define W_META_EXTFLOODFILL 0x0548
97 #define W_META_RESETDC 0x014C
98 #define W_META_STARTDOC 0x014D
99 #define W_META_STARTPAGE 0x004F
100 #define W_META_ENDPAGE 0x0050
101 #define W_META_ABORTDOC 0x0052
102 #define W_META_ENDDOC 0x005E
103 #define W_META_DELETEOBJECT 0x01f0
104 #define W_META_CREATEPALETTE 0x00f7
105 #define W_META_CREATEBRUSH 0x00F8
106 #define W_META_CREATEPATTERNBRUSH 0x01F9
107 #define W_META_CREATEPENINDIRECT 0x02FA
108 #define W_META_CREATEFONTINDIRECT 0x02FB
109 #define W_META_CREATEBRUSHINDIRECT 0x02FC
110 #define W_META_CREATEBITMAPINDIRECT 0x02FD
111 #define W_META_CREATEBITMAP 0x06FE
112 #define W_META_CREATEREGION 0x06FF
114 static void GetWinExtMax( const Point& rSource, Rectangle& rPlaceableBound, const sal_Int16 nMapMode )
116 Point aSource( rSource );
117 if ( nMapMode == MM_HIMETRIC )
118 aSource.Y() = -rSource.Y();
119 if ( aSource.X() < rPlaceableBound.Left() )
120 rPlaceableBound.Left() = aSource.X();
121 if ( aSource.X() > rPlaceableBound.Right() )
122 rPlaceableBound.Right() = aSource.X();
123 if ( aSource.Y() < rPlaceableBound.Top() )
124 rPlaceableBound.Top() = aSource.Y();
125 if ( aSource.Y() > rPlaceableBound.Bottom() )
126 rPlaceableBound.Bottom() = aSource.Y();
129 static void GetWinExtMax( const Rectangle& rSource, Rectangle& rPlaceableBound, const sal_Int16 nMapMode )
131 GetWinExtMax( rSource.TopLeft(), rPlaceableBound, nMapMode );
132 GetWinExtMax( rSource.BottomRight(), rPlaceableBound, nMapMode );
135 inline Point WMFReader::ReadPoint()
137 short nX = 0, nY = 0;
138 pWMF->ReadInt16( nX ).ReadInt16( nY );
139 return Point( nX, nY );
142 inline Point WMFReader::ReadYX()
144 short nX = 0, nY = 0;
145 pWMF->ReadInt16( nY ).ReadInt16( nX );
146 return Point( nX, nY );
149 Rectangle WMFReader::ReadRectangle()
151 Point aBR, aTL;
152 aBR = ReadYX();
153 aTL = ReadYX();
154 aBR.X()--;
155 aBR.Y()--;
156 return Rectangle( aTL, aBR );
159 Size WMFReader::ReadYXExt()
161 short nW=0, nH=0;
162 pWMF->ReadInt16( nH ).ReadInt16( nW );
163 return Size( nW, nH );
166 void WMFReader::ReadRecordParams( sal_uInt16 nFunc )
168 switch( nFunc )
170 case W_META_SETBKCOLOR:
172 pOut->SetBkColor( ReadColor() );
174 break;
176 case W_META_SETBKMODE:
178 sal_uInt16 nDat = 0;
179 pWMF->ReadUInt16( nDat );
180 pOut->SetBkMode( static_cast<BkMode>(nDat) );
182 break;
184 // !!!
185 case W_META_SETMAPMODE:
187 sal_Int16 nMapMode = 0;
188 pWMF->ReadInt16( nMapMode );
189 pOut->SetMapMode( nMapMode );
191 break;
193 case W_META_SETROP2:
195 sal_uInt16 nROP2 = 0;
196 pWMF->ReadUInt16( nROP2 );
197 pOut->SetRasterOp( nROP2 );
199 break;
201 case W_META_SETTEXTCOLOR:
203 pOut->SetTextColor( ReadColor() );
205 break;
207 case W_META_SETWINDOWORG:
209 pOut->SetWinOrg( ReadYX() );
211 break;
213 case W_META_SETWINDOWEXT:
215 short nWidth = 0, nHeight = 0;
216 pWMF->ReadInt16( nHeight ).ReadInt16( nWidth );
217 pOut->SetWinExt( Size( nWidth, nHeight ) );
219 break;
221 case W_META_OFFSETWINDOWORG:
223 short nXAdd = 0, nYAdd = 0;
224 pWMF->ReadInt16( nYAdd ).ReadInt16( nXAdd );
225 pOut->SetWinOrgOffset( nXAdd, nYAdd );
227 break;
229 case W_META_SCALEWINDOWEXT:
231 short nXNum = 0, nXDenom = 0, nYNum = 0, nYDenom = 0;
232 pWMF->ReadInt16( nYDenom ).ReadInt16( nYNum ).ReadInt16( nXDenom ).ReadInt16( nXNum );
233 if (!nYDenom || !nXDenom)
235 pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
236 break;
238 pOut->ScaleWinExt( (double)nXNum / nXDenom, (double)nYNum / nYDenom );
240 break;
242 case W_META_SETVIEWPORTORG:
243 case W_META_SETVIEWPORTEXT:
244 break;
246 case W_META_OFFSETVIEWPORTORG:
248 short nXAdd = 0, nYAdd = 0;
249 pWMF->ReadInt16( nYAdd ).ReadInt16( nXAdd );
250 pOut->SetDevOrgOffset( nXAdd, nYAdd );
252 break;
254 case W_META_SCALEVIEWPORTEXT:
256 short nXNum = 0, nXDenom = 0, nYNum = 0, nYDenom = 0;
257 pWMF->ReadInt16( nYDenom ).ReadInt16( nYNum ).ReadInt16( nXDenom ).ReadInt16( nXNum );
258 if (!nYDenom || !nXDenom)
260 pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
261 break;
263 pOut->ScaleDevExt( (double)nXNum / nXDenom, (double)nYNum / nYDenom );
265 break;
267 case W_META_LINETO:
269 pOut->LineTo( ReadYX() );
271 break;
273 case W_META_MOVETO:
275 pOut->MoveTo( ReadYX() );
277 break;
279 case W_META_INTERSECTCLIPRECT:
281 pOut->IntersectClipRect( ReadRectangle() );
283 break;
285 case W_META_RECTANGLE:
287 pOut->DrawRect( ReadRectangle() );
289 break;
291 case W_META_ROUNDRECT:
293 Size aSize( ReadYXExt() );
294 pOut->DrawRoundRect( ReadRectangle(), Size( aSize.Width() / 2, aSize.Height() / 2 ) );
296 break;
298 case W_META_ELLIPSE:
300 pOut->DrawEllipse( ReadRectangle() );
302 break;
304 case W_META_ARC:
306 Point aEnd( ReadYX() );
307 Point aStart( ReadYX() );
308 Rectangle aRect( ReadRectangle() );
309 aRect.Justify();
310 pOut->DrawArc( aRect, aStart, aEnd );
312 break;
314 case W_META_PIE:
316 Point aEnd( ReadYX() );
317 Point aStart( ReadYX() );
318 Rectangle aRect( ReadRectangle() );
319 aRect.Justify();
321 // #i73608# OutputDevice deviates from WMF
322 // semantics. start==end means full ellipse here.
323 if( aStart == aEnd )
324 pOut->DrawEllipse( aRect );
325 else
326 pOut->DrawPie( aRect, aStart, aEnd );
328 break;
330 case W_META_CHORD:
332 Point aEnd( ReadYX() );
333 Point aStart( ReadYX() );
334 Rectangle aRect( ReadRectangle() );
335 aRect.Justify();
336 pOut->DrawChord( aRect, aStart, aEnd );
338 break;
340 case W_META_POLYGON:
342 bool bRecordOk = true;
344 sal_uInt16 nPoints(0);
345 pWMF->ReadUInt16(nPoints);
347 if (nPoints > pWMF->remainingSize() / (2 * sizeof(sal_uInt16)))
349 bRecordOk = false;
351 else
353 Polygon aPoly(nPoints);
354 for (sal_uInt16 i(0); i < nPoints && pWMF->good(); ++i)
355 aPoly[ i ] = ReadPoint();
356 pOut->DrawPolygon(aPoly);
359 SAL_WARN_IF(!bRecordOk, "vcl.filter", "polygon record has more points than we can handle");
361 bRecordOk &= pWMF->good();
363 if (!bRecordOk)
365 pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
366 break;
369 break;
371 case W_META_POLYPOLYGON:
373 bool bRecordOk = true;
374 sal_uInt16 nPolyCount(0);
375 // Number of polygons:
376 pWMF->ReadUInt16( nPolyCount );
377 if (nPolyCount && pWMF->good())
379 if (nPolyCount > pWMF->remainingSize() / sizeof(sal_uInt16))
381 bRecordOk = false;
382 break;
385 // Number of points of each polygon. Determine total number of points
386 boost::scoped_array<sal_uInt16> xPolygonPointCounts(new sal_uInt16[nPolyCount]);
387 sal_uInt16* pnPoints = xPolygonPointCounts.get();
388 tools::PolyPolygon aPolyPoly(nPolyCount, nPolyCount);
389 sal_uInt16 nPoints = 0;
390 for (sal_uInt16 a = 0; a < nPolyCount && pWMF->good(); ++a)
392 pWMF->ReadUInt16( pnPoints[a] );
394 if (pnPoints[a] > SAL_MAX_UINT16 - nPoints)
396 bRecordOk = false;
397 break;
400 nPoints += pnPoints[a];
403 SAL_WARN_IF(!bRecordOk, "vcl.filter", "polypolygon record has more polygons than we can handle");
405 bRecordOk &= pWMF->good();
407 if (!bRecordOk)
409 pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
410 break;
413 // Polygon points are:
414 for (sal_uInt16 a = 0; a < nPolyCount && pWMF->good(); ++a)
416 const sal_uInt16 nPointCount(pnPoints[a]);
418 if (nPointCount > pWMF->remainingSize() / (2 * sizeof(sal_uInt16)))
420 bRecordOk = false;
421 break;
424 boost::scoped_array<Point> xPolygonPoints(new Point[nPointCount]);
425 Point* pPtAry = xPolygonPoints.get();
427 for(sal_uInt16 b(0); b < nPointCount && pWMF->good(); ++b)
429 pPtAry[b] = ReadPoint();
432 aPolyPoly.Insert(Polygon(nPointCount, pPtAry));
435 bRecordOk &= pWMF->good();
437 if (!bRecordOk)
439 pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
440 break;
443 pOut->DrawPolyPolygon( aPolyPoly );
446 break;
448 case W_META_POLYLINE:
450 bool bRecordOk = true;
452 sal_uInt16 nPoints(0);
453 pWMF->ReadUInt16(nPoints);
455 if (nPoints > pWMF->remainingSize() / (2 * sizeof(sal_uInt16)))
457 bRecordOk = false;
459 else
461 Polygon aPoly(nPoints);
462 for (sal_uInt16 i(0); i < nPoints && pWMF->good(); ++i)
463 aPoly[ i ] = ReadPoint();
464 pOut->DrawPolyLine( aPoly );
467 SAL_WARN_IF(!bRecordOk, "vcl.filter", "polyline record has more points than we can handle");
469 bRecordOk &= pWMF->good();
471 if (!bRecordOk)
473 pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
474 break;
477 break;
479 case W_META_SAVEDC:
481 pOut->Push();
483 break;
485 case W_META_RESTOREDC:
487 pOut->Pop();
489 break;
491 case W_META_SETPIXEL:
493 const Color aColor = ReadColor();
494 pOut->DrawPixel( ReadYX(), aColor );
496 break;
498 case W_META_OFFSETCLIPRGN:
500 pOut->MoveClipRegion( ReadYXExt() );
502 break;
504 case W_META_TEXTOUT:
506 sal_uInt16 nLength = 0;
507 pWMF->ReadUInt16( nLength );
508 if ( nLength )
510 boost::scoped_array<char> pChar(new char[ ( nLength + 1 ) &~ 1 ]);
511 pWMF->Read( pChar.get(), ( nLength + 1 ) &~ 1 );
512 OUString aText( pChar.get(), nLength, pOut->GetCharSet() );
513 pChar.reset();
514 Point aPosition( ReadYX() );
515 pOut->DrawText( aPosition, aText );
518 break;
520 case W_META_EXTTEXTOUT:
522 sal_uInt16 nLen = 0, nOptions = 0;
523 sal_Int32 nRecordPos, nRecordSize = 0, nOriginalTextLen, nNewTextLen;
524 Point aPosition;
525 Rectangle aRect;
526 boost::scoped_array<long> pDXAry;
528 pWMF->SeekRel(-6);
529 nRecordPos = pWMF->Tell();
530 pWMF->ReadInt32( nRecordSize );
531 pWMF->SeekRel(2);
532 aPosition = ReadYX();
533 pWMF->ReadUInt16( nLen );
534 pWMF->ReadUInt16( nOptions );
536 ComplexTextLayoutMode nTextLayoutMode = TEXT_LAYOUT_DEFAULT;
537 if ( nOptions & ETO_RTLREADING )
538 nTextLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT;
539 pOut->SetTextLayoutMode( nTextLayoutMode );
540 DBG_ASSERT( ( nOptions & ( ETO_PDY | ETO_GLYPH_INDEX ) ) == 0, "SJ: ETO_PDY || ETO_GLYPH_INDEX in WMF" );
542 // output only makes sense if the text contains characters
543 if( nLen )
545 nOriginalTextLen = nLen;
546 if( nOptions & ETO_CLIPPED )
548 const Point aPt1( ReadPoint() );
549 const Point aPt2( ReadPoint() );
550 aRect = Rectangle( aPt1, aPt2 );
552 boost::scoped_array<char> pChar(new char[ ( nOriginalTextLen + 1 ) &~ 1 ]);
553 pWMF->Read( pChar.get(), ( nOriginalTextLen + 1 ) &~ 1 );
554 OUString aText( pChar.get(), (sal_uInt16)nOriginalTextLen, pOut->GetCharSet() );// after this conversion the text may contain
555 nNewTextLen = aText.getLength(); // less character (japanese version), so the
556 pChar.reset(); // dxAry will not fit
558 if ( nNewTextLen )
560 sal_uInt32 nMaxStreamPos = nRecordPos + ( nRecordSize << 1 );
561 sal_Int32 nDxArySize = nMaxStreamPos - pWMF->Tell();
562 sal_Int32 nDxAryEntries = nDxArySize >> 1;
563 bool bUseDXAry = false;
565 if ( ( ( nDxAryEntries % nOriginalTextLen ) == 0 ) && ( nNewTextLen <= nOriginalTextLen ) )
567 sal_Int16 nDx = 0, nDxTmp = 0;
568 sal_uInt16 i; //needed just outside the for
569 pDXAry.reset(new long[ nNewTextLen ]);
570 for (i = 0; i < nNewTextLen; i++ )
572 if ( pWMF->Tell() >= nMaxStreamPos )
573 break;
574 pWMF->ReadInt16( nDx );
575 if ( nNewTextLen != nOriginalTextLen )
577 sal_Unicode nUniChar = aText[i];
578 OString aTmp(&nUniChar, 1, pOut->GetCharSet());
579 if ( aTmp.getLength() > 1 )
581 sal_Int32 nDxCount = aTmp.getLength() - 1;
582 if ( ( ( nDxCount * 2 ) + pWMF->Tell() ) > nMaxStreamPos )
583 break;
584 while ( nDxCount-- )
586 pWMF->ReadInt16( nDxTmp );
587 nDx = nDx + nDxTmp;
591 pDXAry[ i ] = nDx;
593 if ( i == nNewTextLen )
594 bUseDXAry = true;
596 if ( pDXAry && bUseDXAry )
597 pOut->DrawText( aPosition, aText, pDXAry.get() );
598 else
599 pOut->DrawText( aPosition, aText );
603 break;
605 case W_META_SELECTOBJECT:
607 sal_Int16 nObjIndex = 0;
608 pWMF->ReadInt16( nObjIndex );
609 pOut->SelectObject( nObjIndex );
611 break;
613 case W_META_SETTEXTALIGN:
615 sal_uInt16 nAlign = 0;
616 pWMF->ReadUInt16( nAlign );
617 pOut->SetTextAlign( nAlign );
619 break;
621 case W_META_BITBLT:
623 // 0-3 : nWinROP #93454#
624 // 4-5 : y offset of source bitmap
625 // 6-7 : x offset of source bitmap
626 // 8-9 : used height of source bitmap
627 // 10-11 : used width of source bitmap
628 // 12-13 : destination position y (in pixel)
629 // 14-15 : destination position x (in pixel)
630 // 16-17 : dont know
631 // 18-19 : Width Bitmap in Pixel
632 // 20-21 : Height Bitmap in Pixel
633 // 22-23 : bytes per scanline
634 // 24 : planes
635 // 25 : bitcount
637 sal_Int32 nWinROP = 0;
638 sal_uInt16 nSx = 0, nSy = 0, nSxe = 0, nSye = 0, nDontKnow = 0, nWidth = 0, nHeight = 0, nBytesPerScan = 0;
639 sal_uInt8 nPlanes, nBitCount;
641 pWMF->ReadInt32( nWinROP )
642 .ReadUInt16( nSy ).ReadUInt16( nSx ).ReadUInt16( nSye ).ReadUInt16( nSxe );
643 Point aPoint( ReadYX() );
644 pWMF->ReadUInt16( nDontKnow ).ReadUInt16( nWidth ).ReadUInt16( nHeight ).ReadUInt16( nBytesPerScan ).ReadUChar( nPlanes ).ReadUChar( nBitCount );
646 if ( nWidth && nHeight && ( nPlanes == 1 ) && ( nBitCount == 1 ) )
648 Bitmap aBmp( Size( nWidth, nHeight ), nBitCount );
649 BitmapWriteAccess* pAcc;
650 pAcc = aBmp.AcquireWriteAccess();
651 if ( pAcc )
653 for (sal_uInt16 y = 0; y < nHeight && pWMF->good(); ++y)
655 sal_uInt16 x = 0;
656 for (sal_uInt16 scan = 0; scan < nBytesPerScan; scan++ )
658 sal_Int8 nEightPixels = 0;
659 pWMF->ReadSChar( nEightPixels );
660 for (sal_Int8 i = 7; i >= 0; i-- )
662 if ( x < nWidth )
664 pAcc->SetPixelIndex( y, x, (nEightPixels>>i)&1 );
666 x++;
670 Bitmap::ReleaseAccess( pAcc );
671 if ( nSye && nSxe &&
672 ( ( nSx + nSxe ) <= aBmp.GetSizePixel().Width() ) &&
673 ( ( nSy + nSye <= aBmp.GetSizePixel().Height() ) ) )
675 Rectangle aCropRect( Point( nSx, nSy ), Size( nSxe, nSye ) );
676 aBmp.Crop( aCropRect );
678 Rectangle aDestRect( aPoint, Size( nSxe, nSye ) );
679 aBmpSaveList.push_back( new BSaveStruct( aBmp, aDestRect, nWinROP, pOut->GetFillStyle () ) );
683 break;
685 case W_META_STRETCHBLT:
686 case W_META_DIBBITBLT:
687 case W_META_DIBSTRETCHBLT:
688 case W_META_STRETCHDIB:
690 sal_Int32 nWinROP = 0;
691 sal_uInt16 nSx = 0, nSy = 0, nSxe = 0, nSye = 0, nUsage = 0;
692 Bitmap aBmp;
694 pWMF->ReadInt32( nWinROP );
696 if( nFunc == W_META_STRETCHDIB )
697 pWMF->ReadUInt16( nUsage );
699 // nSye and nSxe is the number of pixels that has to been used
700 // If they are set to zero, it is as indicator not to scale the bitmap later
702 if( nFunc == W_META_STRETCHDIB || nFunc == W_META_STRETCHBLT || nFunc == W_META_DIBSTRETCHBLT )
703 pWMF->ReadUInt16( nSye ).ReadUInt16( nSxe );
705 // nSy and nx is the offset of the first pixel
706 pWMF->ReadUInt16( nSy ).ReadUInt16( nSx );
708 if( nFunc == W_META_STRETCHDIB || nFunc == W_META_DIBBITBLT || nFunc == W_META_DIBSTRETCHBLT )
710 if ( nWinROP == PATCOPY )
711 pWMF->ReadUInt16( nUsage ); // i don't know anything of this parameter, so its called nUsage
712 // pOut->DrawRect( Rectangle( ReadYX(), aDestSize ), false );
714 Size aDestSize( ReadYXExt() );
715 if ( aDestSize.Width() && aDestSize.Height() ) // #92623# do not try to read buggy bitmaps
717 Rectangle aDestRect( ReadYX(), aDestSize );
718 if ( nWinROP != PATCOPY )
719 ReadDIB(aBmp, *pWMF, false);
721 // test if it is sensible to crop
722 if ( nSye && nSxe &&
723 ( ( nSx + nSxe ) <= aBmp.GetSizePixel().Width() ) &&
724 ( ( nSy + nSye <= aBmp.GetSizePixel().Height() ) ) )
726 Rectangle aCropRect( Point( nSx, nSy ), Size( nSxe, nSye ) );
727 aBmp.Crop( aCropRect );
729 aBmpSaveList.push_back( new BSaveStruct( aBmp, aDestRect, nWinROP, pOut->GetFillStyle () ) );
733 break;
735 case W_META_DIBCREATEPATTERNBRUSH:
737 Bitmap aBmp;
738 BitmapReadAccess* pBmp;
739 sal_uInt32 nRed = 0, nGreen = 0, nBlue = 0, nCount = 1;
740 sal_uInt16 nFunction = 0;
742 pWMF->ReadUInt16( nFunction ).ReadUInt16( nFunction );
744 ReadDIB(aBmp, *pWMF, false);
745 pBmp = aBmp.AcquireReadAccess();
746 if ( pBmp )
748 for ( sal_Int32 y = 0; y < pBmp->Height(); y++ )
750 for ( sal_Int32 x = 0; x < pBmp->Width(); x++ )
752 const BitmapColor aColor( pBmp->GetColor( y, x ) );
754 nRed += aColor.GetRed();
755 nGreen += aColor.GetGreen();
756 nBlue += aColor.GetBlue();
759 nCount = pBmp->Height() * pBmp->Width();
760 if ( !nCount )
761 nCount++;
762 Bitmap::ReleaseAccess( pBmp );
764 Color aColor( (sal_uInt8)( nRed / nCount ), (sal_uInt8)( nGreen / nCount ), (sal_uInt8)( nBlue / nCount ) );
765 pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( aColor, false ) );
767 break;
769 case W_META_DELETEOBJECT:
771 sal_Int16 nIndex = 0;
772 pWMF->ReadInt16( nIndex );
773 pOut->DeleteObject( nIndex );
775 break;
777 case W_META_CREATEPALETTE:
779 pOut->CreateObject( GDI_DUMMY );
781 break;
783 case W_META_CREATEBRUSH:
785 pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ), false ) );
787 break;
789 case W_META_CREATEPATTERNBRUSH:
791 pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ), false ) );
793 break;
795 case W_META_CREATEPENINDIRECT:
797 LineInfo aLineInfo;
798 sal_uInt16 nStyle = 0;
799 sal_uInt16 nWidth = 0;
800 sal_uInt16 nHeight = 0;
802 pWMF->ReadUInt16(nStyle);
803 pWMF->ReadUInt16(nWidth);
804 pWMF->ReadUInt16(nHeight);
806 if (nWidth > 0)
807 aLineInfo.SetWidth(nWidth);
809 bool bTransparent = false;
810 switch( nStyle & 0xFF )
812 case PS_DASHDOTDOT :
813 aLineInfo.SetStyle( LINE_DASH );
814 aLineInfo.SetDashCount( 1 );
815 aLineInfo.SetDotCount( 2 );
816 aLineInfo.SetDashLen( 150 );
817 aLineInfo.SetDotLen( 30 );
818 aLineInfo.SetDistance( 50 );
819 break;
820 case PS_DASHDOT :
821 aLineInfo.SetStyle( LINE_DASH );
822 aLineInfo.SetDashCount( 1 );
823 aLineInfo.SetDotCount( 1 );
824 aLineInfo.SetDashLen( 150 );
825 aLineInfo.SetDotLen( 30 );
826 aLineInfo.SetDistance( 90 );
827 break;
828 case PS_DOT :
829 aLineInfo.SetStyle( LINE_DASH );
830 aLineInfo.SetDashCount( 0 );
831 aLineInfo.SetDotCount( 1 );
832 aLineInfo.SetDotLen( 30 );
833 aLineInfo.SetDistance( 50 );
834 break;
835 case PS_DASH :
836 aLineInfo.SetStyle( LINE_DASH );
837 aLineInfo.SetDashCount( 1 );
838 aLineInfo.SetDotCount( 0 );
839 aLineInfo.SetDashLen( 225 );
840 aLineInfo.SetDistance( 100 );
841 break;
842 case PS_NULL :
843 bTransparent = true;
844 aLineInfo.SetStyle( LINE_NONE );
845 break;
846 default :
847 case PS_INSIDEFRAME :
848 case PS_SOLID :
849 aLineInfo.SetStyle( LINE_SOLID );
851 switch( nStyle & 0xF00 )
853 case PS_ENDCAP_ROUND :
854 aLineInfo.SetLineCap( com::sun::star::drawing::LineCap_ROUND );
855 break;
856 case PS_ENDCAP_SQUARE :
857 aLineInfo.SetLineCap( com::sun::star::drawing::LineCap_SQUARE );
858 break;
859 case PS_ENDCAP_FLAT :
860 default :
861 aLineInfo.SetLineCap( com::sun::star::drawing::LineCap_BUTT );
863 switch( nStyle & 0xF000 )
865 case PS_JOIN_ROUND :
866 aLineInfo.SetLineJoin ( basegfx::B2DLINEJOIN_ROUND );
867 break;
868 case PS_JOIN_MITER :
869 aLineInfo.SetLineJoin ( basegfx::B2DLINEJOIN_MITER );
870 break;
871 case PS_JOIN_BEVEL :
872 aLineInfo.SetLineJoin ( basegfx::B2DLINEJOIN_BEVEL );
873 break;
874 default :
875 aLineInfo.SetLineJoin ( basegfx::B2DLINEJOIN_NONE );
877 pOut->CreateObject( GDI_PEN, new WinMtfLineStyle( ReadColor(), aLineInfo, bTransparent ) );
879 break;
881 case W_META_CREATEBRUSHINDIRECT:
883 sal_uInt16 nStyle = 0;
884 pWMF->ReadUInt16( nStyle );
885 pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( ReadColor(), ( nStyle == BS_HOLLOW ) ) );
887 break;
889 case W_META_CREATEFONTINDIRECT:
891 Size aFontSize;
892 char lfFaceName[LF_FACESIZE];
893 sal_Int16 lfEscapement = 0;
894 sal_Int16 lfOrientation = 0;
895 sal_Int16 lfWeight = 0;
897 LOGFONTW aLogFont;
898 aFontSize = ReadYXExt();
899 pWMF->ReadInt16( lfEscapement );
900 pWMF->ReadInt16( lfOrientation );
901 pWMF->ReadInt16( lfWeight );
902 pWMF->ReadUChar( aLogFont.lfItalic );
903 pWMF->ReadUChar( aLogFont.lfUnderline );
904 pWMF->ReadUChar( aLogFont.lfStrikeOut );
905 pWMF->ReadUChar( aLogFont.lfCharSet );
906 pWMF->ReadUChar( aLogFont.lfOutPrecision );
907 pWMF->ReadUChar( aLogFont.lfClipPrecision );
908 pWMF->ReadUChar( aLogFont.lfQuality );
909 pWMF->ReadUChar( aLogFont.lfPitchAndFamily );
910 pWMF->Read( lfFaceName, LF_FACESIZE );
911 aLogFont.lfWidth = aFontSize.Width();
912 aLogFont.lfHeight = aFontSize.Height();
913 aLogFont.lfEscapement = lfEscapement;
914 aLogFont.lfOrientation = lfOrientation;
915 aLogFont.lfWeight = lfWeight;
917 rtl_TextEncoding eCharSet;
918 if ( ( aLogFont.lfCharSet == OEM_CHARSET ) || ( aLogFont.lfCharSet == DEFAULT_CHARSET ) )
919 eCharSet = osl_getThreadTextEncoding();
920 else
921 eCharSet = rtl_getTextEncodingFromWindowsCharset( aLogFont.lfCharSet );
922 if ( eCharSet == RTL_TEXTENCODING_DONTKNOW )
923 eCharSet = osl_getThreadTextEncoding();
924 if ( eCharSet == RTL_TEXTENCODING_SYMBOL )
925 eCharSet = RTL_TEXTENCODING_MS_1252;
926 aLogFont.alfFaceName = OUString( lfFaceName, strlen(lfFaceName), eCharSet );
928 pOut->CreateObject( GDI_FONT, new WinMtfFontStyle( aLogFont ) );
930 break;
932 case W_META_CREATEBITMAPINDIRECT:
934 pOut->CreateObject( GDI_DUMMY );
936 break;
938 case W_META_CREATEBITMAP:
940 pOut->CreateObject( GDI_DUMMY );
942 break;
944 case W_META_CREATEREGION:
946 pOut->CreateObject( GDI_DUMMY );
948 break;
950 case W_META_EXCLUDECLIPRECT :
952 pOut->ExcludeClipRect( ReadRectangle() );
954 break;
956 case W_META_PATBLT:
958 sal_uInt32 nROP = 0, nOldROP = 0;
959 pWMF->ReadUInt32( nROP );
960 Size aSize = ReadYXExt();
961 nOldROP = pOut->SetRasterOp( nROP );
962 pOut->DrawRect( Rectangle( ReadYX(), aSize ), false );
963 pOut->SetRasterOp( nOldROP );
965 break;
967 case W_META_SELECTCLIPREGION:
969 sal_Int16 nObjIndex = 0;
970 pWMF->ReadInt16( nObjIndex );
971 if ( !nObjIndex )
973 tools::PolyPolygon aEmptyPolyPoly;
974 pOut->SetClipPath( aEmptyPolyPoly, RGN_COPY, true );
977 break;
979 case W_META_ESCAPE :
981 // nRecSize has been checked previously to be greater than 3
982 sal_uInt64 nMetaRecSize = static_cast< sal_uInt64 >( nRecSize - 2 ) * 2;
983 sal_uInt64 nMetaRecEndPos = pWMF->Tell() + nMetaRecSize;
985 // taking care that nRecSize does not exceed the maximal stream position
986 if ( nMetaRecEndPos > nEndPos )
988 pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
989 break;
991 if ( nRecSize >= 4 ) // minimal escape length
993 sal_uInt16 nMode = 0, nLen = 0;
994 pWMF->ReadUInt16( nMode )
995 .ReadUInt16( nLen );
996 if ( ( nMode == W_MFCOMMENT ) && ( nLen >= 4 ) )
998 sal_uInt32 nNewMagic = 0; // we have to read int32 for
999 pWMF->ReadUInt32( nNewMagic ); // META_ESCAPE_ENHANCED_METAFILE CommentIdentifier
1001 if( nNewMagic == 0x2c2a4f4f && nLen >= 14 )
1003 sal_uInt16 nMagic2 = 0;
1004 pWMF->ReadUInt16( nMagic2 );
1005 if( nMagic2 == 0x0a ) // 2nd half of magic
1006 { // continue with private escape
1007 sal_uInt32 nCheck = 0, nEsc = 0;
1008 pWMF->ReadUInt32( nCheck )
1009 .ReadUInt32( nEsc );
1011 sal_uInt32 nEscLen = nLen - 14;
1012 if ( nEscLen <= ( nRecSize * 2 ) )
1014 #ifdef OSL_BIGENDIAN
1015 sal_uInt32 nTmp = OSL_SWAPDWORD( nEsc );
1016 sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 );
1017 #else
1018 sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 );
1019 #endif
1020 boost::scoped_array<sal_Int8> pData;
1022 if ( ( static_cast< sal_uInt64 >( nEscLen ) + pWMF->Tell() ) > nMetaRecEndPos )
1024 pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
1025 break;
1027 if ( nEscLen > 0 )
1029 pData.reset(new sal_Int8[ nEscLen ]);
1030 pWMF->Read( pData.get(), nEscLen );
1031 nCheckSum = rtl_crc32( nCheckSum, pData.get(), nEscLen );
1033 if ( nCheck == nCheckSum )
1035 switch( nEsc )
1037 case PRIVATE_ESCAPE_UNICODE :
1039 // we will use text instead of polygons only if we have the correct font
1040 if ( Application::GetDefaultDevice()->IsFontAvailable( pOut->GetFont().GetName() ) )
1042 Point aPt;
1043 OUString aString;
1044 sal_uInt32 nStringLen, nDXCount;
1045 boost::scoped_array<long> pDXAry;
1046 SvMemoryStream aMemoryStream( nEscLen );
1047 aMemoryStream.Write( pData.get(), nEscLen );
1048 aMemoryStream.Seek( STREAM_SEEK_TO_BEGIN );
1049 sal_Int32 nTmpX(0), nTmpY(0);
1050 aMemoryStream.ReadInt32( nTmpX )
1051 .ReadInt32( nTmpY )
1052 .ReadUInt32( nStringLen );
1053 aPt.X() = nTmpX;
1054 aPt.Y() = nTmpY;
1056 if ( ( static_cast< sal_uInt64 >( nStringLen ) * sizeof( sal_Unicode ) ) < ( nEscLen - aMemoryStream.Tell() ) )
1059 aString = read_uInt16s_ToOUString(aMemoryStream, nStringLen);
1060 aMemoryStream.ReadUInt32( nDXCount );
1061 if ( ( static_cast< sal_uInt64 >( nDXCount ) * sizeof( sal_Int32 ) ) >= ( nEscLen - aMemoryStream.Tell() ) )
1062 nDXCount = 0;
1063 if ( nDXCount )
1064 pDXAry.reset(new long[ nDXCount ]);
1065 for (sal_uInt32 i = 0; i < nDXCount; i++ )
1067 sal_Int32 val;
1068 aMemoryStream.ReadInt32( val);
1069 pDXAry[ i ] = val;
1071 aMemoryStream.ReadUInt32( nSkipActions );
1072 pOut->DrawText( aPt, aString, pDXAry.get() );
1076 break;
1082 else if ( (nNewMagic == static_cast< sal_uInt32 >(0x43464D57)) && (nLen >= 34) && ( (sal_Int32)(nLen + 10) <= (sal_Int32)(nRecSize * 2) ))
1084 sal_uInt32 nComType = 0, nVersion = 0, nFlags = 0, nComRecCount = 0,
1085 nCurRecSize = 0, nRemainingSize = 0, nEMFTotalSize = 0;
1086 sal_uInt16 nCheck = 0;
1088 pWMF->ReadUInt32( nComType ).ReadUInt32( nVersion ).ReadUInt16( nCheck ).ReadUInt32( nFlags )
1089 .ReadUInt32( nComRecCount ).ReadUInt32( nCurRecSize )
1090 .ReadUInt32( nRemainingSize ).ReadUInt32( nEMFTotalSize ); // the nRemainingSize is not mentioned in MSDN documentation
1091 // but it seems to be required to read in data produced by OLE
1093 if( nComType == 0x01 && nVersion == 0x10000 && nComRecCount )
1095 if( !nEMFRec )
1096 { // first EMF comment
1097 nEMFRecCount = nComRecCount;
1098 nEMFSize = nEMFTotalSize;
1099 pEMFStream = new SvMemoryStream( nEMFSize );
1101 else if( ( nEMFRecCount != nComRecCount ) || ( nEMFSize != nEMFTotalSize ) ) // add additional checks here
1103 // total records should be the same as in previous comments
1104 nEMFRecCount = 0xFFFFFFFF;
1105 delete pEMFStream;
1106 pEMFStream = NULL;
1108 nEMFRec++;
1110 if( pEMFStream && nCurRecSize + 34 > nLen )
1112 nEMFRecCount = 0xFFFFFFFF;
1113 delete pEMFStream;
1114 pEMFStream = NULL;
1117 if( pEMFStream )
1119 boost::scoped_array<sal_Int8> pBuf(new sal_Int8[ nCurRecSize ]);
1120 sal_uInt32 nCount = pWMF->Read( pBuf.get(), nCurRecSize );
1121 if( nCount == nCurRecSize )
1122 pEMFStream->Write( pBuf.get(), nCount );
1129 break;
1131 case W_META_SETRELABS:
1132 case W_META_SETPOLYFILLMODE:
1133 case W_META_SETSTRETCHBLTMODE:
1134 case W_META_SETTEXTCHAREXTRA:
1135 case W_META_SETTEXTJUSTIFICATION:
1136 case W_META_FLOODFILL :
1137 case W_META_FILLREGION:
1138 case W_META_FRAMEREGION:
1139 case W_META_INVERTREGION:
1140 case W_META_PAINTREGION:
1141 case W_META_DRAWTEXT:
1142 case W_META_SETMAPPERFLAGS:
1143 case W_META_SETDIBTODEV:
1144 case W_META_SELECTPALETTE:
1145 case W_META_REALIZEPALETTE:
1146 case W_META_ANIMATEPALETTE:
1147 case W_META_SETPALENTRIES:
1148 case W_META_RESIZEPALETTE:
1149 case W_META_EXTFLOODFILL:
1150 case W_META_RESETDC:
1151 case W_META_STARTDOC:
1152 case W_META_STARTPAGE:
1153 case W_META_ENDPAGE:
1154 case W_META_ABORTDOC:
1155 case W_META_ENDDOC:
1156 break;
1160 static const long aMaxWidth = 1024;
1162 bool WMFReader::ReadHeader()
1164 sal_Size nStrmPos = pWMF->Tell();
1166 sal_uInt32 nPlaceableMetaKey(0);
1167 // if available read the METAFILEHEADER
1168 pWMF->ReadUInt32( nPlaceableMetaKey );
1169 if (!pWMF->good())
1170 return false;
1172 Rectangle aPlaceableBound;
1174 bool bPlaceable = nPlaceableMetaKey == 0x9ac6cdd7L;
1176 SAL_INFO("vcl.wmf", "Placeable: \"" << (bPlaceable ? "yes" : "no") << "\"");
1178 if (bPlaceable)
1180 //TODO do some real error handling here
1181 sal_Int16 nVal;
1183 // Skip reserved bytes
1184 pWMF->SeekRel(2);
1186 // BoundRect
1187 pWMF->ReadInt16( nVal );
1188 aPlaceableBound.Left() = nVal;
1189 pWMF->ReadInt16( nVal );
1190 aPlaceableBound.Top() = nVal;
1191 pWMF->ReadInt16( nVal );
1192 aPlaceableBound.Right() = nVal;
1193 pWMF->ReadInt16( nVal );
1194 aPlaceableBound.Bottom() = nVal;
1196 // inch
1197 pWMF->ReadUInt16( nUnitsPerInch );
1199 // reserved
1200 pWMF->SeekRel( 4 );
1202 // Skip and don't check the checksum
1203 pWMF->SeekRel( 2 );
1205 else
1207 nUnitsPerInch = 96;
1210 if ( pExternalHeader != NULL
1211 && pExternalHeader->xExt > 0
1212 && pExternalHeader->yExt > 0
1213 && (pExternalHeader->mapMode == MM_ISOTROPIC || pExternalHeader->mapMode == MM_ANISOTROPIC))
1215 // #n417818#: If we have an external header then overwrite the bounds!
1216 Rectangle aExtRect(0, 0,
1217 (double) pExternalHeader->xExt * 567 * nUnitsPerInch / 1440000,
1218 (double) pExternalHeader->yExt * 567 * nUnitsPerInch / 1440000);
1219 aPlaceableBound = aExtRect;
1221 SAL_INFO("vcl.wmf", "External header size "
1222 " t: " << aPlaceableBound.Left() << " l: " << aPlaceableBound.Top()
1223 << " b: " << aPlaceableBound.Right() << " r: " << aPlaceableBound.Bottom());
1225 pOut->SetMapMode( pExternalHeader->mapMode );
1227 else
1229 pWMF->Seek( nStrmPos + 18 ); // set the streampos to the start of the metaactions
1230 GetPlaceableBound( aPlaceableBound, pWMF );
1232 // The image size is not known so normalize the calculated bounds so that the
1233 // resulting image is not too big
1234 const double fMaxWidth = static_cast<double>(aMaxWidth);
1235 if (aPlaceableBound.GetWidth() > aMaxWidth)
1237 double fRatio = aPlaceableBound.GetWidth() / fMaxWidth;
1239 aPlaceableBound = Rectangle(
1240 aPlaceableBound.Left() / fRatio,
1241 aPlaceableBound.Top() / fRatio,
1242 aPlaceableBound.Right() / fRatio,
1243 aPlaceableBound.Bottom() / fRatio);
1245 SAL_INFO("vcl.wmf", "Placeable bounds "
1246 " t: " << aPlaceableBound.Left() << " l: " << aPlaceableBound.Top()
1247 << " b: " << aPlaceableBound.Right() << " r: " << aPlaceableBound.Bottom());
1251 pWMF->Seek( nStrmPos );
1254 pOut->SetWinOrg( aPlaceableBound.TopLeft() );
1255 Size aWMFSize( labs( aPlaceableBound.GetWidth() ), labs( aPlaceableBound.GetHeight() ) );
1256 pOut->SetWinExt( aWMFSize );
1258 SAL_INFO("vcl.wmf", "WMF size w: " << aWMFSize.Width() << " h: " << aWMFSize.Height());
1260 Size aDevExt( 10000, 10000 );
1261 if( ( labs( aWMFSize.Width() ) > 1 ) && ( labs( aWMFSize.Height() ) > 1 ) )
1263 const Fraction aFrac( 1, nUnitsPerInch );
1264 MapMode aWMFMap( MAP_INCH, Point(), aFrac, aFrac );
1265 Size aSize100( OutputDevice::LogicToLogic( aWMFSize, aWMFMap, MAP_100TH_MM ) );
1266 aDevExt = Size( labs( aSize100.Width() ), labs( aSize100.Height() ) );
1268 pOut->SetDevExt( aDevExt );
1270 SAL_INFO("vcl.wmf", "Dev size w: " << aDevExt.Width() << " h: " << aDevExt.Height());
1272 // read the METAHEADER
1273 sal_uInt32 nMetaKey(0);
1274 pWMF->ReadUInt32( nMetaKey ); // type and headersize
1275 if (!pWMF->good())
1276 return false;
1277 if (nMetaKey != 0x00090001)
1279 sal_uInt16 aNextWord(0);
1280 pWMF->ReadUInt16( aNextWord );
1281 if (nMetaKey != 0x10000 || aNextWord != 0x09)
1283 pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
1284 return false;
1288 pWMF->SeekRel( 2 ); // Version (of Windows)
1289 pWMF->SeekRel( 4 ); // Size (of file in words)
1290 pWMF->SeekRel( 2 ); // NoObjects (maximum number of simultaneous objects)
1291 pWMF->SeekRel( 4 ); // MaxRecord (size of largets record in words)
1292 pWMF->SeekRel( 2 ); // NoParameters (Unused
1294 return pWMF->good();
1297 void WMFReader::ReadWMF()
1299 sal_uInt16 nFunction;
1300 sal_uLong nPos, nPercent, nLastPercent;
1302 nSkipActions = 0;
1303 nCurrentAction = 0;
1304 nUnicodeEscapeAction = 0;
1306 pEMFStream = NULL;
1307 nEMFRecCount = 0;
1308 nEMFRec = 0;
1309 nEMFSize = 0;
1311 pOut->SetMapMode( MM_ANISOTROPIC );
1312 pOut->SetWinOrg( Point() );
1313 pOut->SetWinExt( Size( 1, 1 ) );
1314 pOut->SetDevExt( Size( 10000, 10000 ) );
1316 nEndPos=pWMF->Seek( STREAM_SEEK_TO_END );
1317 pWMF->Seek( nStartPos );
1318 Callback( (sal_uInt16) ( nLastPercent = 0 ) );
1320 if ( ReadHeader( ) )
1322 bool bEMFAvailable = false;
1324 nPos = pWMF->Tell();
1326 if( nEndPos - nStartPos )
1328 while( true )
1330 nCurrentAction++;
1331 nPercent = ( nPos - nStartPos ) * 100 / ( nEndPos - nStartPos );
1333 if( nLastPercent + 4 <= nPercent )
1335 Callback( (sal_uInt16) nPercent );
1336 nLastPercent = nPercent;
1338 pWMF->ReadUInt32( nRecSize ).ReadUInt16( nFunction );
1340 if( pWMF->GetError()
1341 || ( nRecSize < 3 )
1342 || ( nRecSize == 3
1343 && nFunction == 0
1345 || pWMF->IsEof()
1348 if( pWMF->IsEof() )
1349 pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
1351 break;
1353 if ( !bEMFAvailable )
1355 if( !aBmpSaveList.empty()
1356 && ( nFunction != W_META_STRETCHDIB )
1357 && ( nFunction != W_META_DIBBITBLT )
1358 && ( nFunction != W_META_DIBSTRETCHBLT )
1361 pOut->ResolveBitmapActions( aBmpSaveList );
1364 if ( !nSkipActions )
1365 ReadRecordParams( nFunction );
1366 else
1367 nSkipActions--;
1369 if( pEMFStream && nEMFRecCount == nEMFRec )
1371 GDIMetaFile aMeta;
1372 pEMFStream->Seek( 0 );
1373 EnhWMFReader* pEMFReader = new EnhWMFReader ( *pEMFStream, aMeta );
1374 bEMFAvailable = pEMFReader->ReadEnhWMF();
1375 delete pEMFReader; // destroy first!!!
1377 if( bEMFAvailable )
1379 pOut->AddFromGDIMetaFile( aMeta );
1380 pOut->SetrclFrame( Rectangle( Point(0, 0), aMeta.GetPrefSize()));
1382 // the stream needs to be set to the wmf end position,
1383 // otherwise the GfxLink that is created will be incorrect
1384 // (leading to graphic loss after swapout/swapin).
1385 // so we will proceed normally, but are ignoring further wmf
1386 // records
1388 else
1390 // something went wrong
1391 // continue with WMF, don't try this again
1392 delete pEMFStream;
1393 pEMFStream = NULL;
1397 const sal_uInt32 nAvailableBytes = nEndPos - nPos;
1398 const sal_uInt32 nMaxPossibleRecordSize = nAvailableBytes/2;
1399 if (nRecSize <= nMaxPossibleRecordSize)
1401 nPos += nRecSize * 2;
1402 pWMF->Seek(nPos);
1404 else
1405 pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
1408 else
1409 pWMF->SetError( SVSTREAM_GENERALERROR );
1411 if( !pWMF->GetError() && !aBmpSaveList.empty() )
1412 pOut->ResolveBitmapActions( aBmpSaveList );
1414 if ( pWMF->GetError() )
1415 pWMF->Seek( nStartPos );
1418 bool WMFReader::GetPlaceableBound( Rectangle& rPlaceableBound, SvStream* pStm )
1420 bool bRet = true;
1422 Rectangle aBound;
1423 aBound.Left() = RECT_MAX;
1424 aBound.Top() = RECT_MAX;
1425 aBound.Right() = RECT_MIN;
1426 aBound.Bottom() = RECT_MIN;
1427 bool bBoundsDetermined = false;
1429 sal_uInt32 nPos = pStm->Tell();
1430 sal_uInt32 nEnd = pStm->Seek( STREAM_SEEK_TO_END );
1432 pStm->Seek( nPos );
1434 Point aWinOrg(0,0);
1435 boost::optional<Size> aWinExt;
1437 Point aViewportOrg(0,0);
1438 boost::optional<Size> aViewportExt;
1440 if( nEnd - nPos )
1442 sal_Int16 nMapMode = MM_ANISOTROPIC;
1443 sal_uInt16 nFunction;
1444 sal_uInt32 nRSize;
1446 while( bRet )
1448 pStm->ReadUInt32( nRSize ).ReadUInt16( nFunction );
1450 if( pStm->GetError() )
1452 bRet = false;
1453 break;
1455 else if ( nRSize==3 && nFunction==0 )
1457 break;
1459 else if ( nRSize < 3 || pStm->IsEof() )
1461 pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1462 bRet = false;
1463 break;
1465 switch( nFunction )
1467 case W_META_SETWINDOWORG:
1469 aWinOrg = ReadYX();
1471 break;
1473 case W_META_SETWINDOWEXT:
1475 sal_Int16 nWidth(0), nHeight(0);
1476 pStm->ReadInt16(nHeight);
1477 pStm->ReadInt16(nWidth);
1478 aWinExt = Size(nWidth, nHeight);
1480 break;
1482 case W_META_SETVIEWPORTORG:
1484 aViewportOrg = ReadYX();
1486 break;
1488 case W_META_SETVIEWPORTEXT:
1490 sal_Int16 nWidth(0), nHeight(0);
1491 pStm->ReadInt16(nHeight);
1492 pStm->ReadInt16(nWidth);
1493 aViewportExt = Size(nWidth, nHeight);
1495 break;
1497 case W_META_SETMAPMODE :
1498 pStm->ReadInt16( nMapMode );
1499 break;
1501 case W_META_MOVETO:
1502 case W_META_LINETO:
1503 GetWinExtMax( ReadYX(), aBound, nMapMode );
1504 bBoundsDetermined = true;
1505 break;
1507 case W_META_RECTANGLE:
1508 case W_META_INTERSECTCLIPRECT:
1509 case W_META_EXCLUDECLIPRECT :
1510 case W_META_ELLIPSE:
1511 GetWinExtMax( ReadRectangle(), aBound, nMapMode );
1512 bBoundsDetermined = true;
1513 break;
1515 case W_META_ROUNDRECT:
1516 ReadYXExt(); // size
1517 GetWinExtMax( ReadRectangle(), aBound, nMapMode );
1518 bBoundsDetermined = true;
1519 break;
1521 case W_META_ARC:
1522 case W_META_PIE:
1523 case W_META_CHORD:
1524 ReadYX(); // end
1525 ReadYX(); // start
1526 GetWinExtMax( ReadRectangle(), aBound, nMapMode );
1527 bBoundsDetermined = true;
1528 break;
1530 case W_META_POLYGON:
1532 bool bRecordOk = true;
1534 sal_uInt16 nPoints(0);
1535 pStm->ReadUInt16( nPoints );
1537 if (nPoints > pStm->remainingSize() / (2 * sizeof(sal_uInt16)))
1539 bRecordOk = false;
1541 else
1543 for(sal_uInt16 i = 0; i < nPoints; i++ )
1545 GetWinExtMax( ReadPoint(), aBound, nMapMode );
1546 bBoundsDetermined = true;
1550 SAL_WARN_IF(!bRecordOk, "vcl.wmf", "polyline record claimed more points than the stream can provide");
1552 if (!bRecordOk)
1554 pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1555 bRet = false;
1556 break;
1559 break;
1561 case W_META_POLYPOLYGON:
1563 bool bRecordOk = true;
1564 sal_uInt16 nPoly(0), nPoints(0);
1565 pStm->ReadUInt16(nPoly);
1566 if (nPoly > pStm->remainingSize() / sizeof(sal_uInt16))
1568 bRecordOk = false;
1570 else
1572 for(sal_uInt16 i = 0; i < nPoly; i++ )
1574 sal_uInt16 nP = 0;
1575 pStm->ReadUInt16( nP );
1576 if (nP > SAL_MAX_UINT16 - nPoints)
1578 bRecordOk = false;
1579 break;
1581 nPoints += nP;
1585 SAL_WARN_IF(!bRecordOk, "vcl.wmf", "polypolygon record has more polygons than we can handle");
1587 bRecordOk = bRecordOk && pStm->good();
1589 if (!bRecordOk)
1591 pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1592 bRet = false;
1593 break;
1596 if (nPoints > pStm->remainingSize() / (2 * sizeof(sal_uInt16)))
1598 bRecordOk = false;
1600 else
1602 for (sal_uInt16 i = 0; i < nPoints; i++ )
1604 GetWinExtMax( ReadPoint(), aBound, nMapMode );
1605 bBoundsDetermined = true;
1609 SAL_WARN_IF(!bRecordOk, "vcl.wmf", "polypolygon record claimed more points than the stream can provide");
1611 bRecordOk &= pStm->good();
1613 if (!bRecordOk)
1615 pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1616 bRet = false;
1617 break;
1620 break;
1622 case W_META_POLYLINE:
1624 bool bRecordOk = true;
1626 sal_uInt16 nPoints(0);
1627 pStm->ReadUInt16(nPoints);
1628 if (nPoints > pStm->remainingSize() / (2 * sizeof(sal_uInt16)))
1630 bRecordOk = false;
1632 else
1634 for (sal_uInt16 i = 0; i < nPoints; ++i)
1636 GetWinExtMax( ReadPoint(), aBound, nMapMode );
1637 bBoundsDetermined = true;
1641 SAL_WARN_IF(!bRecordOk, "vcl.wmf", "polyline record claimed more points than the stream can provide");
1643 if (!bRecordOk)
1645 pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1646 bRet = false;
1647 break;
1650 break;
1652 case W_META_SETPIXEL:
1654 ReadColor();
1655 GetWinExtMax( ReadYX(), aBound, nMapMode );
1656 bBoundsDetermined = true;
1658 break;
1660 case W_META_TEXTOUT:
1662 sal_uInt16 nLength;
1663 pStm->ReadUInt16( nLength );
1664 // todo: we also have to take care of the text width
1665 if ( nLength )
1667 pStm->SeekRel( ( nLength + 1 ) &~ 1 );
1668 GetWinExtMax( ReadYX(), aBound, nMapMode );
1669 bBoundsDetermined = true;
1672 break;
1674 case W_META_EXTTEXTOUT:
1676 sal_uInt16 nLen, nOptions;
1677 Point aPosition;
1679 aPosition = ReadYX();
1680 pStm->ReadUInt16( nLen ).ReadUInt16( nOptions );
1681 // todo: we also have to take care of the text width
1682 if( nLen )
1684 GetWinExtMax( aPosition, aBound, nMapMode );
1685 bBoundsDetermined = true;
1688 break;
1689 case W_META_BITBLT:
1690 case W_META_STRETCHBLT:
1691 case W_META_DIBBITBLT:
1692 case W_META_DIBSTRETCHBLT:
1693 case W_META_STRETCHDIB:
1695 sal_Int32 nWinROP;
1696 sal_uInt16 nSx, nSy, nSxe, nSye, nUsage;
1697 pStm->ReadInt32( nWinROP );
1699 if( nFunction == W_META_STRETCHDIB )
1700 pStm->ReadUInt16( nUsage );
1702 // nSye and nSxe is the number of pixels that has to been used
1703 if( nFunction == W_META_STRETCHDIB || nFunction == W_META_STRETCHBLT || nFunction == W_META_DIBSTRETCHBLT )
1704 pStm->ReadUInt16( nSye ).ReadUInt16( nSxe );
1705 else
1706 nSye = nSxe = 0; // set this to zero as indicator not to scale the bitmap later
1708 // nSy and nx is the offset of the first pixel
1709 pStm->ReadUInt16( nSy ).ReadUInt16( nSx );
1711 if( nFunction == W_META_STRETCHDIB || nFunction == W_META_DIBBITBLT || nFunction == W_META_DIBSTRETCHBLT )
1713 if ( nWinROP == PATCOPY )
1714 pStm->ReadUInt16( nUsage ); // i don't know anything of this parameter, so its called nUsage
1715 // pOut->DrawRect( Rectangle( ReadYX(), aDestSize ), false );
1717 Size aDestSize( ReadYXExt() );
1718 if ( aDestSize.Width() && aDestSize.Height() ) // #92623# do not try to read buggy bitmaps
1720 Rectangle aDestRect( ReadYX(), aDestSize );
1721 GetWinExtMax( aDestRect, aBound, nMapMode );
1722 bBoundsDetermined = true;
1726 break;
1728 case W_META_PATBLT:
1730 sal_uInt32 nROP;
1731 pStm->ReadUInt32( nROP );
1732 Size aSize = ReadYXExt();
1733 GetWinExtMax( Rectangle( ReadYX(), aSize ), aBound, nMapMode );
1734 bBoundsDetermined = true;
1736 break;
1739 const sal_uInt32 nAvailableBytes = nEnd - nPos;
1740 const sal_uInt32 nMaxPossibleRecordSize = nAvailableBytes/2;
1741 if (nRSize <= nMaxPossibleRecordSize)
1743 nPos += nRSize * 2;
1744 pStm->Seek( nPos );
1746 else
1748 pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1749 bRet = false;
1753 else
1755 pStm->SetError( SVSTREAM_GENERALERROR );
1756 bRet = false;
1759 if (bRet)
1761 if (aWinExt)
1763 rPlaceableBound = Rectangle(aWinOrg, *aWinExt);
1764 SAL_INFO("vcl.wmf", "Window dimension "
1765 " t: " << rPlaceableBound.Left() << " l: " << rPlaceableBound.Top()
1766 << " b: " << rPlaceableBound.Right() << " r: " << rPlaceableBound.Bottom());
1768 else if (aViewportExt)
1770 rPlaceableBound = Rectangle(aViewportOrg, *aViewportExt);
1771 SAL_INFO("vcl.wmf", "Viewport dimension "
1772 " t: " << rPlaceableBound.Left() << " l: " << rPlaceableBound.Top()
1773 << " b: " << rPlaceableBound.Right() << " r: " << rPlaceableBound.Bottom());
1775 else if (bBoundsDetermined)
1777 rPlaceableBound = aBound;
1778 SAL_INFO("vcl.wmf", "Determined dimension "
1779 " t: " << rPlaceableBound.Left() << " l: " << rPlaceableBound.Top()
1780 << " b: " << rPlaceableBound.Right() << " r: " << rPlaceableBound.Bottom());
1782 else
1784 rPlaceableBound.Left() = 0;
1785 rPlaceableBound.Top() = 0;
1786 rPlaceableBound.Right() = aMaxWidth;
1787 rPlaceableBound.Bottom() = aMaxWidth;
1788 SAL_INFO("vcl.wmf", "Default dimension "
1789 " t: " << rPlaceableBound.Left() << " l: " << rPlaceableBound.Top()
1790 << " b: " << rPlaceableBound.Right() << " r: " << rPlaceableBound.Bottom());
1794 return bRet;
1797 WMFReader::WMFReader(SvStream& rStreamWMF, GDIMetaFile& rGDIMetaFile,
1798 FilterConfigItem* pConfigItem, WMF_EXTERNALHEADER* pExtHeader)
1799 : WinMtf(new WinMtfOutput(rGDIMetaFile) , rStreamWMF, pConfigItem)
1800 , nUnitsPerInch(96)
1801 , nRecSize(0)
1802 , pEMFStream(NULL)
1803 , nEMFRecCount(0)
1804 , nEMFRec(0)
1805 , nEMFSize(0)
1806 , nSkipActions(0)
1807 , nCurrentAction(0)
1808 , nUnicodeEscapeAction(0)
1809 , pExternalHeader(pExtHeader)
1812 WMFReader::~WMFReader()
1814 delete pEMFStream;
1817 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */