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 .
20 #include <wmfreader.hxx>
21 #include <emfreader.hxx>
26 #include <o3tl/safeint.hxx>
27 #include <o3tl/unit_conversion.hxx>
29 #include <rtl/tencinfo.h>
30 #include <sal/log.hxx>
31 #include <osl/endian.h>
32 #include <vcl/gdimtf.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/dibtools.hxx>
35 #include <vcl/outdev.hxx>
36 #include <vcl/wmfexternal.hxx>
37 #include <tools/fract.hxx>
38 #include <vcl/BitmapReadAccess.hxx>
39 #include <vcl/BitmapTools.hxx>
40 #include <osl/thread.h>
43 #define W_META_SETBKCOLOR 0x0201
44 #define W_META_SETBKMODE 0x0102
45 #define W_META_SETMAPMODE 0x0103
46 #define W_META_SETROP2 0x0104
47 #define W_META_SETRELABS 0x0105
48 #define W_META_SETPOLYFILLMODE 0x0106
49 #define W_META_SETSTRETCHBLTMODE 0x0107
50 #define W_META_SETTEXTCHAREXTRA 0x0108
51 #define W_META_SETTEXTCOLOR 0x0209
52 #define W_META_SETTEXTJUSTIFICATION 0x020A
53 #define W_META_SETWINDOWORG 0x020B
54 #define W_META_SETWINDOWEXT 0x020C
55 #define W_META_SETVIEWPORTORG 0x020D
56 #define W_META_SETVIEWPORTEXT 0x020E
57 #define W_META_OFFSETWINDOWORG 0x020F
58 #define W_META_SCALEWINDOWEXT 0x0410
59 #define W_META_OFFSETVIEWPORTORG 0x0211
60 #define W_META_SCALEVIEWPORTEXT 0x0412
61 #define W_META_LINETO 0x0213
62 #define W_META_MOVETO 0x0214
63 #define W_META_EXCLUDECLIPRECT 0x0415
64 #define W_META_INTERSECTCLIPRECT 0x0416
65 #define W_META_ARC 0x0817
66 #define W_META_ELLIPSE 0x0418
67 #define W_META_FLOODFILL 0x0419
68 #define W_META_PIE 0x081A
69 #define W_META_RECTANGLE 0x041B
70 #define W_META_ROUNDRECT 0x061C
71 #define W_META_PATBLT 0x061D
72 #define W_META_SAVEDC 0x001E
73 #define W_META_SETPIXEL 0x041F
74 #define W_META_OFFSETCLIPRGN 0x0220
75 #define W_META_TEXTOUT 0x0521
76 #define W_META_BITBLT 0x0922
77 #define W_META_STRETCHBLT 0x0B23
78 #define W_META_POLYGON 0x0324
79 #define W_META_POLYLINE 0x0325
80 #define W_META_ESCAPE 0x0626
81 #define W_META_RESTOREDC 0x0127
82 #define W_META_FILLREGION 0x0228
83 #define W_META_FRAMEREGION 0x0429
84 #define W_META_INVERTREGION 0x012A
85 #define W_META_PAINTREGION 0x012B
86 #define W_META_SELECTCLIPREGION 0x012C
87 #define W_META_SELECTOBJECT 0x012D
88 #define W_META_SETTEXTALIGN 0x012E
89 #define W_META_DRAWTEXT 0x062F
90 #define W_META_CHORD 0x0830
91 #define W_META_SETMAPPERFLAGS 0x0231
92 #define W_META_EXTTEXTOUT 0x0a32
93 #define W_META_SETDIBTODEV 0x0d33
94 #define W_META_SELECTPALETTE 0x0234
95 #define W_META_REALIZEPALETTE 0x0035
96 #define W_META_ANIMATEPALETTE 0x0436
97 #define W_META_SETPALENTRIES 0x0037
98 #define W_META_POLYPOLYGON 0x0538
99 #define W_META_RESIZEPALETTE 0x0139
100 #define W_META_DIBBITBLT 0x0940
101 #define W_META_DIBSTRETCHBLT 0x0b41
102 #define W_META_DIBCREATEPATTERNBRUSH 0x0142
103 #define W_META_STRETCHDIB 0x0f43
104 #define W_META_EXTFLOODFILL 0x0548
105 #define W_META_RESETDC 0x014C
106 #define W_META_STARTDOC 0x014D
107 #define W_META_STARTPAGE 0x004F
108 #define W_META_ENDPAGE 0x0050
109 #define W_META_ABORTDOC 0x0052
110 #define W_META_ENDDOC 0x005E
111 #define W_META_DELETEOBJECT 0x01f0
112 #define W_META_CREATEPALETTE 0x00f7
113 #define W_META_CREATEBRUSH 0x00F8
114 #define W_META_CREATEPATTERNBRUSH 0x01F9
115 #define W_META_CREATEPENINDIRECT 0x02FA
116 #define W_META_CREATEFONTINDIRECT 0x02FB
117 #define W_META_CREATEBRUSHINDIRECT 0x02FC
118 #define W_META_CREATEBITMAPINDIRECT 0x02FD
119 #define W_META_CREATEBITMAP 0x06FE
120 #define W_META_CREATEREGION 0x06FF
124 void GetWinExtMax(const Point
& rSource
, tools::Rectangle
& rPlaceableBound
, const sal_Int16 nMapMode
)
126 Point
aSource(rSource
);
127 if (nMapMode
== MM_HIMETRIC
)
128 aSource
.setY( -rSource
.Y() );
129 if (aSource
.X() < rPlaceableBound
.Left())
130 rPlaceableBound
.SetLeft( aSource
.X() );
131 if (aSource
.X() > rPlaceableBound
.Right())
132 rPlaceableBound
.SetRight( aSource
.X() );
133 if (aSource
.Y() < rPlaceableBound
.Top())
134 rPlaceableBound
.SetTop( aSource
.Y() );
135 if (aSource
.Y() > rPlaceableBound
.Bottom())
136 rPlaceableBound
.SetBottom( aSource
.Y() );
139 void GetWinExtMax(const tools::Rectangle
& rSource
, tools::Rectangle
& rPlaceableBound
, const sal_Int16 nMapMode
)
141 GetWinExtMax(rSource
.TopLeft(), rPlaceableBound
, nMapMode
);
142 GetWinExtMax(rSource
.BottomRight(), rPlaceableBound
, nMapMode
);
146 record_type_name(sal_uInt16 nRecType
)
154 case W_META_SETBKCOLOR
: return "META_SETBKCOLOR";
155 case W_META_SETBKMODE
: return "META_SETBKMODE";
156 case W_META_SETMAPMODE
: return "META_SETMAPMODE";
157 case W_META_SETROP2
: return "META_SETROP2";
158 case W_META_SETRELABS
: return "META_SETRELABS";
159 case W_META_SETPOLYFILLMODE
: return "META_SETPOLYFILLMODE";
160 case W_META_SETSTRETCHBLTMODE
: return "META_SETSTRETCHBLTMODE";
161 case W_META_SETTEXTCHAREXTRA
: return "META_SETTEXTCHAREXTRA";
162 case W_META_SETTEXTCOLOR
: return "META_SETTEXTCOLOR";
163 case W_META_SETTEXTJUSTIFICATION
: return "META_SETTEXTJUSTIFICATION";
164 case W_META_SETWINDOWORG
: return "META_SETWINDOWORG";
165 case W_META_SETWINDOWEXT
: return "META_SETWINDOWEXT";
166 case W_META_SETVIEWPORTORG
: return "META_SETVIEWPORTORG";
167 case W_META_SETVIEWPORTEXT
: return "META_SETVIEWPORTEXT";
168 case W_META_OFFSETWINDOWORG
: return "META_OFFSETWINDOWORG";
169 case W_META_SCALEWINDOWEXT
: return "META_SCALEWINDOWEXT";
170 case W_META_OFFSETVIEWPORTORG
: return "META_OFFSETVIEWPORTORG";
171 case W_META_SCALEVIEWPORTEXT
: return "META_SCALEVIEWPORTEXT";
172 case W_META_LINETO
: return "META_LINETO";
173 case W_META_MOVETO
: return "META_MOVETO";
174 case W_META_EXCLUDECLIPRECT
: return "META_EXCLUDECLIPRECT";
175 case W_META_INTERSECTCLIPRECT
: return "META_INTERSECTCLIPRECT";
176 case W_META_ARC
: return "META_ARC";
177 case W_META_ELLIPSE
: return "META_ELLIPSE";
178 case W_META_FLOODFILL
: return "META_FLOODFILL";
179 case W_META_PIE
: return "META_PIE";
180 case W_META_RECTANGLE
: return "META_RECTANGLE";
181 case W_META_ROUNDRECT
: return "META_ROUNDRECT";
182 case W_META_PATBLT
: return "META_PATBLT";
183 case W_META_SAVEDC
: return "META_SAVEDC";
184 case W_META_SETPIXEL
: return "META_SETPIXEL";
185 case W_META_OFFSETCLIPRGN
: return "META_OFFSETCLIPRGN";
186 case W_META_TEXTOUT
: return "META_TEXTOUT";
187 case W_META_BITBLT
: return "META_BITBLT";
188 case W_META_STRETCHBLT
: return "META_STRETCHBLT";
189 case W_META_POLYGON
: return "META_POLYGON";
190 case W_META_POLYLINE
: return "META_POLYLINE";
191 case W_META_ESCAPE
: return "META_ESCAPE";
192 case W_META_RESTOREDC
: return "META_RESTOREDC";
193 case W_META_FILLREGION
: return "META_FILLREGION";
194 case W_META_FRAMEREGION
: return "META_FRAMEREGION";
195 case W_META_INVERTREGION
: return "META_INVERTREGION";
196 case W_META_PAINTREGION
: return "META_PAINTREGION";
197 case W_META_SELECTCLIPREGION
: return "META_SELECTCLIPREGION";
198 case W_META_SELECTOBJECT
: return "META_SELECTOBJECT";
199 case W_META_SETTEXTALIGN
: return "META_SETTEXTALIGN";
200 case W_META_DRAWTEXT
: return "META_DRAWTEXT";
201 case W_META_CHORD
: return "META_CHORD";
202 case W_META_SETMAPPERFLAGS
: return "META_SETMAPPERFLAGS";
203 case W_META_EXTTEXTOUT
: return "META_EXTTEXTOUT";
204 case W_META_SETDIBTODEV
: return "META_SETDIBTODEV";
205 case W_META_SELECTPALETTE
: return "META_SELECTPALETTE";
206 case W_META_REALIZEPALETTE
: return "META_REALIZEPALETTE";
207 case W_META_ANIMATEPALETTE
: return "META_ANIMATEPALETTE";
208 case W_META_SETPALENTRIES
: return "META_SETPALENTRIES";
209 case W_META_POLYPOLYGON
: return "META_POLYPOLYGON";
210 case W_META_RESIZEPALETTE
: return "META_RESIZEPALETTE";
211 case W_META_DIBBITBLT
: return "META_DIBBITBLT";
212 case W_META_DIBSTRETCHBLT
: return "META_DIBSTRETCHBLT";
213 case W_META_DIBCREATEPATTERNBRUSH
: return "META_DIBCREATEPATTERNBRUSH";
214 case W_META_STRETCHDIB
: return "META_STRETCHDIB";
215 case W_META_EXTFLOODFILL
: return "META_EXTFLOODFILL";
216 case W_META_RESETDC
: return "META_RESETDC";
217 case W_META_STARTDOC
: return "META_STARTDOC";
218 case W_META_STARTPAGE
: return "META_STARTPAGE";
219 case W_META_ENDPAGE
: return "META_ENDPAGE";
220 case W_META_ABORTDOC
: return "META_ABORTDOC";
221 case W_META_ENDDOC
: return "META_ENDDOC";
222 case W_META_DELETEOBJECT
: return "META_DELETEOBJECT";
223 case W_META_CREATEPALETTE
: return "META_CREATEPALETTE";
224 case W_META_CREATEBRUSH
: return "META_CREATEBRUSH";
225 case W_META_CREATEPATTERNBRUSH
: return "META_CREATEPATTERNBRUSH";
226 case W_META_CREATEPENINDIRECT
: return "META_CREATEPENINDIRECT";
227 case W_META_CREATEFONTINDIRECT
: return "META_CREATEFONTINDIRECT";
228 case W_META_CREATEBRUSHINDIRECT
: return "META_CREATEBRUSHINDIRECT";
229 case W_META_CREATEBITMAPINDIRECT
: return "META_CREATEBITMAPINDIRECT";
230 case W_META_CREATEBITMAP
: return "META_CREATEBITMAP";
231 case W_META_CREATEREGION
: return "META_CREATEREGION";
233 // Yes, return a pointer to a static buffer. This is a very
234 // local debugging output function, so no big deal.
235 static char buffer
[11];
236 sprintf(buffer
, "0x%08" SAL_PRIxUINT32
, sal_uInt32(nRecType
));
246 inline Point
WmfReader::ReadPoint()
248 short nX
= 0, nY
= 0;
249 mpInputStream
->ReadInt16( nX
).ReadInt16( nY
);
250 return Point( nX
, nY
);
253 inline Point
WmfReader::ReadYX()
255 short nX
= 0, nY
= 0;
256 mpInputStream
->ReadInt16( nY
).ReadInt16( nX
);
257 return Point( nX
, nY
);
260 tools::Rectangle
WmfReader::ReadRectangle()
267 if (aTL
.X() > aBR
.X() || aTL
.Y() > aBR
.Y())
269 SAL_WARN("emfio", "broken rectangle");
270 return tools::Rectangle::Justify(aTL
, aBR
);
272 return tools::Rectangle( aTL
, aBR
);
275 Size
WmfReader::ReadYXExt()
278 mpInputStream
->ReadInt16( nH
).ReadInt16( nW
);
279 return Size( nW
, nH
);
282 void WmfReader::ReadRecordParams( sal_uInt32 nRecordSize
, sal_uInt16 nFunc
)
284 SAL_INFO("emfio", "\t" << record_type_name(nFunc
));
287 case W_META_SETBKCOLOR
:
289 SetBkColor( ReadColor() );
293 case W_META_SETBKMODE
:
296 mpInputStream
->ReadUInt16( nDat
);
297 SetBkMode( static_cast<BkMode
>(nDat
) );
302 case W_META_SETMAPMODE
:
304 sal_Int16 nMapMode
= 0;
305 mpInputStream
->ReadInt16( nMapMode
);
306 SetMapMode( nMapMode
);
312 sal_uInt16 nROP2
= 0;
313 mpInputStream
->ReadUInt16( nROP2
);
314 SetRasterOp( static_cast<WMFRasterOp
>(nROP2
) );
318 case W_META_SETTEXTCOLOR
:
320 SetTextColor( ReadColor() );
324 case W_META_SETWINDOWORG
:
326 SetWinOrg( ReadYX() );
330 case W_META_SETWINDOWEXT
:
332 short nWidth
= 0, nHeight
= 0;
333 mpInputStream
->ReadInt16( nHeight
).ReadInt16( nWidth
);
334 SetWinExt( Size( nWidth
, nHeight
) );
338 case W_META_OFFSETWINDOWORG
:
340 short nXAdd
= 0, nYAdd
= 0;
341 mpInputStream
->ReadInt16( nYAdd
).ReadInt16( nXAdd
);
342 SetWinOrgOffset( nXAdd
, nYAdd
);
346 case W_META_SCALEWINDOWEXT
:
348 short nXNum
= 0, nXDenom
= 0, nYNum
= 0, nYDenom
= 0;
349 mpInputStream
->ReadInt16( nYDenom
).ReadInt16( nYNum
).ReadInt16( nXDenom
).ReadInt16( nXNum
);
350 if (!nYDenom
|| !nXDenom
)
352 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
355 ScaleWinExt( static_cast<double>(nXNum
) / nXDenom
, static_cast<double>(nYNum
) / nYDenom
);
359 case W_META_SETVIEWPORTORG
:
360 case W_META_SETVIEWPORTEXT
:
363 case W_META_OFFSETVIEWPORTORG
:
365 short nXAdd
= 0, nYAdd
= 0;
366 mpInputStream
->ReadInt16( nYAdd
).ReadInt16( nXAdd
);
367 SetDevOrgOffset( nXAdd
, nYAdd
);
371 case W_META_SCALEVIEWPORTEXT
:
373 short nXNum
= 0, nXDenom
= 0, nYNum
= 0, nYDenom
= 0;
374 mpInputStream
->ReadInt16( nYDenom
).ReadInt16( nYNum
).ReadInt16( nXDenom
).ReadInt16( nXNum
);
375 if (!nYDenom
|| !nXDenom
)
377 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
380 ScaleDevExt( static_cast<double>(nXNum
) / nXDenom
, static_cast<double>(nYNum
) / nYDenom
);
396 case W_META_INTERSECTCLIPRECT
:
398 IntersectClipRect( ReadRectangle() );
402 case W_META_RECTANGLE
:
404 DrawRect( ReadRectangle() );
408 case W_META_ROUNDRECT
:
410 Size
aSize( ReadYXExt() );
411 DrawRoundRect( ReadRectangle(), Size( aSize
.Width() / 2, aSize
.Height() / 2 ) );
417 DrawEllipse( ReadRectangle() );
423 Point
aEnd( ReadYX() );
424 Point
aStart( ReadYX() );
425 tools::Rectangle
aRect( ReadRectangle() );
427 DrawArc( aRect
, aStart
, aEnd
);
433 Point
aEnd( ReadYX() );
434 Point
aStart( ReadYX() );
435 tools::Rectangle
aRect( ReadRectangle() );
438 // #i73608# OutputDevice deviates from WMF
439 // semantics. start==end means full ellipse here.
441 DrawEllipse( aRect
);
443 DrawPie( aRect
, aStart
, aEnd
);
449 Point
aEnd( ReadYX() );
450 Point
aStart( ReadYX() );
451 tools::Rectangle
aRect( ReadRectangle() );
453 DrawChord( aRect
, aStart
, aEnd
);
459 bool bRecordOk
= true;
461 sal_uInt16
nPoints(0);
462 mpInputStream
->ReadUInt16(nPoints
);
464 if (nPoints
> mpInputStream
->remainingSize() / (2 * sizeof(sal_uInt16
)))
470 tools::Polygon
aPoly(nPoints
);
471 for (sal_uInt16
i(0); i
< nPoints
&& mpInputStream
->good(); ++i
)
472 aPoly
[ i
] = ReadPoint();
473 DrawPolygon(aPoly
, false/*bRecordPath*/);
476 SAL_WARN_IF(!bRecordOk
, "emfio", "polygon record has more points than we can handle");
478 bRecordOk
&= mpInputStream
->good();
482 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
488 case W_META_POLYPOLYGON
:
490 sal_uInt16
nPolyCount(0);
491 // Number of polygons:
492 mpInputStream
->ReadUInt16( nPolyCount
);
493 if (nPolyCount
&& mpInputStream
->good())
495 bool bRecordOk
= true;
496 if (nPolyCount
> mpInputStream
->remainingSize() / sizeof(sal_uInt16
))
501 // Number of points of each polygon. Determine total number of points
502 std::unique_ptr
<sal_uInt16
[]> xPolygonPointCounts(new sal_uInt16
[nPolyCount
]);
503 sal_uInt16
* pnPoints
= xPolygonPointCounts
.get();
504 tools::PolyPolygon
aPolyPoly(nPolyCount
);
505 sal_uInt16 nPoints
= 0;
506 for (sal_uInt16 a
= 0; a
< nPolyCount
&& mpInputStream
->good(); ++a
)
508 mpInputStream
->ReadUInt16( pnPoints
[a
] );
510 if (pnPoints
[a
] > SAL_MAX_UINT16
- nPoints
)
516 nPoints
+= pnPoints
[a
];
519 SAL_WARN_IF(!bRecordOk
, "emfio", "polypolygon record has more polygons than we can handle");
521 bRecordOk
&= mpInputStream
->good();
525 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
529 // Polygon points are:
530 for (sal_uInt16 a
= 0; a
< nPolyCount
&& mpInputStream
->good(); ++a
)
532 const sal_uInt16
nPointCount(pnPoints
[a
]);
534 if (nPointCount
> mpInputStream
->remainingSize() / (2 * sizeof(sal_uInt16
)))
540 std::unique_ptr
<Point
[]> xPolygonPoints(new Point
[nPointCount
]);
541 Point
* pPtAry
= xPolygonPoints
.get();
543 for(sal_uInt16
b(0); b
< nPointCount
&& mpInputStream
->good(); ++b
)
545 pPtAry
[b
] = ReadPoint();
548 aPolyPoly
.Insert( tools::Polygon(nPointCount
, pPtAry
) );
551 bRecordOk
&= mpInputStream
->good();
555 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
559 DrawPolyPolygon( aPolyPoly
);
564 case W_META_POLYLINE
:
566 bool bRecordOk
= true;
568 sal_uInt16
nPoints(0);
569 mpInputStream
->ReadUInt16(nPoints
);
571 if (nPoints
> mpInputStream
->remainingSize() / (2 * sizeof(sal_uInt16
)))
577 tools::Polygon
aPoly(nPoints
);
578 for (sal_uInt16
i(0); i
< nPoints
&& mpInputStream
->good(); ++i
)
579 aPoly
[ i
] = ReadPoint();
580 DrawPolyLine( aPoly
);
583 SAL_WARN_IF(!bRecordOk
, "emfio", "polyline record has more points than we can handle");
585 bRecordOk
&= mpInputStream
->good();
589 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
601 case W_META_RESTOREDC
:
604 mpInputStream
->ReadInt16( nSavedDC
);
605 SAL_INFO( "emfio", "\t\t SavedDC: " << nSavedDC
);
610 case W_META_SETPIXEL
:
612 const Color aColor
= ReadColor();
613 DrawPixel( ReadYX(), aColor
);
617 case W_META_OFFSETCLIPRGN
:
619 MoveClipRegion( ReadYXExt() );
625 //record is Recordsize, RecordFunction, StringLength, <String>, YStart, XStart
626 const sal_uInt32 nNonStringLen
= sizeof(sal_uInt32
) + 4 * sizeof(sal_uInt16
);
627 const sal_uInt32 nRecSize
= mnRecSize
* 2;
629 if (nRecSize
< nNonStringLen
)
631 SAL_WARN("emfio", "W_META_TEXTOUT too short");
635 sal_uInt16 nLength
= 0;
636 mpInputStream
->ReadUInt16(nLength
);
637 sal_uInt16 nStoredLength
= (nLength
+ 1) &~ 1;
639 if (nRecSize
- nNonStringLen
< nStoredLength
)
641 SAL_WARN("emfio", "W_META_TEXTOUT too short, truncating string");
642 nLength
= nStoredLength
= nRecSize
- nNonStringLen
;
647 std::vector
<char> aChars(nStoredLength
);
648 nLength
= std::min
<sal_uInt16
>(nLength
, mpInputStream
->ReadBytes(aChars
.data(), aChars
.size()));
649 OUString
aText(aChars
.data(), nLength
, GetCharSet());
650 Point
aPosition( ReadYX() );
651 DrawText( aPosition
, aText
);
656 case W_META_EXTTEXTOUT
:
658 //record is Recordsize, RecordFunction, Y, X, StringLength, options, maybe rectangle, <String>
659 sal_uInt32 nNonStringLen
= sizeof(sal_uInt32
) + 5 * sizeof(sal_uInt16
);
660 const sal_uInt32 nRecSize
= mnRecSize
* 2;
662 if (nRecSize
< nNonStringLen
)
664 SAL_WARN("emfio", "W_META_EXTTEXTOUT too short");
668 auto nRecordPos
= mpInputStream
->Tell() - 6;
669 Point aPosition
= ReadYX();
670 sal_uInt16 nLen
= 0, nOptions
= 0;
671 mpInputStream
->ReadUInt16( nLen
).ReadUInt16( nOptions
);
672 SAL_INFO( "emfio", "\t\t\t Pos: " << aPosition
.getX() << ":" << aPosition
.getY() << " String Length: " << nLen
<< " Options: " << nOptions
);
673 tools::Rectangle aRect
;
674 if ( ( nOptions
& ETO_CLIPPED
) || ( nOptions
& ETO_OPAQUE
) )
676 nNonStringLen
+= 2 * sizeof(sal_uInt16
);
678 if (nRecSize
< nNonStringLen
)
680 SAL_WARN("emfio", "W_META_TEXTOUT too short");
683 const Point aTopLeft
= ReadPoint();
684 const Point aBottomRight
= ReadPoint();
685 aRect
= tools::Rectangle( aTopLeft
, aBottomRight
);
686 if ( nOptions
& ETO_OPAQUE
)
687 DrawRectWithBGColor( aRect
);
688 SAL_INFO( "emfio", "\t\t\t Rectangle : " << aTopLeft
.getX() << ":" << aTopLeft
.getY() << ", " << aBottomRight
.getX() << ":" << aBottomRight
.getY() );
691 ComplexTextLayoutFlags nTextLayoutMode
= ComplexTextLayoutFlags::Default
;
692 if ( nOptions
& ETO_RTLREADING
)
693 nTextLayoutMode
= ComplexTextLayoutFlags::BiDiRtl
| ComplexTextLayoutFlags::TextOriginLeft
;
694 SetTextLayoutMode( nTextLayoutMode
);
695 SAL_WARN_IF( ( nOptions
& ( ETO_PDY
| ETO_GLYPH_INDEX
) ) != 0, "emfio", "SJ: ETO_PDY || ETO_GLYPH_INDEX in WMF" );
697 // output only makes sense if the text contains characters
700 sal_Int32 nOriginalTextLen
= nLen
;
701 sal_Int32 nOriginalBlockLen
= ( nOriginalTextLen
+ 1 ) &~ 1;
703 auto nMaxStreamPos
= nRecordPos
+ nRecSize
;
704 auto nRemainingSize
= std::min(mpInputStream
->remainingSize(), nMaxStreamPos
- mpInputStream
->Tell());
705 if (nRemainingSize
< o3tl::make_unsigned(nOriginalBlockLen
))
707 SAL_WARN("emfio", "exttextout record claimed more data than the stream can provide");
708 nOriginalTextLen
= nOriginalBlockLen
= nRemainingSize
;
711 std::unique_ptr
<char[]> pChar(new char[nOriginalBlockLen
]);
712 mpInputStream
->ReadBytes(pChar
.get(), nOriginalBlockLen
);
713 OUString
aText(pChar
.get(), nOriginalTextLen
, GetCharSet()); // after this conversion the text may contain
714 sal_Int32 nNewTextLen
= aText
.getLength(); // less character (japanese version), so the
715 // dxAry will not fit
718 if ( nOptions
& ETO_CLIPPED
)
720 Push(); // Save the current clip. It will be restored after text drawing
721 IntersectClipRect( aRect
);
723 SAL_INFO( "emfio", "\t\t\t Text : " << aText
);
724 std::unique_ptr
<tools::Long
[]> pDXAry
, pDYAry
;
725 auto nDxArySize
= nMaxStreamPos
- mpInputStream
->Tell();
726 auto nDxAryEntries
= nDxArySize
>> 1;
727 bool bUseDXAry
= false;
729 if ( ( ( nDxAryEntries
% nOriginalTextLen
) == 0 ) && ( nNewTextLen
<= nOriginalTextLen
) )
731 sal_Int32 i
; // needed just outside the for
732 pDXAry
.reset(new tools::Long
[ nNewTextLen
]);
733 if ( nOptions
& ETO_PDY
)
735 pDYAry
.reset(new tools::Long
[ nNewTextLen
]);
737 for (i
= 0; i
< nNewTextLen
; i
++ )
739 if ( mpInputStream
->Tell() >= nMaxStreamPos
)
741 sal_Int32 nDxCount
= 1;
742 if ( nNewTextLen
!= nOriginalTextLen
)
744 sal_Unicode cUniChar
= aText
[i
];
745 OString
aTmp(&cUniChar
, 1, GetCharSet());
746 if ( aTmp
.getLength() > 1 )
748 nDxCount
= aTmp
.getLength();
752 sal_Int16 nDx
= 0, nDy
= 0;
755 if ( ( mpInputStream
->Tell() + 2 ) > nMaxStreamPos
)
757 sal_Int16 nDxTmp
= 0;
758 mpInputStream
->ReadInt16(nDxTmp
);
760 if ( nOptions
& ETO_PDY
)
762 if ( ( mpInputStream
->Tell() + 2 ) > nMaxStreamPos
)
764 sal_Int16 nDyTmp
= 0;
765 mpInputStream
->ReadInt16(nDyTmp
);
771 if ( nOptions
& ETO_PDY
)
776 if ( i
== nNewTextLen
)
779 if ( pDXAry
&& bUseDXAry
)
780 DrawText( aPosition
, aText
, pDXAry
.get(), pDYAry
.get() );
782 DrawText( aPosition
, aText
);
783 if ( nOptions
& ETO_CLIPPED
)
790 case W_META_SELECTOBJECT
:
791 case W_META_SELECTPALETTE
:
793 sal_uInt16 nObjIndex
= 0;
794 mpInputStream
->ReadUInt16( nObjIndex
);
795 SelectObject( nObjIndex
);
799 case W_META_SETTEXTALIGN
:
801 sal_uInt16 nAlign
= 0;
802 mpInputStream
->ReadUInt16( nAlign
);
803 SetTextAlign( nAlign
);
808 case W_META_STRETCHBLT
:
810 sal_uInt32 nRasterOperation
= 0;
811 sal_Int16 nSrcHeight
= 0, nSrcWidth
= 0, nYSrc
, nXSrc
, nSye
, nSxe
, nBitmapType
, nWidth
, nHeight
, nBytesPerScan
;
812 sal_uInt8 nPlanes
, nBitCount
;
813 const bool bNoSourceBitmap
= ( nRecordSize
== ( static_cast< sal_uInt32
>( nFunc
) >> 8 ) + 3 );
815 mpInputStream
->ReadUInt32( nRasterOperation
);
816 SAL_INFO("emfio", "\t\t Raster operation: 0x" << std::hex
<< nRasterOperation
<< std::dec
<< ", No source bitmap: " << bNoSourceBitmap
);
818 if( nFunc
== W_META_STRETCHBLT
)
819 mpInputStream
->ReadInt16( nSrcHeight
).ReadInt16( nSrcWidth
);
821 mpInputStream
->ReadInt16( nYSrc
).ReadInt16( nXSrc
);
822 if ( bNoSourceBitmap
)
823 mpInputStream
->SeekRel( 2 ); // Skip Reserved 2 bytes (it must be ignored)
824 mpInputStream
->ReadInt16( nSye
).ReadInt16( nSxe
);
825 Point
aPoint( ReadYX() ); // The upper-left corner of the destination rectangle.
826 mpInputStream
->ReadInt16( nBitmapType
).ReadInt16( nWidth
).ReadInt16( nHeight
).ReadInt16( nBytesPerScan
).ReadUChar( nPlanes
).ReadUChar( nBitCount
);
828 SAL_INFO("emfio", "\t\t Bitmap type:" << nBitmapType
<< " Width:" << nWidth
<< " Height:" << nHeight
<< " WidthBytes:" << nBytesPerScan
<< " Planes: " << static_cast< sal_uInt16
>( nPlanes
) << " BitCount: " << static_cast< sal_uInt16
>( nBitCount
) );
829 if ( bNoSourceBitmap
|| ( nBitCount
== 4 ) || ( nBitCount
== 8 ) || nPlanes
!= 1 )
831 SAL_WARN("emfio", "\t\t TODO The unsupported Bitmap record. Please fill a bug.");
834 const vcl::PixelFormat ePixelFormat
= vcl::bitDepthToPixelFormat( nBitCount
);
835 bool bOk
= nWidth
> 0 && nHeight
> 0 && nBytesPerScan
> 0 && nPlanes
== 1 && ePixelFormat
!= vcl::PixelFormat::INVALID
;
838 // must be enough data to fulfil the request
839 bOk
= o3tl::make_unsigned( nBytesPerScan
) <= mpInputStream
->remainingSize() / nHeight
;
843 // scanline must be large enough to provide all pixels
844 bOk
= nBytesPerScan
>= nWidth
* nBitCount
/ 8;
848 std::unique_ptr
< sal_uInt8
[] > pData
;
849 pData
.reset( new sal_uInt8
[ nHeight
* nBytesPerScan
] );
850 mpInputStream
->ReadBytes( pData
.get(), nHeight
* nBytesPerScan
);
851 BitmapEx aBitmap
= vcl::bitmap::CreateFromData( pData
.get(), nWidth
, nHeight
, nBytesPerScan
, ePixelFormat
, true );
853 ( nXSrc
+ nSxe
<= nWidth
) &&
854 ( nYSrc
+ nSye
<= nHeight
) )
856 tools::Rectangle
aCropRect( Point( nXSrc
, nYSrc
), Size( nSxe
, nSye
) );
857 aBitmap
.Crop( aCropRect
);
859 tools::Rectangle
aDestRect( aPoint
, Size( nSxe
, nSye
) );
860 maBmpSaveList
.emplace_back(new BSaveStruct(aBitmap
, aDestRect
, nRasterOperation
));
865 case W_META_DIBBITBLT
:
866 case W_META_DIBSTRETCHBLT
:
867 case W_META_STRETCHDIB
:
869 sal_uInt32 nRasterOperation
= 0;
870 sal_uInt16 nColorUsage
= 0;
871 sal_Int16 nSrcHeight
= 0, nSrcWidth
= 0, nYSrc
= 0, nXSrc
= 0;
873 const bool bNoSourceBitmap
= ( nFunc
!= W_META_STRETCHDIB
) && ( nRecordSize
== ( ( static_cast< sal_uInt32
>( nFunc
) >> 8 ) + 3 ) );
875 mpInputStream
->ReadUInt32( nRasterOperation
);
876 SAL_INFO("emfio", "\t\t Raster operation: 0x" << std::hex
<< nRasterOperation
<< std::dec
<< ", No source bitmap: " << bNoSourceBitmap
);
877 if( nFunc
== W_META_STRETCHDIB
)
878 mpInputStream
->ReadUInt16( nColorUsage
);
880 // nSrcHeight and nSrcWidth is the number of pixels that has to been used
881 // If they are set to zero, it is as indicator not to scale the bitmap later
882 if( nFunc
== W_META_DIBSTRETCHBLT
||
883 nFunc
== W_META_STRETCHDIB
)
884 mpInputStream
->ReadInt16( nSrcHeight
).ReadInt16( nSrcWidth
);
886 // nYSrc and nXSrc is the offset of the first pixel
887 mpInputStream
->ReadInt16( nYSrc
).ReadInt16( nXSrc
);
889 if ( bNoSourceBitmap
)
890 mpInputStream
->SeekRel( 2 ); // Skip Reserved 2 bytes (it must be ignored)
892 Size
aDestSize( ReadYXExt() );
893 if ( aDestSize
.Width() && aDestSize
.Height() ) // #92623# do not try to read buggy bitmaps
895 tools::Rectangle
aDestRect( ReadYX(), aDestSize
);
896 if ( !bNoSourceBitmap
)
898 // tdf#142625 Read the DIBHeader and check if bitmap is supported
899 // If bitmap is not supported don't run ReadDIB, as it will interrupt image processing
900 const auto nOldPos(mpInputStream
->Tell());
901 sal_uInt32 nHeaderSize
;
902 sal_uInt16 nBitCount
;
903 mpInputStream
->ReadUInt32( nHeaderSize
);
904 if ( nHeaderSize
== 0xC ) // BitmapCoreHeader
905 mpInputStream
->SeekRel( 6 ); // skip Width (16), Height (16), Planes (16)
907 mpInputStream
->SeekRel( 10 ); // skip Width (32), Height (32), Planes (16)
908 mpInputStream
->ReadUInt16( nBitCount
);
909 if ( nBitCount
== 0 ) // TODO Undefined BitCount (JPEG/PNG), which are not supported
911 mpInputStream
->Seek(nOldPos
);
913 if ( !ReadDIB( aBmp
, *mpInputStream
, false ) )
914 SAL_WARN( "emfio", "\tTODO Read DIB failed. Interrupting processing whole image. Please report bug report." );
916 // test if it is sensible to crop
917 if ( nSrcHeight
&& nSrcWidth
&&
918 ( nXSrc
+ nSrcWidth
<= aBmp
.GetSizePixel().Width() ) &&
919 ( nYSrc
+ nSrcHeight
<= aBmp
.GetSizePixel().Height() ) )
921 tools::Rectangle
aCropRect( Point( nXSrc
, nYSrc
), Size( nSrcWidth
, nSrcHeight
) );
922 aBmp
.Crop( aCropRect
);
925 maBmpSaveList
.emplace_back(new BSaveStruct(aBmp
, aDestRect
, nRasterOperation
));
930 case W_META_DIBCREATEPATTERNBRUSH
:
933 sal_uInt32 nRed
= 0, nGreen
= 0, nBlue
= 0, nCount
= 1;
934 sal_uInt16 nStyle
, nColorUsage
;
936 mpInputStream
->ReadUInt16( nStyle
).ReadUInt16( nColorUsage
);
937 SAL_INFO( "emfio", "\t\t Style:" << nStyle
<< ", ColorUsage: " << nColorUsage
);
938 if ( nStyle
== BS_PATTERN
) // TODO tdf#142625 Add support for pattern
940 SAL_WARN( "emfio", "\tTODO: Pattern brush style is not supported." );
944 if ( !ReadDIB( aBmp
, *mpInputStream
, false ) )
945 SAL_WARN( "emfio", "\tTODO Read DIB failed. Interrupting processing whole image. Please report bug report." );
946 if ( !aBmp
.IsEmpty() )
948 Bitmap::ScopedReadAccess
pBmp(aBmp
);
949 for ( tools::Long y
= 0; y
< pBmp
->Height(); y
++ )
951 for ( tools::Long x
= 0; x
< pBmp
->Width(); x
++ )
953 const BitmapColor
aColor( pBmp
->GetColor( y
, x
) );
955 nRed
+= aColor
.GetRed();
956 nGreen
+= aColor
.GetGreen();
957 nBlue
+= aColor
.GetBlue();
960 nCount
= pBmp
->Height() * pBmp
->Width();
964 Color
aColor( static_cast<sal_uInt8
>( nRed
/ nCount
), static_cast<sal_uInt8
>( nGreen
/ nCount
), static_cast<sal_uInt8
>( nBlue
/ nCount
) );
965 CreateObject(std::make_unique
<WinMtfFillStyle
>( aColor
, false ));
969 case W_META_DELETEOBJECT
:
971 sal_uInt16 nIndex
= 0;
972 mpInputStream
->ReadUInt16( nIndex
);
973 DeleteObject( nIndex
);
977 case W_META_CREATEPALETTE
:
979 sal_uInt16 nStart
= 0;
980 sal_uInt16 nNumberOfEntries
= 0;
981 mpInputStream
->ReadUInt16( nStart
);
982 mpInputStream
->ReadUInt16( nNumberOfEntries
);
984 SAL_INFO("emfio", "\t\t Start 0x" << std::hex
<< nStart
<< std::dec
<< ", Number of entries: " << nNumberOfEntries
);
985 sal_uInt32 nPalleteEntry
;
986 std::vector
< Color
> aPaletteColors
;
987 for (sal_uInt16 i
= 0; i
< nNumberOfEntries
; ++i
)
989 //PALETTEENTRY: Values, Blue, Green, Red
990 mpInputStream
->ReadUInt32( nPalleteEntry
);
991 SAL_INFO("emfio", "\t\t " << i
<< ". Palette entry: " << std::setw(10) << std::showbase
<<std::hex
<< nPalleteEntry
<< std::dec
);
992 aPaletteColors
.push_back(Color(static_cast<sal_uInt8
>(nPalleteEntry
), static_cast<sal_uInt8
>(nPalleteEntry
>> 8), static_cast<sal_uInt8
>(nPalleteEntry
>> 16)));
994 CreateObject(std::make_unique
<WinMtfPalette
>( aPaletteColors
));
998 case W_META_CREATEBRUSH
:
1000 SAL_WARN( "emfio", "TODO: Not implemented. Please fill the bug report" );
1001 CreateObject(std::make_unique
<WinMtfFillStyle
>( COL_WHITE
, false ));
1005 case W_META_CREATEPATTERNBRUSH
:
1007 SAL_WARN( "emfio", "TODO: Not implemented. Please fill the bug report" );
1008 CreateObject(std::make_unique
<WinMtfFillStyle
>( COL_WHITE
, false ));
1012 case W_META_CREATEPENINDIRECT
:
1015 sal_uInt16 nStyle
= 0;
1016 sal_uInt16 nWidth
= 0;
1017 sal_uInt16 nHeight
= 0;
1019 mpInputStream
->ReadUInt16(nStyle
);
1020 mpInputStream
->ReadUInt16(nWidth
);
1021 mpInputStream
->ReadUInt16(nHeight
);
1024 aLineInfo
.SetWidth(nWidth
);
1026 bool bTransparent
= false;
1028 switch( nStyle
& 0xFF )
1030 case PS_DASHDOTDOT
:
1031 aLineInfo
.SetStyle( LineStyle::Dash
);
1032 aLineInfo
.SetDashCount( 1 );
1033 aLineInfo
.SetDotCount( 2 );
1036 aLineInfo
.SetStyle( LineStyle::Dash
);
1037 aLineInfo
.SetDashCount( 1 );
1038 aLineInfo
.SetDotCount( 1 );
1041 aLineInfo
.SetStyle( LineStyle::Dash
);
1042 aLineInfo
.SetDashCount( 0 );
1043 aLineInfo
.SetDotCount( 1 );
1046 aLineInfo
.SetStyle( LineStyle::Dash
);
1047 aLineInfo
.SetDashCount( 1 );
1048 aLineInfo
.SetDotCount( 0 );
1051 bTransparent
= true;
1052 aLineInfo
.SetStyle( LineStyle::NONE
);
1055 case PS_INSIDEFRAME
:
1057 aLineInfo
.SetStyle( LineStyle::Solid
);
1059 switch( nStyle
& 0xF00 )
1061 case PS_ENDCAP_ROUND
:
1062 aLineInfo
.SetLineCap( css::drawing::LineCap_ROUND
);
1064 case PS_ENDCAP_SQUARE
:
1065 aLineInfo
.SetLineCap( css::drawing::LineCap_SQUARE
);
1067 case PS_ENDCAP_FLAT
:
1069 aLineInfo
.SetLineCap( css::drawing::LineCap_BUTT
);
1071 switch( nStyle
& 0xF000 )
1073 case PS_JOIN_ROUND
:
1074 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Round
);
1076 case PS_JOIN_MITER
:
1077 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Miter
);
1079 case PS_JOIN_BEVEL
:
1080 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Bevel
);
1083 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::NONE
);
1085 CreateObject(std::make_unique
<WinMtfLineStyle
>( ReadColor(), aLineInfo
, bTransparent
));
1089 case W_META_CREATEBRUSHINDIRECT
:
1091 sal_uInt16 nBrushStyle
= 0;
1092 mpInputStream
->ReadUInt16( nBrushStyle
);
1093 CreateObject(std::make_unique
<WinMtfFillStyle
>( ReadColor(), ( nBrushStyle
== BS_NULL
) ));
1094 SAL_WARN_IF( (nBrushStyle
!= BS_SOLID
) && (nBrushStyle
!= BS_NULL
), "emfio", "TODO: Brush style not implemented. Please fill the bug report" );
1098 case W_META_CREATEFONTINDIRECT
:
1101 char lfFaceName
[LF_FACESIZE
+1];
1102 sal_Int16 lfEscapement
= 0;
1103 sal_Int16 lfOrientation
= 0;
1104 sal_Int16 lfWeight
= 0;
1107 aFontSize
= ReadYXExt();
1108 mpInputStream
->ReadInt16( lfEscapement
);
1109 mpInputStream
->ReadInt16( lfOrientation
);
1110 mpInputStream
->ReadInt16( lfWeight
);
1111 mpInputStream
->ReadUChar( aLogFont
.lfItalic
);
1112 mpInputStream
->ReadUChar( aLogFont
.lfUnderline
);
1113 mpInputStream
->ReadUChar( aLogFont
.lfStrikeOut
);
1114 mpInputStream
->ReadUChar( aLogFont
.lfCharSet
);
1115 mpInputStream
->ReadUChar( aLogFont
.lfOutPrecision
);
1116 mpInputStream
->ReadUChar( aLogFont
.lfClipPrecision
);
1117 mpInputStream
->ReadUChar( aLogFont
.lfQuality
);
1118 mpInputStream
->ReadUChar( aLogFont
.lfPitchAndFamily
);
1119 size_t nRet
= mpInputStream
->ReadBytes( lfFaceName
, LF_FACESIZE
);
1120 lfFaceName
[nRet
] = 0;
1121 aLogFont
.lfWidth
= aFontSize
.Width();
1122 aLogFont
.lfHeight
= aFontSize
.Height();
1123 aLogFont
.lfEscapement
= lfEscapement
;
1124 aLogFont
.lfOrientation
= lfOrientation
;
1125 aLogFont
.lfWeight
= lfWeight
;
1127 rtl_TextEncoding eCharSet
;
1128 if ( ( aLogFont
.lfCharSet
== OEM_CHARSET
) || ( aLogFont
.lfCharSet
== DEFAULT_CHARSET
) )
1129 eCharSet
= osl_getThreadTextEncoding();
1131 eCharSet
= rtl_getTextEncodingFromWindowsCharset( aLogFont
.lfCharSet
);
1132 if ( eCharSet
== RTL_TEXTENCODING_DONTKNOW
)
1133 eCharSet
= osl_getThreadTextEncoding();
1134 if ( eCharSet
== RTL_TEXTENCODING_SYMBOL
)
1135 eCharSet
= RTL_TEXTENCODING_MS_1252
;
1136 aLogFont
.alfFaceName
= OUString( lfFaceName
, strlen(lfFaceName
), eCharSet
);
1138 CreateObject(std::make_unique
<WinMtfFontStyle
>( aLogFont
));
1142 case W_META_CREATEBITMAPINDIRECT
:
1144 SAL_WARN( "emfio", "TODO: W_META_CREATEBITMAPINDIRECT is not implemented. Please fill the bug report" );
1149 case W_META_CREATEBITMAP
:
1151 SAL_WARN( "emfio", "TODO: W_META_CREATEBITMAP is not implemented. Please fill the bug report" );
1156 case W_META_CREATEREGION
:
1158 SAL_WARN( "emfio", "TODO: W_META_CREATEREGION is not implemented. Please fill the bug report" );
1163 case W_META_EXCLUDECLIPRECT
:
1165 SAL_WARN( "emfio", "TODO: Not working correctly. Please fill the bug report" );
1166 ExcludeClipRect( ReadRectangle() );
1172 sal_uInt32 nROP
= 0;
1173 WMFRasterOp nOldROP
= WMFRasterOp::NONE
;
1174 mpInputStream
->ReadUInt32( nROP
);
1175 Size aSize
= ReadYXExt();
1176 nOldROP
= SetRasterOp( static_cast<WMFRasterOp
>(nROP
) );
1177 DrawRect( tools::Rectangle( ReadYX(), aSize
), false );
1178 SetRasterOp( nOldROP
);
1182 case W_META_SELECTCLIPREGION
:
1184 sal_uInt16 nObjIndex
;
1185 mpInputStream
->ReadUInt16( nObjIndex
);
1186 SAL_WARN( "emfio", "TODO: W_META_SELECTCLIPREGION is not implemented. Please fill the bug report" );
1189 tools::PolyPolygon aEmptyPolyPoly
;
1190 SetClipPath( aEmptyPolyPoly
, RGN_COPY
, true );
1195 case W_META_ESCAPE
:
1197 // mnRecSize has been checked previously to be greater than 3
1198 sal_uInt64 nMetaRecSize
= static_cast< sal_uInt64
>(mnRecSize
- 2 ) * 2;
1199 sal_uInt64 nMetaRecEndPos
= mpInputStream
->Tell() + nMetaRecSize
;
1201 // taking care that mnRecSize does not exceed the maximal stream position
1202 if ( nMetaRecEndPos
> mnEndPos
)
1204 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1207 if (mnRecSize
>= 4 ) // minimal escape length
1209 sal_uInt16 nMode
= 0, nLen
= 0;
1210 mpInputStream
->ReadUInt16( nMode
)
1211 .ReadUInt16( nLen
);
1212 if ( ( nMode
== W_MFCOMMENT
) && ( nLen
>= 4 ) )
1214 sal_uInt32 nNewMagic
= 0; // we have to read int32 for
1215 mpInputStream
->ReadUInt32( nNewMagic
); // META_ESCAPE_ENHANCED_METAFILE CommentIdentifier
1217 if( nNewMagic
== 0x2c2a4f4f && nLen
>= 14 )
1219 sal_uInt16 nMagic2
= 0;
1220 mpInputStream
->ReadUInt16( nMagic2
);
1221 if( nMagic2
== 0x0a ) // 2nd half of magic
1222 { // continue with private escape
1223 sal_uInt32 nCheck
= 0, nEsc
= 0;
1224 mpInputStream
->ReadUInt32( nCheck
)
1225 .ReadUInt32( nEsc
);
1227 sal_uInt32 nEscLen
= nLen
- 14;
1228 if ( nEscLen
<= (mnRecSize
* 2 ) )
1230 #ifdef OSL_BIGENDIAN
1231 sal_uInt32 nTmp
= OSL_SWAPDWORD( nEsc
);
1232 sal_uInt32 nCheckSum
= rtl_crc32( 0, &nTmp
, 4 );
1234 sal_uInt32 nCheckSum
= rtl_crc32( 0, &nEsc
, 4 );
1236 std::unique_ptr
<sal_Int8
[]> pData
;
1238 if ( ( static_cast< sal_uInt64
>( nEscLen
) + mpInputStream
->Tell() ) > nMetaRecEndPos
)
1240 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1245 pData
.reset(new sal_Int8
[ nEscLen
]);
1246 mpInputStream
->ReadBytes(pData
.get(), nEscLen
);
1247 nCheckSum
= rtl_crc32( nCheckSum
, pData
.get(), nEscLen
);
1249 if ( nCheck
== nCheckSum
)
1253 case PRIVATE_ESCAPE_UNICODE
:
1255 // we will use text instead of polygons only if we have the correct font
1256 if ( Application::GetDefaultDevice()->IsFontAvailable( GetFont().GetFamilyName() ) )
1259 sal_uInt32 nStringLen
, nDXCount
;
1260 std::unique_ptr
<tools::Long
[]> pDXAry
;
1261 SvMemoryStream
aMemoryStream( nEscLen
);
1262 aMemoryStream
.WriteBytes(pData
.get(), nEscLen
);
1263 aMemoryStream
.Seek( STREAM_SEEK_TO_BEGIN
);
1264 sal_Int32
nTmpX(0), nTmpY(0);
1265 aMemoryStream
.ReadInt32( nTmpX
)
1267 .ReadUInt32( nStringLen
);
1271 if ( ( static_cast< sal_uInt64
>( nStringLen
) * sizeof( sal_Unicode
) ) < ( nEscLen
- aMemoryStream
.Tell() ) )
1273 OUString aString
= read_uInt16s_ToOUString(aMemoryStream
, nStringLen
);
1274 aMemoryStream
.ReadUInt32( nDXCount
);
1275 if ( ( static_cast< sal_uInt64
>( nDXCount
) * sizeof( sal_Int32
) ) >= ( nEscLen
- aMemoryStream
.Tell() ) )
1278 pDXAry
.reset(new tools::Long
[ nDXCount
]);
1279 for (sal_uInt32 i
= 0; i
< nDXCount
; i
++ )
1282 aMemoryStream
.ReadInt32( val
);
1285 aMemoryStream
.ReadUInt32(mnSkipActions
);
1286 DrawText( aPt
, aString
, pDXAry
.get() );
1296 else if ( (nNewMagic
== static_cast< sal_uInt32
>(0x43464D57)) && (nLen
>= 34) && ( static_cast<sal_Int32
>(nLen
+ 10) <= static_cast<sal_Int32
>(mnRecSize
* 2) ))
1298 sal_uInt32 nComType
= 0, nVersion
= 0, nFlags
= 0, nComRecCount
= 0,
1299 nCurRecSize
= 0, nRemainingSize
= 0, nEMFTotalSize
= 0;
1300 sal_uInt16 nCheck
= 0;
1302 mpInputStream
->ReadUInt32( nComType
).ReadUInt32( nVersion
).ReadUInt16( nCheck
).ReadUInt32( nFlags
)
1303 .ReadUInt32( nComRecCount
).ReadUInt32( nCurRecSize
)
1304 .ReadUInt32( nRemainingSize
).ReadUInt32( nEMFTotalSize
); // the nRemainingSize is not mentioned in MSDN documentation
1305 // but it seems to be required to read in data produced by OLE
1307 if( nComType
== 0x01 && nVersion
== 0x10000 && nComRecCount
)
1310 { // first EMF comment
1311 mnEMFRecCount
= nComRecCount
;
1312 mnEMFSize
= nEMFTotalSize
;
1313 if (mnEMFSize
> mpInputStream
->remainingSize())
1315 SAL_WARN("emfio", "emf size claims to be larger than remaining data");
1316 mpEMFStream
.reset();
1319 mpEMFStream
= std::make_unique
<SvMemoryStream
>(mnEMFSize
, 0);
1321 else if( (mnEMFRecCount
!= nComRecCount
) || (mnEMFSize
!= nEMFTotalSize
) ) // add additional checks here
1323 // total records should be the same as in previous comments
1324 mnEMFRecCount
= 0xFFFFFFFF;
1325 mpEMFStream
.reset();
1329 if (mpEMFStream
&& nCurRecSize
+ 34 > nLen
)
1331 mnEMFRecCount
= 0xFFFFFFFF;
1332 mpEMFStream
.reset();
1335 if (mpEMFStream
&& nCurRecSize
> mpInputStream
->remainingSize())
1337 SAL_WARN("emfio", "emf record size claims to be larger than remaining data");
1338 mnEMFRecCount
= 0xFFFFFFFF;
1339 mpEMFStream
.reset();
1344 std::vector
<sal_Int8
> aBuf(nCurRecSize
);
1345 sal_uInt32 nCount
= mpInputStream
->ReadBytes(aBuf
.data(), nCurRecSize
);
1346 if( nCount
== nCurRecSize
)
1347 mpEMFStream
->WriteBytes(aBuf
.data(), nCount
);
1356 case W_META_SETRELABS
:
1357 case W_META_SETPOLYFILLMODE
:
1358 case W_META_SETSTRETCHBLTMODE
:
1359 case W_META_SETTEXTCHAREXTRA
:
1360 case W_META_SETTEXTJUSTIFICATION
:
1361 case W_META_FLOODFILL
:
1362 case W_META_FILLREGION
:
1363 case W_META_FRAMEREGION
:
1364 case W_META_INVERTREGION
:
1365 case W_META_PAINTREGION
:
1366 case W_META_DRAWTEXT
:
1367 case W_META_SETMAPPERFLAGS
:
1368 case W_META_SETDIBTODEV
:
1369 case W_META_REALIZEPALETTE
:
1370 case W_META_ANIMATEPALETTE
:
1371 case W_META_SETPALENTRIES
:
1372 case W_META_RESIZEPALETTE
:
1373 case W_META_EXTFLOODFILL
:
1374 case W_META_RESETDC
:
1375 case W_META_STARTDOC
:
1376 case W_META_STARTPAGE
:
1377 case W_META_ENDPAGE
:
1378 case W_META_ABORTDOC
:
1381 SAL_WARN("emfio", "TODO: WMF record not implemented: " << record_type_name(nFunc
));
1387 SAL_WARN("emfio", "Unknown Meta Action: 0x" << std::hex
<< nFunc
<< std::dec
);
1392 maScaledFontHelper
.applyAlternativeFontScale();
1395 const tools::Long aMaxWidth
= 1024;
1397 bool WmfReader::ReadHeader()
1399 sal_uInt64
const nStrmPos
= mpInputStream
->Tell();
1401 sal_uInt32
nPlaceableMetaKey(0);
1402 // if available read the METAFILEHEADER
1403 mpInputStream
->ReadUInt32( nPlaceableMetaKey
);
1404 if (!mpInputStream
->good())
1407 tools::Rectangle aPlaceableBound
;
1409 bool bPlaceable
= nPlaceableMetaKey
== 0x9ac6cdd7L
;
1411 SAL_INFO("emfio", "Placeable: \"" << (bPlaceable
? "yes" : "no") << "\"");
1415 //TODO do some real error handling here
1418 // Skip reserved bytes
1419 mpInputStream
->SeekRel(2);
1422 mpInputStream
->ReadInt16( nVal
);
1423 aPlaceableBound
.SetLeft( nVal
);
1424 mpInputStream
->ReadInt16( nVal
);
1425 aPlaceableBound
.SetTop( nVal
);
1426 mpInputStream
->ReadInt16( nVal
);
1427 aPlaceableBound
.SetRight( nVal
);
1428 mpInputStream
->ReadInt16( nVal
);
1429 aPlaceableBound
.SetBottom( nVal
);
1432 mpInputStream
->ReadUInt16( mnUnitsPerInch
);
1435 mpInputStream
->SeekRel( 4 );
1437 // Skip and don't check the checksum
1438 mpInputStream
->SeekRel( 2 );
1442 mnUnitsPerInch
= 96;
1444 if (mpExternalHeader
!= nullptr
1445 && mpExternalHeader
->xExt
> 0
1446 && mpExternalHeader
->yExt
> 0
1447 && (mpExternalHeader
->mapMode
== MM_ISOTROPIC
|| mpExternalHeader
->mapMode
== MM_ANISOTROPIC
))
1449 // #n417818#: If we have an external header then overwrite the bounds!
1450 tools::Rectangle
aExtRect(0, 0,
1451 o3tl::convert(mpExternalHeader
->xExt
, o3tl::Length::mm100
, o3tl::Length::px
),
1452 o3tl::convert(mpExternalHeader
->yExt
, o3tl::Length::mm100
, o3tl::Length::px
));
1453 aPlaceableBound
= aExtRect
;
1455 SAL_INFO("emfio", "External header size "
1456 " left: " << aPlaceableBound
.Left() << " top: " << aPlaceableBound
.Top()
1457 << " right: " << aPlaceableBound
.Right() << " bottom: " << aPlaceableBound
.Bottom());
1459 SetMapMode(mpExternalHeader
->mapMode
);
1463 mpInputStream
->Seek(nStrmPos
+ 18); // set the streampos to the start of the metaactions
1464 GetPlaceableBound(aPlaceableBound
, mpInputStream
);
1466 // The image size is not known so normalize the calculated bounds so that the
1467 // resulting image is not too big
1468 if (aPlaceableBound
.GetWidth() > aMaxWidth
)
1470 const double fMaxWidth
= static_cast<double>(aMaxWidth
);
1471 double fRatio
= aPlaceableBound
.GetWidth() / fMaxWidth
;
1473 aPlaceableBound
= tools::Rectangle(
1474 aPlaceableBound
.Left() / fRatio
,
1475 aPlaceableBound
.Top() / fRatio
,
1476 aPlaceableBound
.Right() / fRatio
,
1477 aPlaceableBound
.Bottom() / fRatio
);
1479 SAL_INFO("emfio", "Placeable bounds "
1480 " left: " << aPlaceableBound
.Left() << " top: " << aPlaceableBound
.Top()
1481 << " right: " << aPlaceableBound
.Right() << " bottom: " << aPlaceableBound
.Bottom());
1485 mpInputStream
->Seek( nStrmPos
);
1488 SetWinOrg( aPlaceableBound
.TopLeft() );
1490 std::abs( aPlaceableBound
.GetWidth() ), std::abs( aPlaceableBound
.GetHeight() ) );
1491 SetWinExt( aWMFSize
);
1493 SAL_INFO("emfio", "WMF size w: " << aWMFSize
.Width() << " h: " << aWMFSize
.Height());
1495 Size
aDevExt( 10000, 10000 );
1496 if( ( std::abs( aWMFSize
.Width() ) > 1 ) && ( std::abs( aWMFSize
.Height() ) > 1 ) )
1498 const Fraction
aFrac( 1, mnUnitsPerInch
);
1499 MapMode
aWMFMap( MapUnit::MapInch
, Point(), aFrac
, aFrac
);
1500 Size
aSize100(OutputDevice::LogicToLogic(aWMFSize
, aWMFMap
, MapMode(MapUnit::Map100thMM
)));
1501 aDevExt
= Size( std::abs( aSize100
.Width() ), std::abs( aSize100
.Height() ) );
1503 SetDevExt( aDevExt
);
1505 SAL_INFO("emfio", "Dev size w: " << aDevExt
.Width() << " h: " << aDevExt
.Height());
1507 // read the METAHEADER
1508 sal_uInt32
nMetaKey(0);
1509 mpInputStream
->ReadUInt32( nMetaKey
); // type and headersize
1510 if (!mpInputStream
->good())
1512 if (nMetaKey
!= 0x00090001)
1514 sal_uInt16
aNextWord(0);
1515 mpInputStream
->ReadUInt16( aNextWord
);
1516 if (nMetaKey
!= 0x10000 || aNextWord
!= 0x09)
1518 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1523 mpInputStream
->SeekRel( 2 ); // Version (of Windows)
1524 mpInputStream
->SeekRel( 4 ); // Size (of file in words)
1525 mpInputStream
->SeekRel( 2 ); // NoObjects (maximum number of simultaneous objects)
1526 mpInputStream
->SeekRel( 4 ); // MaxRecord (size of largest record in words)
1527 mpInputStream
->SeekRel( 2 ); // NoParameters (Unused
1529 return mpInputStream
->good();
1532 void WmfReader::ReadWMF()
1534 sal_uInt16 nFunction
;
1538 mpEMFStream
.reset();
1543 SetMapMode( MM_ANISOTROPIC
);
1544 SetWinOrg( Point() );
1545 SetWinExt( Size( 1, 1 ) );
1546 SetDevExt( Size( 10000, 10000 ) );
1548 mnEndPos
=mpInputStream
->TellEnd();
1549 mpInputStream
->Seek( mnStartPos
);
1551 if ( ReadHeader( ) )
1553 auto nPos
= mpInputStream
->Tell();
1555 if( mnEndPos
- mnStartPos
)
1557 bool bEMFAvailable
= false;
1558 while( !mpInputStream
->eof() )
1560 mpInputStream
->ReadUInt32(mnRecSize
).ReadUInt16( nFunction
);
1563 !mpInputStream
->good() ||
1565 (mnRecSize
== 3 && nFunction
== 0)
1568 if( mpInputStream
->eof() )
1569 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1574 const sal_uInt32 nAvailableBytes
= mnEndPos
- nPos
;
1575 const sal_uInt32 nMaxPossibleRecordSize
= nAvailableBytes
/2;
1576 if (mnRecSize
> nMaxPossibleRecordSize
)
1578 mpInputStream
->SetError(SVSTREAM_FILEFORMAT_ERROR
);
1582 if ( !bEMFAvailable
)
1584 if( !maBmpSaveList
.empty()
1585 && ( nFunction
!= W_META_STRETCHDIB
)
1586 && ( nFunction
!= W_META_DIBBITBLT
)
1587 && ( nFunction
!= W_META_DIBSTRETCHBLT
)
1590 ResolveBitmapActions( maBmpSaveList
);
1593 if ( !mnSkipActions
)
1594 ReadRecordParams( mnRecSize
, nFunction
);
1598 if(mpEMFStream
&& mnEMFRecCount
== mnEMFRec
)
1601 mpEMFStream
->Seek( 0 );
1602 std::unique_ptr
<EmfReader
> pEMFReader(std::make_unique
<EmfReader
>( *mpEMFStream
, aMeta
));
1603 pEMFReader
->SetEnableEMFPlus(mbEnableEMFPlus
);
1604 bEMFAvailable
= pEMFReader
->ReadEnhWMF();
1605 pEMFReader
.reset(); // destroy first!!!
1609 AddFromGDIMetaFile( aMeta
);
1610 SetrclFrame( tools::Rectangle( Point(0, 0), aMeta
.GetPrefSize()));
1612 // the stream needs to be set to the wmf end position,
1613 // otherwise the GfxLink that is created will be incorrect
1614 // (leading to graphic loss after swapout/swapin).
1615 // so we will proceed normally, but are ignoring further wmf
1620 // something went wrong
1621 // continue with WMF, don't try this again
1622 mpEMFStream
.reset();
1627 nPos
+= mnRecSize
* 2;
1628 mpInputStream
->Seek(nPos
);
1632 mpInputStream
->SetError( SVSTREAM_GENERALERROR
);
1634 if( !mpInputStream
->GetError() && !maBmpSaveList
.empty() )
1635 ResolveBitmapActions( maBmpSaveList
);
1637 if ( mpInputStream
->GetError() )
1638 mpInputStream
->Seek( mnStartPos
);
1641 void WmfReader::GetPlaceableBound( tools::Rectangle
& rPlaceableBound
, SvStream
* pStm
)
1645 tools::Rectangle aBound
;
1646 aBound
.SetLeft( RECT_MAX
);
1647 aBound
.SetTop( RECT_MAX
);
1648 aBound
.SetRight( RECT_MIN
);
1649 aBound
.SetBottom( RECT_MIN
);
1650 bool bBoundsDetermined
= false;
1652 auto nPos
= pStm
->Tell();
1653 auto nEnd
= nPos
+ pStm
->remainingSize();
1656 std::optional
<Size
> aWinExt
;
1658 Point
aViewportOrg(0,0);
1659 std::optional
<Size
> aViewportExt
;
1663 sal_Int16 nMapMode
= MM_ANISOTROPIC
;
1664 sal_uInt16 nFunction
;
1669 pStm
->ReadUInt32( nRSize
).ReadUInt16( nFunction
);
1671 if( pStm
->GetError() )
1676 else if ( nRSize
==3 && nFunction
==0 )
1680 else if ( nRSize
< 3 || pStm
->eof() )
1682 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1688 case W_META_SETWINDOWORG
:
1694 case W_META_SETWINDOWEXT
:
1696 sal_Int16
nWidth(0), nHeight(0);
1697 pStm
->ReadInt16(nHeight
);
1698 pStm
->ReadInt16(nWidth
);
1699 aWinExt
= Size(nWidth
, nHeight
);
1703 case W_META_SETVIEWPORTORG
:
1705 aViewportOrg
= ReadYX();
1709 case W_META_SETVIEWPORTEXT
:
1711 sal_Int16
nWidth(0), nHeight(0);
1712 pStm
->ReadInt16(nHeight
);
1713 pStm
->ReadInt16(nWidth
);
1714 aViewportExt
= Size(nWidth
, nHeight
);
1718 case W_META_SETMAPMODE
:
1719 pStm
->ReadInt16( nMapMode
);
1724 GetWinExtMax( ReadYX(), aBound
, nMapMode
);
1725 bBoundsDetermined
= true;
1728 case W_META_RECTANGLE
:
1729 case W_META_INTERSECTCLIPRECT
:
1730 case W_META_EXCLUDECLIPRECT
:
1731 case W_META_ELLIPSE
:
1732 GetWinExtMax( ReadRectangle(), aBound
, nMapMode
);
1733 bBoundsDetermined
= true;
1736 case W_META_ROUNDRECT
:
1737 ReadYXExt(); // size
1738 GetWinExtMax( ReadRectangle(), aBound
, nMapMode
);
1739 bBoundsDetermined
= true;
1747 GetWinExtMax( ReadRectangle(), aBound
, nMapMode
);
1748 bBoundsDetermined
= true;
1751 case W_META_POLYGON
:
1753 bool bRecordOk
= true;
1755 sal_uInt16
nPoints(0);
1756 pStm
->ReadUInt16( nPoints
);
1758 if (nPoints
> pStm
->remainingSize() / (2 * sizeof(sal_uInt16
)))
1764 for(sal_uInt16 i
= 0; i
< nPoints
; i
++ )
1766 GetWinExtMax( ReadPoint(), aBound
, nMapMode
);
1767 bBoundsDetermined
= true;
1771 SAL_WARN_IF(!bRecordOk
, "emfio", "polyline record claimed more points than the stream can provide");
1775 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1782 case W_META_POLYPOLYGON
:
1784 bool bRecordOk
= true;
1785 sal_uInt16
nPoly(0), nPoints(0);
1786 pStm
->ReadUInt16(nPoly
);
1787 if (nPoly
> pStm
->remainingSize() / sizeof(sal_uInt16
))
1793 for(sal_uInt16 i
= 0; i
< nPoly
; i
++ )
1796 pStm
->ReadUInt16( nP
);
1797 if (nP
> SAL_MAX_UINT16
- nPoints
)
1806 SAL_WARN_IF(!bRecordOk
, "emfio", "polypolygon record has more polygons than we can handle");
1808 bRecordOk
= bRecordOk
&& pStm
->good();
1812 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1817 if (nPoints
> pStm
->remainingSize() / (2 * sizeof(sal_uInt16
)))
1823 for (sal_uInt16 i
= 0; i
< nPoints
; i
++ )
1825 GetWinExtMax( ReadPoint(), aBound
, nMapMode
);
1826 bBoundsDetermined
= true;
1830 SAL_WARN_IF(!bRecordOk
, "emfio", "polypolygon record claimed more points than the stream can provide");
1832 bRecordOk
&= pStm
->good();
1836 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1843 case W_META_POLYLINE
:
1845 bool bRecordOk
= true;
1847 sal_uInt16
nPoints(0);
1848 pStm
->ReadUInt16(nPoints
);
1849 if (nPoints
> pStm
->remainingSize() / (2 * sizeof(sal_uInt16
)))
1855 for (sal_uInt16 i
= 0; i
< nPoints
; ++i
)
1857 GetWinExtMax( ReadPoint(), aBound
, nMapMode
);
1858 bBoundsDetermined
= true;
1862 SAL_WARN_IF(!bRecordOk
, "emfio", "polyline record claimed more points than the stream can provide");
1866 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1873 case W_META_SETPIXEL
:
1876 GetWinExtMax( ReadYX(), aBound
, nMapMode
);
1877 bBoundsDetermined
= true;
1881 case W_META_TEXTOUT
:
1884 pStm
->ReadUInt16( nLength
);
1885 // todo: we also have to take care of the text width
1888 pStm
->SeekRel( ( nLength
+ 1 ) &~ 1 );
1889 GetWinExtMax( ReadYX(), aBound
, nMapMode
);
1890 bBoundsDetermined
= true;
1895 case W_META_EXTTEXTOUT
:
1897 sal_uInt16 nLen
, nOptions
;
1898 Point aPosition
= ReadYX();
1899 pStm
->ReadUInt16( nLen
).ReadUInt16( nOptions
);
1900 // todo: we also have to take care of the text width
1903 GetWinExtMax( aPosition
, aBound
, nMapMode
);
1904 bBoundsDetermined
= true;
1909 case W_META_DIBBITBLT
:
1910 case W_META_DIBSTRETCHBLT
:
1911 case W_META_STRETCHBLT
:
1912 case W_META_STRETCHDIB
:
1914 sal_uInt32 nRasterOperation
;
1915 sal_Int16 nYSrc
, nXSrc
;
1916 sal_uInt16 nColorUsage
;
1917 pStm
->ReadUInt32( nRasterOperation
);
1919 if( nFunction
== W_META_STRETCHDIB
)
1920 pStm
->ReadUInt16( nColorUsage
);
1922 if( nFunction
== W_META_DIBSTRETCHBLT
||
1923 nFunction
== W_META_STRETCHBLT
||
1924 nFunction
== W_META_STRETCHDIB
)
1926 sal_Int16 nSrcHeight
, nSrcWidth
;
1927 pStm
->ReadInt16( nSrcHeight
).ReadInt16( nSrcWidth
);
1930 // nYSrc and nXSrc is the offset of the first pixel
1931 pStm
->ReadInt16( nYSrc
).ReadInt16( nXSrc
);
1933 const bool bNoSourceBitmap
= ( nFunction
!= W_META_STRETCHDIB
) && ( nRSize
== ( ( static_cast< sal_uInt32
>( nFunction
) >> 8 ) + 3 ) );
1934 if ( bNoSourceBitmap
)
1935 mpInputStream
->SeekRel( 2 ); // Skip Reserved 2 bytes (it must be ignored)
1937 Size
aDestSize( ReadYXExt() );
1938 if ( aDestSize
.Width() && aDestSize
.Height() ) // #92623# do not try to read buggy bitmaps
1940 tools::Rectangle
aDestRect( ReadYX(), aDestSize
);
1941 GetWinExtMax( aDestRect
, aBound
, nMapMode
);
1942 bBoundsDetermined
= true;
1950 pStm
->ReadUInt32( nROP
);
1951 Size aSize
= ReadYXExt();
1952 GetWinExtMax( tools::Rectangle( ReadYX(), aSize
), aBound
, nMapMode
);
1953 bBoundsDetermined
= true;
1958 const auto nAvailableBytes
= nEnd
- nPos
;
1959 const auto nMaxPossibleRecordSize
= nAvailableBytes
/2;
1960 if (nRSize
<= nMaxPossibleRecordSize
)
1967 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1974 pStm
->SetError( SVSTREAM_GENERALERROR
);
1983 rPlaceableBound
= tools::Rectangle(aWinOrg
, *aWinExt
);
1984 SAL_INFO("emfio", "Window dimension "
1985 " left: " << rPlaceableBound
.Left() << " top: " << rPlaceableBound
.Top()
1986 << " right: " << rPlaceableBound
.Right() << " bottom: " << rPlaceableBound
.Bottom());
1988 else if (aViewportExt
)
1990 rPlaceableBound
= tools::Rectangle(aViewportOrg
, *aViewportExt
);
1991 SAL_INFO("emfio", "Viewport dimension "
1992 " left: " << rPlaceableBound
.Left() << " top: " << rPlaceableBound
.Top()
1993 << " right: " << rPlaceableBound
.Right() << " bottom: " << rPlaceableBound
.Bottom());
1995 else if (bBoundsDetermined
)
1997 rPlaceableBound
= aBound
;
1998 SAL_INFO("emfio", "Determined dimension "
1999 " left: " << rPlaceableBound
.Left() << " top: " << rPlaceableBound
.Top()
2000 << " right: " << rPlaceableBound
.Right() << " bottom: " << rPlaceableBound
.Bottom());
2004 rPlaceableBound
.SetLeft( 0 );
2005 rPlaceableBound
.SetTop( 0 );
2006 rPlaceableBound
.SetRight( aMaxWidth
);
2007 rPlaceableBound
.SetBottom( aMaxWidth
);
2008 SAL_INFO("emfio", "Default dimension "
2009 " left: " << rPlaceableBound
.Left() << " top: " << rPlaceableBound
.Top()
2010 << " right: " << rPlaceableBound
.Right() << " bottom: " << rPlaceableBound
.Bottom());
2014 WmfReader::WmfReader(SvStream
& rStreamWMF
, GDIMetaFile
& rGDIMetaFile
, const WmfExternal
* pExternalHeader
)
2015 : MtfTools(rGDIMetaFile
, rStreamWMF
)
2016 , mnUnitsPerInch(96)
2023 , mpExternalHeader(pExternalHeader
)
2028 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */