update credits
[LibreOffice.git] / emfio / source / reader / wmfreader.cxx
blob4f5606f66aae2cf37219f1b0803cec02ea1f5c7b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <wmfreader.hxx>
21 #include <emfreader.hxx>
23 #include <cstdlib>
24 #include <memory>
25 #include <optional>
26 #include <o3tl/safeint.hxx>
27 #include <o3tl/unit_conversion.hxx>
28 #include <rtl/crc.h>
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>
42 // MS Windows defines
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
122 namespace
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);
145 const char *
146 record_type_name(sal_uInt16 nRecType)
148 #ifndef SAL_LOG_INFO
149 (void) nRecType;
150 return "";
151 #else
152 switch( 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";
232 default:
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));
237 return buffer;
239 #endif
244 namespace emfio
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()
262 Point aBR, aTL;
263 aBR = ReadYX();
264 aTL = ReadYX();
265 aBR.AdjustX( -1 );
266 aBR.AdjustY( -1 );
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()
277 short nW=0, nH=0;
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));
285 switch( nFunc )
287 case W_META_SETBKCOLOR:
289 SetBkColor( ReadColor() );
291 break;
293 case W_META_SETBKMODE:
295 sal_uInt16 nDat = 0;
296 mpInputStream->ReadUInt16( nDat );
297 SetBkMode( static_cast<BkMode>(nDat) );
299 break;
301 // !!!
302 case W_META_SETMAPMODE:
304 sal_Int16 nMapMode = 0;
305 mpInputStream->ReadInt16( nMapMode );
306 SetMapMode( nMapMode );
308 break;
310 case W_META_SETROP2:
312 sal_uInt16 nROP2 = 0;
313 mpInputStream->ReadUInt16( nROP2 );
314 SetRasterOp( static_cast<WMFRasterOp>(nROP2) );
316 break;
318 case W_META_SETTEXTCOLOR:
320 SetTextColor( ReadColor() );
322 break;
324 case W_META_SETWINDOWORG:
326 SetWinOrg( ReadYX() );
328 break;
330 case W_META_SETWINDOWEXT:
332 short nWidth = 0, nHeight = 0;
333 mpInputStream->ReadInt16( nHeight ).ReadInt16( nWidth );
334 SetWinExt( Size( nWidth, nHeight ) );
336 break;
338 case W_META_OFFSETWINDOWORG:
340 short nXAdd = 0, nYAdd = 0;
341 mpInputStream->ReadInt16( nYAdd ).ReadInt16( nXAdd );
342 SetWinOrgOffset( nXAdd, nYAdd );
344 break;
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 );
353 break;
355 ScaleWinExt( static_cast<double>(nXNum) / nXDenom, static_cast<double>(nYNum) / nYDenom );
357 break;
359 case W_META_SETVIEWPORTORG:
360 case W_META_SETVIEWPORTEXT:
361 break;
363 case W_META_OFFSETVIEWPORTORG:
365 short nXAdd = 0, nYAdd = 0;
366 mpInputStream->ReadInt16( nYAdd ).ReadInt16( nXAdd );
367 SetDevOrgOffset( nXAdd, nYAdd );
369 break;
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 );
378 break;
380 ScaleDevExt( static_cast<double>(nXNum) / nXDenom, static_cast<double>(nYNum) / nYDenom );
382 break;
384 case W_META_LINETO:
386 LineTo( ReadYX() );
388 break;
390 case W_META_MOVETO:
392 MoveTo( ReadYX() );
394 break;
396 case W_META_INTERSECTCLIPRECT:
398 IntersectClipRect( ReadRectangle() );
400 break;
402 case W_META_RECTANGLE:
404 DrawRect( ReadRectangle() );
406 break;
408 case W_META_ROUNDRECT:
410 Size aSize( ReadYXExt() );
411 DrawRoundRect( ReadRectangle(), Size( aSize.Width() / 2, aSize.Height() / 2 ) );
413 break;
415 case W_META_ELLIPSE:
417 DrawEllipse( ReadRectangle() );
419 break;
421 case W_META_ARC:
423 Point aEnd( ReadYX() );
424 Point aStart( ReadYX() );
425 tools::Rectangle aRect( ReadRectangle() );
426 aRect.Justify();
427 DrawArc( aRect, aStart, aEnd );
429 break;
431 case W_META_PIE:
433 Point aEnd( ReadYX() );
434 Point aStart( ReadYX() );
435 tools::Rectangle aRect( ReadRectangle() );
436 aRect.Justify();
438 // #i73608# OutputDevice deviates from WMF
439 // semantics. start==end means full ellipse here.
440 if( aStart == aEnd )
441 DrawEllipse( aRect );
442 else
443 DrawPie( aRect, aStart, aEnd );
445 break;
447 case W_META_CHORD:
449 Point aEnd( ReadYX() );
450 Point aStart( ReadYX() );
451 tools::Rectangle aRect( ReadRectangle() );
452 aRect.Justify();
453 DrawChord( aRect, aStart, aEnd );
455 break;
457 case W_META_POLYGON:
459 bool bRecordOk = true;
461 sal_uInt16 nPoints(0);
462 mpInputStream->ReadUInt16(nPoints);
464 if (nPoints > mpInputStream->remainingSize() / (2 * sizeof(sal_uInt16)))
466 bRecordOk = false;
468 else
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();
480 if (!bRecordOk)
482 mpInputStream->SetError( SVSTREAM_FILEFORMAT_ERROR );
483 break;
486 break;
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))
498 break;
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)
512 bRecordOk = false;
513 break;
516 nPoints += pnPoints[a];
519 SAL_WARN_IF(!bRecordOk, "emfio", "polypolygon record has more polygons than we can handle");
521 bRecordOk &= mpInputStream->good();
523 if (!bRecordOk)
525 mpInputStream->SetError( SVSTREAM_FILEFORMAT_ERROR );
526 break;
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)))
536 bRecordOk = false;
537 break;
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();
553 if (!bRecordOk)
555 mpInputStream->SetError( SVSTREAM_FILEFORMAT_ERROR );
556 break;
559 DrawPolyPolygon( aPolyPoly );
562 break;
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)))
573 bRecordOk = false;
575 else
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();
587 if (!bRecordOk)
589 mpInputStream->SetError( SVSTREAM_FILEFORMAT_ERROR );
590 break;
593 break;
595 case W_META_SAVEDC:
597 Push();
599 break;
601 case W_META_RESTOREDC:
603 sal_Int16 nSavedDC;
604 mpInputStream->ReadInt16( nSavedDC );
605 SAL_INFO( "emfio", "\t\t SavedDC: " << nSavedDC );
606 Pop( nSavedDC );
608 break;
610 case W_META_SETPIXEL:
612 const Color aColor = ReadColor();
613 DrawPixel( ReadYX(), aColor );
615 break;
617 case W_META_OFFSETCLIPRGN:
619 MoveClipRegion( ReadYXExt() );
621 break;
623 case W_META_TEXTOUT:
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");
632 break;
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;
645 if (nLength)
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 );
654 break;
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");
665 break;
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");
681 break;
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
698 if (nLen)
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
716 if ( nNewTextLen )
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 )
740 break;
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;
753 while ( nDxCount-- )
755 if ( ( mpInputStream->Tell() + 2 ) > nMaxStreamPos )
756 break;
757 sal_Int16 nDxTmp = 0;
758 mpInputStream->ReadInt16(nDxTmp);
759 nDx += nDxTmp;
760 if ( nOptions & ETO_PDY )
762 if ( ( mpInputStream->Tell() + 2 ) > nMaxStreamPos )
763 break;
764 sal_Int16 nDyTmp = 0;
765 mpInputStream->ReadInt16(nDyTmp);
766 nDy += nDyTmp;
770 pDXAry[ i ] = nDx;
771 if ( nOptions & ETO_PDY )
773 pDYAry[i] = nDy;
776 if ( i == nNewTextLen )
777 bUseDXAry = true;
779 if ( pDXAry && bUseDXAry )
780 DrawText( aPosition, aText, pDXAry.get(), pDYAry.get() );
781 else
782 DrawText( aPosition, aText );
783 if ( nOptions & ETO_CLIPPED )
784 Pop();
788 break;
790 case W_META_SELECTOBJECT:
791 case W_META_SELECTPALETTE:
793 sal_uInt16 nObjIndex = 0;
794 mpInputStream->ReadUInt16( nObjIndex );
795 SelectObject( nObjIndex );
797 break;
799 case W_META_SETTEXTALIGN:
801 sal_uInt16 nAlign = 0;
802 mpInputStream->ReadUInt16( nAlign );
803 SetTextAlign( nAlign );
805 break;
807 case W_META_BITBLT:
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.");
832 break;
834 const vcl::PixelFormat ePixelFormat = vcl::bitDepthToPixelFormat( nBitCount );
835 bool bOk = nWidth > 0 && nHeight > 0 && nBytesPerScan > 0 && nPlanes == 1 && ePixelFormat != vcl::PixelFormat::INVALID;
836 if (bOk)
838 // must be enough data to fulfil the request
839 bOk = o3tl::make_unsigned( nBytesPerScan ) <= mpInputStream->remainingSize() / nHeight;
841 if (bOk)
843 // scanline must be large enough to provide all pixels
844 bOk = nBytesPerScan >= nWidth * nBitCount / 8;
846 if (bOk)
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 );
852 if ( nSye && nSxe &&
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));
863 break;
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;
872 Bitmap aBmp;
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)
906 else
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
910 break;
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));
928 break;
930 case W_META_DIBCREATEPATTERNBRUSH:
932 Bitmap aBmp;
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." );
941 CreateObject();
942 break;
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();
961 if ( !nCount )
962 nCount++;
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 ));
967 break;
969 case W_META_DELETEOBJECT:
971 sal_uInt16 nIndex = 0;
972 mpInputStream->ReadUInt16( nIndex );
973 DeleteObject( nIndex );
975 break;
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 ));
996 break;
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 ));
1003 break;
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 ));
1010 break;
1012 case W_META_CREATEPENINDIRECT:
1014 LineInfo aLineInfo;
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);
1023 if (nWidth > 0)
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 );
1034 break;
1035 case PS_DASHDOT :
1036 aLineInfo.SetStyle( LineStyle::Dash );
1037 aLineInfo.SetDashCount( 1 );
1038 aLineInfo.SetDotCount( 1 );
1039 break;
1040 case PS_DOT :
1041 aLineInfo.SetStyle( LineStyle::Dash );
1042 aLineInfo.SetDashCount( 0 );
1043 aLineInfo.SetDotCount( 1 );
1044 break;
1045 case PS_DASH :
1046 aLineInfo.SetStyle( LineStyle::Dash );
1047 aLineInfo.SetDashCount( 1 );
1048 aLineInfo.SetDotCount( 0 );
1049 break;
1050 case PS_NULL :
1051 bTransparent = true;
1052 aLineInfo.SetStyle( LineStyle::NONE );
1053 break;
1054 default :
1055 case PS_INSIDEFRAME :
1056 case PS_SOLID :
1057 aLineInfo.SetStyle( LineStyle::Solid );
1059 switch( nStyle & 0xF00 )
1061 case PS_ENDCAP_ROUND :
1062 aLineInfo.SetLineCap( css::drawing::LineCap_ROUND );
1063 break;
1064 case PS_ENDCAP_SQUARE :
1065 aLineInfo.SetLineCap( css::drawing::LineCap_SQUARE );
1066 break;
1067 case PS_ENDCAP_FLAT :
1068 default :
1069 aLineInfo.SetLineCap( css::drawing::LineCap_BUTT );
1071 switch( nStyle & 0xF000 )
1073 case PS_JOIN_ROUND :
1074 aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::Round );
1075 break;
1076 case PS_JOIN_MITER :
1077 aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::Miter );
1078 break;
1079 case PS_JOIN_BEVEL :
1080 aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::Bevel );
1081 break;
1082 default :
1083 aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::NONE );
1085 CreateObject(std::make_unique<WinMtfLineStyle>( ReadColor(), aLineInfo, bTransparent ));
1087 break;
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" );
1096 break;
1098 case W_META_CREATEFONTINDIRECT:
1100 Size aFontSize;
1101 char lfFaceName[LF_FACESIZE+1];
1102 sal_Int16 lfEscapement = 0;
1103 sal_Int16 lfOrientation = 0;
1104 sal_Int16 lfWeight = 0;
1106 LOGFONTW aLogFont;
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();
1130 else
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 ));
1140 break;
1142 case W_META_CREATEBITMAPINDIRECT:
1144 SAL_WARN( "emfio", "TODO: W_META_CREATEBITMAPINDIRECT is not implemented. Please fill the bug report" );
1145 CreateObject();
1147 break;
1149 case W_META_CREATEBITMAP:
1151 SAL_WARN( "emfio", "TODO: W_META_CREATEBITMAP is not implemented. Please fill the bug report" );
1152 CreateObject();
1154 break;
1156 case W_META_CREATEREGION:
1158 SAL_WARN( "emfio", "TODO: W_META_CREATEREGION is not implemented. Please fill the bug report" );
1159 CreateObject();
1161 break;
1163 case W_META_EXCLUDECLIPRECT :
1165 SAL_WARN( "emfio", "TODO: Not working correctly. Please fill the bug report" );
1166 ExcludeClipRect( ReadRectangle() );
1168 break;
1170 case W_META_PATBLT:
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 );
1180 break;
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" );
1187 if ( !nObjIndex )
1189 tools::PolyPolygon aEmptyPolyPoly;
1190 SetClipPath( aEmptyPolyPoly, RGN_COPY, true );
1193 break;
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 );
1205 break;
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 );
1233 #else
1234 sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 );
1235 #endif
1236 std::unique_ptr<sal_Int8[]> pData;
1238 if ( ( static_cast< sal_uInt64 >( nEscLen ) + mpInputStream->Tell() ) > nMetaRecEndPos )
1240 mpInputStream->SetError( SVSTREAM_FILEFORMAT_ERROR );
1241 break;
1243 if ( nEscLen > 0 )
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 )
1251 switch( nEsc )
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() ) )
1258 Point aPt;
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 )
1266 .ReadInt32( nTmpY )
1267 .ReadUInt32( nStringLen );
1268 aPt.setX( nTmpX );
1269 aPt.setY( nTmpY );
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() ) )
1276 nDXCount = 0;
1277 if ( nDXCount )
1278 pDXAry.reset(new tools::Long[ nDXCount ]);
1279 for (sal_uInt32 i = 0; i < nDXCount; i++ )
1281 sal_Int32 val;
1282 aMemoryStream.ReadInt32( val);
1283 pDXAry[ i ] = val;
1285 aMemoryStream.ReadUInt32(mnSkipActions);
1286 DrawText( aPt, aString, pDXAry.get() );
1290 break;
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 )
1309 if( !mnEMFRec)
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();
1318 else
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();
1327 mnEMFRec++;
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();
1342 if (mpEMFStream)
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);
1354 break;
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:
1379 case W_META_ENDDOC:
1381 SAL_WARN("emfio", "TODO: WMF record not implemented: " << record_type_name(nFunc));
1383 break;
1385 default:
1387 SAL_WARN("emfio", "Unknown Meta Action: 0x" << std::hex << nFunc << std::dec);
1391 // tdf#127471
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())
1405 return false;
1407 tools::Rectangle aPlaceableBound;
1409 bool bPlaceable = nPlaceableMetaKey == 0x9ac6cdd7L;
1411 SAL_INFO("emfio", "Placeable: \"" << (bPlaceable ? "yes" : "no") << "\"");
1413 if (bPlaceable)
1415 //TODO do some real error handling here
1416 sal_Int16 nVal;
1418 // Skip reserved bytes
1419 mpInputStream->SeekRel(2);
1421 // BoundRect
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 );
1431 // inch
1432 mpInputStream->ReadUInt16( mnUnitsPerInch );
1434 // reserved
1435 mpInputStream->SeekRel( 4 );
1437 // Skip and don't check the checksum
1438 mpInputStream->SeekRel( 2 );
1440 else
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);
1461 else
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() );
1489 Size aWMFSize(
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())
1511 return false;
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 );
1519 return false;
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;
1536 mnSkipActions = 0;
1538 mpEMFStream.reset();
1539 mnEMFRecCount = 0;
1540 mnEMFRec = 0;
1541 mnEMFSize = 0;
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 );
1562 if (
1563 !mpInputStream->good() ||
1564 (mnRecSize < 3) ||
1565 (mnRecSize == 3 && nFunction == 0)
1568 if( mpInputStream->eof() )
1569 mpInputStream->SetError( SVSTREAM_FILEFORMAT_ERROR );
1571 break;
1574 const sal_uInt32 nAvailableBytes = mnEndPos - nPos;
1575 const sal_uInt32 nMaxPossibleRecordSize = nAvailableBytes/2;
1576 if (mnRecSize > nMaxPossibleRecordSize)
1578 mpInputStream->SetError(SVSTREAM_FILEFORMAT_ERROR);
1579 break;
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 );
1595 else
1596 mnSkipActions--;
1598 if(mpEMFStream && mnEMFRecCount == mnEMFRec)
1600 GDIMetaFile aMeta;
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!!!
1607 if( bEMFAvailable )
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
1616 // records
1618 else
1620 // something went wrong
1621 // continue with WMF, don't try this again
1622 mpEMFStream.reset();
1627 nPos += mnRecSize * 2;
1628 mpInputStream->Seek(nPos);
1631 else
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 )
1643 bool bRet = true;
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();
1655 Point aWinOrg(0,0);
1656 std::optional<Size> aWinExt;
1658 Point aViewportOrg(0,0);
1659 std::optional<Size> aViewportExt;
1661 if (nEnd - nPos)
1663 sal_Int16 nMapMode = MM_ANISOTROPIC;
1664 sal_uInt16 nFunction;
1665 sal_uInt32 nRSize;
1667 while( bRet )
1669 pStm->ReadUInt32( nRSize ).ReadUInt16( nFunction );
1671 if( pStm->GetError() )
1673 bRet = false;
1674 break;
1676 else if ( nRSize==3 && nFunction==0 )
1678 break;
1680 else if ( nRSize < 3 || pStm->eof() )
1682 pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1683 bRet = false;
1684 break;
1686 switch( nFunction )
1688 case W_META_SETWINDOWORG:
1690 aWinOrg = ReadYX();
1692 break;
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);
1701 break;
1703 case W_META_SETVIEWPORTORG:
1705 aViewportOrg = ReadYX();
1707 break;
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);
1716 break;
1718 case W_META_SETMAPMODE :
1719 pStm->ReadInt16( nMapMode );
1720 break;
1722 case W_META_MOVETO:
1723 case W_META_LINETO:
1724 GetWinExtMax( ReadYX(), aBound, nMapMode );
1725 bBoundsDetermined = true;
1726 break;
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;
1734 break;
1736 case W_META_ROUNDRECT:
1737 ReadYXExt(); // size
1738 GetWinExtMax( ReadRectangle(), aBound, nMapMode );
1739 bBoundsDetermined = true;
1740 break;
1742 case W_META_ARC:
1743 case W_META_PIE:
1744 case W_META_CHORD:
1745 ReadYX(); // end
1746 ReadYX(); // start
1747 GetWinExtMax( ReadRectangle(), aBound, nMapMode );
1748 bBoundsDetermined = true;
1749 break;
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)))
1760 bRecordOk = false;
1762 else
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");
1773 if (!bRecordOk)
1775 pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1776 bRet = false;
1777 break;
1780 break;
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))
1789 bRecordOk = false;
1791 else
1793 for(sal_uInt16 i = 0; i < nPoly; i++ )
1795 sal_uInt16 nP = 0;
1796 pStm->ReadUInt16( nP );
1797 if (nP > SAL_MAX_UINT16 - nPoints)
1799 bRecordOk = false;
1800 break;
1802 nPoints += nP;
1806 SAL_WARN_IF(!bRecordOk, "emfio", "polypolygon record has more polygons than we can handle");
1808 bRecordOk = bRecordOk && pStm->good();
1810 if (!bRecordOk)
1812 pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1813 bRet = false;
1814 break;
1817 if (nPoints > pStm->remainingSize() / (2 * sizeof(sal_uInt16)))
1819 bRecordOk = false;
1821 else
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();
1834 if (!bRecordOk)
1836 pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1837 bRet = false;
1838 break;
1841 break;
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)))
1851 bRecordOk = false;
1853 else
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");
1864 if (!bRecordOk)
1866 pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1867 bRet = false;
1868 break;
1871 break;
1873 case W_META_SETPIXEL:
1875 ReadColor();
1876 GetWinExtMax( ReadYX(), aBound, nMapMode );
1877 bBoundsDetermined = true;
1879 break;
1881 case W_META_TEXTOUT:
1883 sal_uInt16 nLength;
1884 pStm->ReadUInt16( nLength );
1885 // todo: we also have to take care of the text width
1886 if ( nLength )
1888 pStm->SeekRel( ( nLength + 1 ) &~ 1 );
1889 GetWinExtMax( ReadYX(), aBound, nMapMode );
1890 bBoundsDetermined = true;
1893 break;
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
1901 if( nLen )
1903 GetWinExtMax( aPosition, aBound, nMapMode );
1904 bBoundsDetermined = true;
1907 break;
1908 case W_META_BITBLT:
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;
1945 break;
1947 case W_META_PATBLT:
1949 sal_uInt32 nROP;
1950 pStm->ReadUInt32( nROP );
1951 Size aSize = ReadYXExt();
1952 GetWinExtMax( tools::Rectangle( ReadYX(), aSize ), aBound, nMapMode );
1953 bBoundsDetermined = true;
1955 break;
1958 const auto nAvailableBytes = nEnd - nPos;
1959 const auto nMaxPossibleRecordSize = nAvailableBytes/2;
1960 if (nRSize <= nMaxPossibleRecordSize)
1962 nPos += nRSize * 2;
1963 pStm->Seek(nPos);
1965 else
1967 pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1968 bRet = false;
1972 else
1974 pStm->SetError( SVSTREAM_GENERALERROR );
1975 bRet = false;
1978 if (!bRet)
1979 return;
1981 if (aWinExt)
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());
2002 else
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)
2017 , mnRecSize(0)
2018 , mpEMFStream()
2019 , mnEMFRecCount(0)
2020 , mnEMFRec(0)
2021 , mnEMFSize(0)
2022 , mnSkipActions(0)
2023 , mpExternalHeader(pExternalHeader)
2028 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */