1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
22 #include <boost/scoped_array.hpp>
23 #include <boost/optional.hpp>
24 #include <vcl/gdimtf.hxx>
25 #include <vcl/wmf.hxx>
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>
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()
156 return Rectangle( aTL
, aBR
);
159 Size
WMFReader::ReadYXExt()
162 pWMF
->ReadInt16( nH
).ReadInt16( nW
);
163 return Size( nW
, nH
);
166 void WMFReader::ReadRecordParams( sal_uInt16 nFunc
)
170 case W_META_SETBKCOLOR
:
172 pOut
->SetBkColor( ReadColor() );
176 case W_META_SETBKMODE
:
179 pWMF
->ReadUInt16( nDat
);
180 pOut
->SetBkMode( static_cast<BkMode
>(nDat
) );
185 case W_META_SETMAPMODE
:
187 sal_Int16 nMapMode
= 0;
188 pWMF
->ReadInt16( nMapMode
);
189 pOut
->SetMapMode( nMapMode
);
195 sal_uInt16 nROP2
= 0;
196 pWMF
->ReadUInt16( nROP2
);
197 pOut
->SetRasterOp( nROP2
);
201 case W_META_SETTEXTCOLOR
:
203 pOut
->SetTextColor( ReadColor() );
207 case W_META_SETWINDOWORG
:
209 pOut
->SetWinOrg( ReadYX() );
213 case W_META_SETWINDOWEXT
:
215 short nWidth
= 0, nHeight
= 0;
216 pWMF
->ReadInt16( nHeight
).ReadInt16( nWidth
);
217 pOut
->SetWinExt( Size( nWidth
, nHeight
) );
221 case W_META_OFFSETWINDOWORG
:
223 short nXAdd
= 0, nYAdd
= 0;
224 pWMF
->ReadInt16( nYAdd
).ReadInt16( nXAdd
);
225 pOut
->SetWinOrgOffset( nXAdd
, nYAdd
);
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
);
238 pOut
->ScaleWinExt( (double)nXNum
/ nXDenom
, (double)nYNum
/ nYDenom
);
242 case W_META_SETVIEWPORTORG
:
243 case W_META_SETVIEWPORTEXT
:
246 case W_META_OFFSETVIEWPORTORG
:
248 short nXAdd
= 0, nYAdd
= 0;
249 pWMF
->ReadInt16( nYAdd
).ReadInt16( nXAdd
);
250 pOut
->SetDevOrgOffset( nXAdd
, nYAdd
);
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
);
263 pOut
->ScaleDevExt( (double)nXNum
/ nXDenom
, (double)nYNum
/ nYDenom
);
269 pOut
->LineTo( ReadYX() );
275 pOut
->MoveTo( ReadYX() );
279 case W_META_INTERSECTCLIPRECT
:
281 pOut
->IntersectClipRect( ReadRectangle() );
285 case W_META_RECTANGLE
:
287 pOut
->DrawRect( ReadRectangle() );
291 case W_META_ROUNDRECT
:
293 Size
aSize( ReadYXExt() );
294 pOut
->DrawRoundRect( ReadRectangle(), Size( aSize
.Width() / 2, aSize
.Height() / 2 ) );
300 pOut
->DrawEllipse( ReadRectangle() );
306 Point
aEnd( ReadYX() );
307 Point
aStart( ReadYX() );
308 Rectangle
aRect( ReadRectangle() );
310 pOut
->DrawArc( aRect
, aStart
, aEnd
);
316 Point
aEnd( ReadYX() );
317 Point
aStart( ReadYX() );
318 Rectangle
aRect( ReadRectangle() );
321 // #i73608# OutputDevice deviates from WMF
322 // semantics. start==end means full ellipse here.
324 pOut
->DrawEllipse( aRect
);
326 pOut
->DrawPie( aRect
, aStart
, aEnd
);
332 Point
aEnd( ReadYX() );
333 Point
aStart( ReadYX() );
334 Rectangle
aRect( ReadRectangle() );
336 pOut
->DrawChord( aRect
, aStart
, aEnd
);
342 bool bRecordOk
= true;
344 sal_uInt16
nPoints(0);
345 pWMF
->ReadUInt16(nPoints
);
347 if (nPoints
> pWMF
->remainingSize() / (2 * sizeof(sal_uInt16
)))
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();
365 pWMF
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
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
))
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
)
400 nPoints
+= pnPoints
[a
];
403 SAL_WARN_IF(!bRecordOk
, "vcl.filter", "polypolygon record has more polygons than we can handle");
405 bRecordOk
&= pWMF
->good();
409 pWMF
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
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
)))
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();
439 pWMF
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
443 pOut
->DrawPolyPolygon( aPolyPoly
);
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
)))
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();
473 pWMF
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
485 case W_META_RESTOREDC
:
491 case W_META_SETPIXEL
:
493 const Color aColor
= ReadColor();
494 pOut
->DrawPixel( ReadYX(), aColor
);
498 case W_META_OFFSETCLIPRGN
:
500 pOut
->MoveClipRegion( ReadYXExt() );
506 sal_uInt16 nLength
= 0;
507 pWMF
->ReadUInt16( 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() );
514 Point
aPosition( ReadYX() );
515 pOut
->DrawText( aPosition
, aText
);
520 case W_META_EXTTEXTOUT
:
522 sal_uInt16 nLen
= 0, nOptions
= 0;
523 sal_Int32 nRecordPos
, nRecordSize
= 0, nOriginalTextLen
, nNewTextLen
;
526 boost::scoped_array
<long> pDXAry
;
529 nRecordPos
= pWMF
->Tell();
530 pWMF
->ReadInt32( nRecordSize
);
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
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
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
)
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
)
586 pWMF
->ReadInt16( nDxTmp
);
593 if ( i
== nNewTextLen
)
596 if ( pDXAry
&& bUseDXAry
)
597 pOut
->DrawText( aPosition
, aText
, pDXAry
.get() );
599 pOut
->DrawText( aPosition
, aText
);
605 case W_META_SELECTOBJECT
:
607 sal_Int16 nObjIndex
= 0;
608 pWMF
->ReadInt16( nObjIndex
);
609 pOut
->SelectObject( nObjIndex
);
613 case W_META_SETTEXTALIGN
:
615 sal_uInt16 nAlign
= 0;
616 pWMF
->ReadUInt16( nAlign
);
617 pOut
->SetTextAlign( nAlign
);
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)
631 // 18-19 : Width Bitmap in Pixel
632 // 20-21 : Height Bitmap in Pixel
633 // 22-23 : bytes per scanline
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();
653 for (sal_uInt16 y
= 0; y
< nHeight
&& pWMF
->good(); ++y
)
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
-- )
664 pAcc
->SetPixelIndex( y
, x
, (nEightPixels
>>i
)&1 );
670 Bitmap::ReleaseAccess( pAcc
);
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 () ) );
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;
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
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 () ) );
735 case W_META_DIBCREATEPATTERNBRUSH
:
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();
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();
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 ) );
769 case W_META_DELETEOBJECT
:
771 sal_Int16 nIndex
= 0;
772 pWMF
->ReadInt16( nIndex
);
773 pOut
->DeleteObject( nIndex
);
777 case W_META_CREATEPALETTE
:
779 pOut
->CreateObject( GDI_DUMMY
);
783 case W_META_CREATEBRUSH
:
785 pOut
->CreateObject( GDI_BRUSH
, new WinMtfFillStyle( Color( COL_WHITE
), false ) );
789 case W_META_CREATEPATTERNBRUSH
:
791 pOut
->CreateObject( GDI_BRUSH
, new WinMtfFillStyle( Color( COL_WHITE
), false ) );
795 case W_META_CREATEPENINDIRECT
:
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
);
807 aLineInfo
.SetWidth(nWidth
);
809 bool bTransparent
= false;
810 switch( nStyle
& 0xFF )
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 );
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 );
829 aLineInfo
.SetStyle( LINE_DASH
);
830 aLineInfo
.SetDashCount( 0 );
831 aLineInfo
.SetDotCount( 1 );
832 aLineInfo
.SetDotLen( 30 );
833 aLineInfo
.SetDistance( 50 );
836 aLineInfo
.SetStyle( LINE_DASH
);
837 aLineInfo
.SetDashCount( 1 );
838 aLineInfo
.SetDotCount( 0 );
839 aLineInfo
.SetDashLen( 225 );
840 aLineInfo
.SetDistance( 100 );
844 aLineInfo
.SetStyle( LINE_NONE
);
847 case PS_INSIDEFRAME
:
849 aLineInfo
.SetStyle( LINE_SOLID
);
851 switch( nStyle
& 0xF00 )
853 case PS_ENDCAP_ROUND
:
854 aLineInfo
.SetLineCap( com::sun::star::drawing::LineCap_ROUND
);
856 case PS_ENDCAP_SQUARE
:
857 aLineInfo
.SetLineCap( com::sun::star::drawing::LineCap_SQUARE
);
859 case PS_ENDCAP_FLAT
:
861 aLineInfo
.SetLineCap( com::sun::star::drawing::LineCap_BUTT
);
863 switch( nStyle
& 0xF000 )
866 aLineInfo
.SetLineJoin ( basegfx::B2DLINEJOIN_ROUND
);
869 aLineInfo
.SetLineJoin ( basegfx::B2DLINEJOIN_MITER
);
872 aLineInfo
.SetLineJoin ( basegfx::B2DLINEJOIN_BEVEL
);
875 aLineInfo
.SetLineJoin ( basegfx::B2DLINEJOIN_NONE
);
877 pOut
->CreateObject( GDI_PEN
, new WinMtfLineStyle( ReadColor(), aLineInfo
, bTransparent
) );
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
) ) );
889 case W_META_CREATEFONTINDIRECT
:
892 char lfFaceName
[LF_FACESIZE
];
893 sal_Int16 lfEscapement
= 0;
894 sal_Int16 lfOrientation
= 0;
895 sal_Int16 lfWeight
= 0;
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();
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
) );
932 case W_META_CREATEBITMAPINDIRECT
:
934 pOut
->CreateObject( GDI_DUMMY
);
938 case W_META_CREATEBITMAP
:
940 pOut
->CreateObject( GDI_DUMMY
);
944 case W_META_CREATEREGION
:
946 pOut
->CreateObject( GDI_DUMMY
);
950 case W_META_EXCLUDECLIPRECT
:
952 pOut
->ExcludeClipRect( ReadRectangle() );
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
);
967 case W_META_SELECTCLIPREGION
:
969 sal_Int16 nObjIndex
= 0;
970 pWMF
->ReadInt16( nObjIndex
);
973 tools::PolyPolygon aEmptyPolyPoly
;
974 pOut
->SetClipPath( aEmptyPolyPoly
, RGN_COPY
, true );
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
);
991 if ( nRecSize
>= 4 ) // minimal escape length
993 sal_uInt16 nMode
= 0, nLen
= 0;
994 pWMF
->ReadUInt16( nMode
)
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 );
1018 sal_uInt32 nCheckSum
= rtl_crc32( 0, &nEsc
, 4 );
1020 boost::scoped_array
<sal_Int8
> pData
;
1022 if ( ( static_cast< sal_uInt64
>( nEscLen
) + pWMF
->Tell() ) > nMetaRecEndPos
)
1024 pWMF
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
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
)
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() ) )
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
)
1052 .ReadUInt32( nStringLen
);
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() ) )
1064 pDXAry
.reset(new long[ nDXCount
]);
1065 for (sal_uInt32 i
= 0; i
< nDXCount
; i
++ )
1068 aMemoryStream
.ReadInt32( val
);
1071 aMemoryStream
.ReadUInt32( nSkipActions
);
1072 pOut
->DrawText( aPt
, aString
, pDXAry
.get() );
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
)
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;
1110 if( pEMFStream
&& nCurRecSize
+ 34 > nLen
)
1112 nEMFRecCount
= 0xFFFFFFFF;
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
);
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
:
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
);
1172 Rectangle aPlaceableBound
;
1174 bool bPlaceable
= nPlaceableMetaKey
== 0x9ac6cdd7L
;
1176 SAL_INFO("vcl.wmf", "Placeable: \"" << (bPlaceable
? "yes" : "no") << "\"");
1180 //TODO do some real error handling here
1183 // Skip reserved bytes
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
;
1197 pWMF
->ReadUInt16( nUnitsPerInch
);
1202 // Skip and don't check the checksum
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
);
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
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
);
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
;
1304 nUnicodeEscapeAction
= 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
)
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()
1349 pWMF
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
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
);
1369 if( pEMFStream
&& nEMFRecCount
== nEMFRec
)
1372 pEMFStream
->Seek( 0 );
1373 EnhWMFReader
* pEMFReader
= new EnhWMFReader ( *pEMFStream
, aMeta
);
1374 bEMFAvailable
= pEMFReader
->ReadEnhWMF();
1375 delete pEMFReader
; // destroy first!!!
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
1390 // something went wrong
1391 // continue with WMF, don't try this again
1397 const sal_uInt32 nAvailableBytes
= nEndPos
- nPos
;
1398 const sal_uInt32 nMaxPossibleRecordSize
= nAvailableBytes
/2;
1399 if (nRecSize
<= nMaxPossibleRecordSize
)
1401 nPos
+= nRecSize
* 2;
1405 pWMF
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
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
)
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
);
1435 boost::optional
<Size
> aWinExt
;
1437 Point
aViewportOrg(0,0);
1438 boost::optional
<Size
> aViewportExt
;
1442 sal_Int16 nMapMode
= MM_ANISOTROPIC
;
1443 sal_uInt16 nFunction
;
1448 pStm
->ReadUInt32( nRSize
).ReadUInt16( nFunction
);
1450 if( pStm
->GetError() )
1455 else if ( nRSize
==3 && nFunction
==0 )
1459 else if ( nRSize
< 3 || pStm
->IsEof() )
1461 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1467 case W_META_SETWINDOWORG
:
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
);
1482 case W_META_SETVIEWPORTORG
:
1484 aViewportOrg
= ReadYX();
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
);
1497 case W_META_SETMAPMODE
:
1498 pStm
->ReadInt16( nMapMode
);
1503 GetWinExtMax( ReadYX(), aBound
, nMapMode
);
1504 bBoundsDetermined
= true;
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;
1515 case W_META_ROUNDRECT
:
1516 ReadYXExt(); // size
1517 GetWinExtMax( ReadRectangle(), aBound
, nMapMode
);
1518 bBoundsDetermined
= true;
1526 GetWinExtMax( ReadRectangle(), aBound
, nMapMode
);
1527 bBoundsDetermined
= true;
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
)))
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");
1554 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
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
))
1572 for(sal_uInt16 i
= 0; i
< nPoly
; i
++ )
1575 pStm
->ReadUInt16( nP
);
1576 if (nP
> SAL_MAX_UINT16
- nPoints
)
1585 SAL_WARN_IF(!bRecordOk
, "vcl.wmf", "polypolygon record has more polygons than we can handle");
1587 bRecordOk
= bRecordOk
&& pStm
->good();
1591 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1596 if (nPoints
> pStm
->remainingSize() / (2 * sizeof(sal_uInt16
)))
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();
1615 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
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
)))
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");
1645 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1652 case W_META_SETPIXEL
:
1655 GetWinExtMax( ReadYX(), aBound
, nMapMode
);
1656 bBoundsDetermined
= true;
1660 case W_META_TEXTOUT
:
1663 pStm
->ReadUInt16( nLength
);
1664 // todo: we also have to take care of the text width
1667 pStm
->SeekRel( ( nLength
+ 1 ) &~ 1 );
1668 GetWinExtMax( ReadYX(), aBound
, nMapMode
);
1669 bBoundsDetermined
= true;
1674 case W_META_EXTTEXTOUT
:
1676 sal_uInt16 nLen
, nOptions
;
1679 aPosition
= ReadYX();
1680 pStm
->ReadUInt16( nLen
).ReadUInt16( nOptions
);
1681 // todo: we also have to take care of the text width
1684 GetWinExtMax( aPosition
, aBound
, nMapMode
);
1685 bBoundsDetermined
= true;
1690 case W_META_STRETCHBLT
:
1691 case W_META_DIBBITBLT
:
1692 case W_META_DIBSTRETCHBLT
:
1693 case W_META_STRETCHDIB
:
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
);
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;
1731 pStm
->ReadUInt32( nROP
);
1732 Size aSize
= ReadYXExt();
1733 GetWinExtMax( Rectangle( ReadYX(), aSize
), aBound
, nMapMode
);
1734 bBoundsDetermined
= true;
1739 const sal_uInt32 nAvailableBytes
= nEnd
- nPos
;
1740 const sal_uInt32 nMaxPossibleRecordSize
= nAvailableBytes
/2;
1741 if (nRSize
<= nMaxPossibleRecordSize
)
1748 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1755 pStm
->SetError( SVSTREAM_GENERALERROR
);
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());
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());
1797 WMFReader::WMFReader(SvStream
& rStreamWMF
, GDIMetaFile
& rGDIMetaFile
,
1798 FilterConfigItem
* pConfigItem
, WMF_EXTERNALHEADER
* pExtHeader
)
1799 : WinMtf(new WinMtfOutput(rGDIMetaFile
) , rStreamWMF
, pConfigItem
)
1808 , nUnicodeEscapeAction(0)
1809 , pExternalHeader(pExtHeader
)
1812 WMFReader::~WMFReader()
1817 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */