xref: /trunk/main/svtools/source/filter/wmf/winwmf.cxx (revision 864d6d404ef6868a2971746939c3496b71cc3952)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_svtools.hxx"
24 
25 #include "winmtf.hxx"
26 #include <vcl/gdimtf.hxx>
27 #include <rtl/crc.h>
28 #include <rtl/tencinfo.h>
29 #include <osl/endian.h>
30 #include <vcl/svapp.hxx>
31 #include <vcl/dibtools.hxx>
32 
33 //====================== MS-Windows-defines ===============================
34 
35 #define W_META_SETBKCOLOR           0x0201
36 #define W_META_SETBKMODE            0x0102
37 #define W_META_SETMAPMODE           0x0103
38 #define W_META_SETROP2              0x0104
39 #define W_META_SETRELABS            0x0105
40 #define W_META_SETPOLYFILLMODE      0x0106
41 #define W_META_SETSTRETCHBLTMODE    0x0107
42 #define W_META_SETTEXTCHAREXTRA     0x0108
43 #define W_META_SETTEXTCOLOR         0x0209
44 #define W_META_SETTEXTJUSTIFICATION 0x020A
45 #define W_META_SETWINDOWORG         0x020B
46 #define W_META_SETWINDOWEXT         0x020C
47 #define W_META_SETVIEWPORTORG       0x020D
48 #define W_META_SETVIEWPORTEXT       0x020E
49 #define W_META_OFFSETWINDOWORG      0x020F
50 #define W_META_SCALEWINDOWEXT       0x0410
51 #define W_META_OFFSETVIEWPORTORG    0x0211
52 #define W_META_SCALEVIEWPORTEXT     0x0412
53 #define W_META_LINETO               0x0213
54 #define W_META_MOVETO               0x0214
55 #define W_META_EXCLUDECLIPRECT      0x0415
56 #define W_META_INTERSECTCLIPRECT    0x0416
57 #define W_META_ARC                  0x0817
58 #define W_META_ELLIPSE              0x0418
59 #define W_META_FLOODFILL            0x0419
60 #define W_META_PIE                  0x081A
61 #define W_META_RECTANGLE            0x041B
62 #define W_META_ROUNDRECT            0x061C
63 #define W_META_PATBLT               0x061D
64 #define W_META_SAVEDC               0x001E
65 #define W_META_SETPIXEL             0x041F
66 #define W_META_OFFSETCLIPRGN        0x0220
67 #define W_META_TEXTOUT              0x0521
68 #define W_META_BITBLT               0x0922
69 #define W_META_STRETCHBLT           0x0B23
70 #define W_META_POLYGON              0x0324
71 #define W_META_POLYLINE             0x0325
72 #define W_META_ESCAPE               0x0626
73 #define W_META_RESTOREDC            0x0127
74 #define W_META_FILLREGION           0x0228
75 #define W_META_FRAMEREGION          0x0429
76 #define W_META_INVERTREGION         0x012A
77 #define W_META_PAINTREGION          0x012B
78 #define W_META_SELECTCLIPREGION     0x012C
79 #define W_META_SELECTOBJECT         0x012D
80 #define W_META_SETTEXTALIGN         0x012E
81 #define W_META_DRAWTEXT             0x062F
82 #define W_META_CHORD                0x0830
83 #define W_META_SETMAPPERFLAGS       0x0231
84 #define W_META_EXTTEXTOUT           0x0a32
85 #define W_META_SETDIBTODEV          0x0d33
86 #define W_META_SELECTPALETTE        0x0234
87 #define W_META_REALIZEPALETTE       0x0035
88 #define W_META_ANIMATEPALETTE       0x0436
89 #define W_META_SETPALENTRIES        0x0037
90 #define W_META_POLYPOLYGON          0x0538
91 #define W_META_RESIZEPALETTE        0x0139
92 #define W_META_DIBBITBLT            0x0940
93 #define W_META_DIBSTRETCHBLT        0x0b41
94 #define W_META_DIBCREATEPATTERNBRUSH 0x0142
95 #define W_META_STRETCHDIB           0x0f43
96 #define W_META_EXTFLOODFILL         0x0548
97 #define W_META_RESETDC              0x014C
98 #define W_META_STARTDOC             0x014D
99 #define W_META_STARTPAGE            0x004F
100 #define W_META_ENDPAGE              0x0050
101 #define W_META_ABORTDOC             0x0052
102 #define W_META_ENDDOC               0x005E
103 #define W_META_DELETEOBJECT         0x01f0
104 #define W_META_CREATEPALETTE        0x00f7
105 #define W_META_CREATEBRUSH          0x00F8
106 #define W_META_CREATEPATTERNBRUSH   0x01F9
107 #define W_META_CREATEPENINDIRECT    0x02FA
108 #define W_META_CREATEFONTINDIRECT   0x02FB
109 #define W_META_CREATEBRUSHINDIRECT  0x02FC
110 #define W_META_CREATEBITMAPINDIRECT 0x02FD
111 #define W_META_CREATEBITMAP         0x06FE
112 #define W_META_CREATEREGION         0x06FF
113 
114 //=================== Methoden von WMFReader ==============================
115 
ReadPoint()116 inline Point WMFReader::ReadPoint()
117 {
118     short nX, nY;
119     *pWMF >> nX >> nY;
120     return Point( nX, nY );
121 }
122 
123 // ------------------------------------------------------------------------
124 
ReadYX()125 inline Point WMFReader::ReadYX()
126 {
127     short nX, nY;
128     *pWMF >> nY >> nX;
129     return Point( nX, nY );
130 }
131 
132 // ------------------------------------------------------------------------
133 
ReadRectangle()134 Rectangle WMFReader::ReadRectangle()
135 {
136     Point aBR, aTL;
137     aBR = ReadYX();
138     aTL = ReadYX();
139     aBR.X()--;
140     aBR.Y()--;
141     return Rectangle( aTL, aBR );
142 }
143 
144 // ------------------------------------------------------------------------
145 
ReadYXExt()146 Size WMFReader::ReadYXExt()
147 {
148     short nW, nH;
149     *pWMF >> nH >> nW;
150     return Size( nW, nH );
151 }
152 
153 // ------------------------------------------------------------------------
154 
ReadRecordParams(sal_uInt16 nFunc)155 void WMFReader::ReadRecordParams( sal_uInt16 nFunc )
156 {
157     switch( nFunc )
158     {
159         case W_META_SETBKCOLOR:
160         {
161             pOut->SetBkColor( ReadColor() );
162         }
163         break;
164 
165         case W_META_SETBKMODE:
166         {
167             sal_uInt16 nDat;
168             *pWMF >> nDat;
169             pOut->SetBkMode( nDat );
170         }
171         break;
172 
173         // !!!
174         case W_META_SETMAPMODE:
175         {
176             sal_Int16 nMapMode;
177             *pWMF >> nMapMode;
178             pOut->SetMapMode( nMapMode );
179         }
180         break;
181 
182         case W_META_SETROP2:
183         {
184             sal_uInt16 nROP2;
185             *pWMF >> nROP2;
186             pOut->SetRasterOp( nROP2 );
187         }
188         break;
189 
190         case W_META_SETTEXTCOLOR:
191         {
192             pOut->SetTextColor( ReadColor() );
193         }
194         break;
195 
196         case W_META_SETWINDOWORG:
197         {
198             pOut->SetWinOrg( ReadYX() );
199         }
200         break;
201 
202         case W_META_SETWINDOWEXT:
203         {
204             short nWidth, nHeight;
205             *pWMF >> nHeight >> nWidth;
206             pOut->SetWinExt( Size( nWidth, nHeight ) );
207         }
208         break;
209 
210         case W_META_OFFSETWINDOWORG:
211         {
212             short nXAdd, nYAdd;
213             *pWMF >> nYAdd >> nXAdd;
214             pOut->SetWinOrgOffset( nXAdd, nYAdd );
215         }
216         break;
217 
218         case W_META_SCALEWINDOWEXT:
219         {
220             short nXNum, nXDenom, nYNum, nYDenom;
221             *pWMF >> nYDenom >> nYNum >> nXDenom >> nXNum;
222             pOut->ScaleWinExt( (double)nXNum / nXDenom, (double)nYNum / nYDenom );
223         }
224         break;
225 
226         case W_META_SETVIEWPORTORG:
227         case W_META_SETVIEWPORTEXT:
228         break;
229 
230         case W_META_OFFSETVIEWPORTORG:
231         {
232             short nXAdd, nYAdd;
233             *pWMF >> nYAdd >> nXAdd;
234             pOut->SetDevOrgOffset( nXAdd, nYAdd );
235         }
236         break;
237 
238         case W_META_SCALEVIEWPORTEXT:
239         {
240             short nXNum, nXDenom, nYNum, nYDenom;
241             *pWMF >> nYDenom >> nYNum >> nXDenom >> nXNum;
242             pOut->ScaleDevExt( (double)nXNum / nXDenom, (double)nYNum / nYDenom );
243         }
244         break;
245 
246         case W_META_LINETO:
247         {
248             pOut->LineTo( ReadYX() );
249         }
250         break;
251 
252         case W_META_MOVETO:
253         {
254             pOut->MoveTo( ReadYX() );
255         }
256         break;
257 
258         case W_META_INTERSECTCLIPRECT:
259         {
260             pOut->IntersectClipRect( ReadRectangle() );
261         }
262         break;
263 
264         case W_META_RECTANGLE:
265         {
266             pOut->DrawRect( ReadRectangle() );
267         }
268         break;
269 
270         case W_META_ROUNDRECT:
271         {
272             Size aSize( ReadYXExt() );
273             pOut->DrawRoundRect( ReadRectangle(), Size( aSize.Width() / 2, aSize.Height() / 2 ) );
274         }
275         break;
276 
277         case W_META_ELLIPSE:
278         {
279             pOut->DrawEllipse( ReadRectangle() );
280         }
281         break;
282 
283         case W_META_ARC:
284         {
285             Point aEnd( ReadYX() );
286             Point aStart( ReadYX() );
287             Rectangle aRect( ReadRectangle() );
288             aRect.Justify();
289             pOut->DrawArc( aRect, aStart, aEnd );
290         }
291         break;
292 
293         case W_META_PIE:
294         {
295             Point     aEnd( ReadYX() );
296             Point     aStart( ReadYX() );
297             Rectangle aRect( ReadRectangle() );
298             aRect.Justify();
299 
300             // #i73608# OutputDevice deviates from WMF
301             // semantics. start==end means full ellipse here.
302             if( aStart == aEnd )
303                 pOut->DrawEllipse( aRect );
304             else
305                 pOut->DrawPie( aRect, aStart, aEnd );
306         }
307         break;
308 
309         case W_META_CHORD:
310         {
311             Point aEnd( ReadYX() );
312             Point aStart( ReadYX() );
313             Rectangle aRect( ReadRectangle() );
314             aRect.Justify();
315             pOut->DrawChord( aRect, aStart, aEnd );
316         }
317         break;
318 
319         case W_META_POLYGON:
320         {
321             sal_uInt16 i,nPoints;
322             *pWMF >> nPoints;
323             Polygon aPoly( nPoints );
324             for( i = 0; i < nPoints; i++ )
325                 aPoly[ i ] = ReadPoint();
326             pOut->DrawPolygon( aPoly );
327         }
328         break;
329 
330         case W_META_POLYPOLYGON:
331         {
332             sal_uInt16 nPolyCount(0);
333 
334             // get number of polygons
335             *pWMF >> nPolyCount;
336 
337             if(nPolyCount && !pWMF->IsEof())
338             {
339                 sal_uInt16* pnPoints = new sal_uInt16[nPolyCount];
340                 sal_uInt16 a(0);
341                 PolyPolygon aPolyPoly(nPolyCount, nPolyCount);
342 
343                 for(a = 0; a < nPolyCount && !pWMF->IsEof(); a++)
344                 {
345                     *pWMF >> pnPoints[a];
346                 }
347 
348                 for(a = 0; a < nPolyCount && !pWMF->IsEof(); a++)
349                 {
350                     const sal_uInt16 nPointCount(pnPoints[a]);
351                     Point* pPtAry = new Point[nPointCount];
352 
353                     for(sal_uInt16 b(0); b < nPointCount && !pWMF->IsEof(); b++)
354                     {
355                         pPtAry[b] = ReadPoint();
356                     }
357 
358                     aPolyPoly.Insert(Polygon(nPointCount, pPtAry));
359                     delete[] pPtAry;
360                 }
361 
362                 delete[] pnPoints;
363                 pOut->DrawPolyPolygon(aPolyPoly);
364             }
365         }
366         break;
367 
368         case W_META_POLYLINE:
369         {
370             sal_uInt16 i,nPoints;
371             *pWMF >> nPoints;
372             Polygon aPoly( nPoints );
373             for( i = 0; i < nPoints; i++ )
374                 aPoly[ i ] = ReadPoint();
375             pOut->DrawPolyLine( aPoly );
376         }
377         break;
378 
379         case W_META_SAVEDC:
380         {
381             pOut->Push();
382         }
383         break;
384 
385         case W_META_RESTOREDC:
386         {
387             pOut->Pop();
388         }
389         break;
390 
391         case W_META_SETPIXEL:
392         {
393             const Color aColor = ReadColor();
394             pOut->DrawPixel( ReadYX(), aColor );
395         }
396         break;
397 
398         case W_META_OFFSETCLIPRGN:
399         {
400             pOut->MoveClipRegion( ReadYXExt() );
401         }
402         break;
403 
404         case W_META_TEXTOUT:
405         {
406             sal_uInt16 nLength;
407             *pWMF >> nLength;
408             if ( nLength )
409             {
410                 char*   pChar = new char[ ( nLength + 1 ) &~ 1 ];
411                 pWMF->Read( pChar, ( nLength + 1 ) &~ 1 );
412                 String aText( pChar, nLength, pOut->GetCharSet() );
413                 delete[] pChar;
414                 Point aPosition( ReadYX() );
415                 pOut->DrawText( aPosition, aText );
416             }
417         }
418         break;
419 
420         case W_META_EXTTEXTOUT:
421         {
422             sal_Int16   nDx, nDxTmp;
423             sal_uInt16  i, nLen, nOptions;
424             sal_Int32   nRecordPos, nRecordSize, nOriginalTextLen, nNewTextLen;
425             Point       aPosition;
426             Rectangle   aRect;
427             sal_Int32*  pDXAry = NULL;
428 
429             pWMF->SeekRel(-6);
430             nRecordPos = pWMF->Tell();
431             *pWMF >> nRecordSize;
432             pWMF->SeekRel(2);
433             aPosition = ReadYX();
434             *pWMF >> nLen >> nOptions;
435 
436             sal_Int32 nTextLayoutMode = TEXT_LAYOUT_DEFAULT;
437             if ( nOptions & ETO_RTLREADING )
438                 nTextLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT;
439             pOut->SetTextLayoutMode( nTextLayoutMode );
440             DBG_ASSERT( ( nOptions & ( ETO_PDY | ETO_GLYPH_INDEX ) ) == 0, "SJ: ETO_PDY || ETO_GLYPH_INDEX in WMF" );
441 
442             // Nur wenn der Text auch Zeichen enthaelt, macht die Ausgabe Sinn
443             if( nLen )
444             {
445                 nOriginalTextLen = nLen;
446                 if( nOptions & ETO_CLIPPED )
447                 {
448                     const Point aPt1( ReadPoint() );
449                     const Point aPt2( ReadPoint() );
450                     aRect = Rectangle( aPt1, aPt2 );
451                 }
452                 char* pChar = new char[ ( nOriginalTextLen + 1 ) &~ 1 ];
453                 pWMF->Read( pChar, ( nOriginalTextLen + 1 ) &~ 1 );
454                 String aText( pChar, (sal_uInt16)nOriginalTextLen, pOut->GetCharSet() );// after this conversion the text may contain
455                 nNewTextLen = aText.Len();                                              // less character (japanese version), so the
456                 delete[] pChar;                                                         // dxAry will not fit
457 
458                 if ( nNewTextLen )
459                 {
460                     sal_uInt32  nMaxStreamPos = nRecordPos + ( nRecordSize << 1 );
461                     sal_Int32   nDxArySize =  nMaxStreamPos - pWMF->Tell();
462                     sal_Int32   nDxAryEntries = nDxArySize >> 1;
463                     sal_Bool    bUseDXAry = sal_False;
464 
465                     if ( ( ( nDxAryEntries % nOriginalTextLen ) == 0 ) && ( nNewTextLen <= nOriginalTextLen ) )
466                     {
467                         pDXAry = new sal_Int32[ nNewTextLen ];
468                         for ( i = 0; i < nNewTextLen; i++ )
469                         {
470                             if ( pWMF->Tell() >= nMaxStreamPos )
471                                 break;
472                             *pWMF >> nDx;
473                             if ( nNewTextLen != nOriginalTextLen )
474                             {
475                                 ByteString aTmp( aText.GetChar( i ), pOut->GetCharSet() );
476                                 if ( aTmp.Len() > 1 )
477                                 {
478                                     sal_Int32 nDxCount = aTmp.Len() - 1;
479                                     if ( ( ( nDxCount * 2 ) + pWMF->Tell() ) > nMaxStreamPos )
480                                         break;
481                                     while ( nDxCount-- )
482                                     {
483                                         *pWMF >> nDxTmp;
484                                         nDx = nDx + nDxTmp;
485                                     }
486                                 }
487                             }
488                             pDXAry[ i ] = nDx;
489                         }
490                         if ( i == nNewTextLen )
491                             bUseDXAry = sal_True;
492                     }
493                     if ( pDXAry && bUseDXAry )
494                         pOut->DrawText( aPosition, aText, pDXAry );
495                     else
496                         pOut->DrawText( aPosition, aText );
497                 }
498             }
499             delete[] pDXAry;
500 
501         }
502         break;
503 
504         case W_META_SELECTOBJECT:
505         {
506             sal_Int16   nObjIndex;
507             *pWMF >> nObjIndex;
508             pOut->SelectObject( nObjIndex );
509         }
510         break;
511 
512         case W_META_SETTEXTALIGN:
513         {
514             sal_uInt16  nAlign;
515             *pWMF >> nAlign;
516             pOut->SetTextAlign( nAlign );
517         }
518         break;
519 
520         case W_META_BITBLT:
521         {
522             // 0-3   : nWinROP                      #93454#
523             // 4-5   : y offset of source bitmap
524             // 6-7   : x offset of source bitmap
525             // 8-9   : used height of source bitmap
526             // 10-11 : used width  of source bitmap
527             // 12-13 : destination position y (in pixel)
528             // 14-15 : destination position x (in pixel)
529             // 16-17 : dont know
530             // 18-19 : Width Bitmap in Pixel
531             // 20-21 : Height Bitmap in Pixel
532             // 22-23 : bytes per scanline
533             // 24    : planes
534             // 25    : bitcount
535 
536             sal_Int32   nWinROP;
537             sal_uInt16  nSx, nSy, nSxe, nSye, nDontKnow, nWidth, nHeight, nBytesPerScan;
538             sal_uInt8   nPlanes, nBitCount;
539 
540             *pWMF >> nWinROP
541                   >> nSy >> nSx >> nSye >> nSxe;
542             Point aPoint( ReadYX() );
543             *pWMF >> nDontKnow >> nWidth >> nHeight >> nBytesPerScan >> nPlanes >> nBitCount;
544 
545             if ( nWidth && nHeight && ( nPlanes == 1 ) && ( nBitCount == 1 ) )
546             {
547                 Bitmap aBmp( Size( nWidth, nHeight ), nBitCount );
548                 BitmapWriteAccess* pAcc;
549                 pAcc = aBmp.AcquireWriteAccess();
550                 if ( pAcc )
551                 {
552                     sal_uInt16 y, x, scan;
553                     sal_Int8 i, nEightPixels;
554                     for ( y = 0; y < nHeight; y++ )
555                     {
556                         x = 0;
557                         for ( scan = 0; scan < nBytesPerScan; scan++ )
558                         {
559                             *pWMF >> nEightPixels;
560                             for ( i = 7; i >= 0; i-- )
561                             {
562                                 if ( x < nWidth )
563                                 {
564                                     pAcc->SetPixelIndex( y, x, (nEightPixels>>i)&1 );
565                                 }
566                                 x++;
567                             }
568                         }
569                     }
570                     aBmp.ReleaseAccess( pAcc );
571                     if ( nSye && nSxe &&
572                         ( ( nSx + nSxe ) <= aBmp.GetSizePixel().Width() ) &&
573                             ( ( nSy + nSye <= aBmp.GetSizePixel().Height() ) ) )
574                     {
575                         Rectangle aCropRect( Point( nSx, nSy ), Size( nSxe, nSye ) );
576                         aBmp.Crop( aCropRect );
577                     }
578                     Rectangle aDestRect( aPoint, Size( nSxe, nSye ) );
579                     aBmpSaveList.Insert( new BSaveStruct( aBmp, aDestRect, nWinROP ), LIST_APPEND );
580                 }
581             }
582         }
583         break;
584 
585         case W_META_STRETCHBLT:
586         case W_META_DIBBITBLT:
587         case W_META_DIBSTRETCHBLT:
588         case W_META_STRETCHDIB:
589         {
590             sal_Int32   nWinROP;
591             sal_uInt16  nSx, nSy, nSxe, nSye, nUsage;
592             Bitmap      aBmp;
593 
594             *pWMF >> nWinROP;
595 
596             if( nFunc == W_META_STRETCHDIB )
597                 *pWMF >> nUsage;
598 
599             // nSye and nSxe is the number of pixels that has to been used
600             if( nFunc == W_META_STRETCHDIB || nFunc == W_META_STRETCHBLT || nFunc == W_META_DIBSTRETCHBLT )
601                 *pWMF >> nSye >> nSxe;
602             else
603                 nSye = nSxe = 0;    // set this to zero as indicator not to scale the bitmap later
604 
605             // nSy and nx is the offset of the first pixel
606             *pWMF >> nSy >> nSx;
607 
608             if( nFunc == W_META_STRETCHDIB || nFunc == W_META_DIBBITBLT || nFunc == W_META_DIBSTRETCHBLT )
609             {
610                 if ( nWinROP == PATCOPY )
611                     *pWMF >> nUsage;    // i don't know anything of this parameter, so its called nUsage
612                                         // pOut->DrawRect( Rectangle( ReadYX(), aDestSize ), sal_False );
613 
614                 Size aDestSize( ReadYXExt() );
615                 if ( aDestSize.Width() && aDestSize.Height() )  // #92623# do not try to read buggy bitmaps
616                 {
617                     Rectangle aDestRect( ReadYX(), aDestSize );
618                     if ( nWinROP != PATCOPY )
619                         ReadDIB(aBmp, *pWMF, false);
620 
621                     // test if it is sensible to crop
622                     if ( nSye && nSxe &&
623                         ( ( nSx + nSxe ) <= aBmp.GetSizePixel().Width() ) &&
624                             ( ( nSy + nSye <= aBmp.GetSizePixel().Height() ) ) )
625                     {
626                         Rectangle aCropRect( Point( nSx, nSy ), Size( nSxe, nSye ) );
627                         aBmp.Crop( aCropRect );
628                     }
629                     aBmpSaveList.Insert( new BSaveStruct( aBmp, aDestRect, nWinROP ), LIST_APPEND );
630                 }
631             }
632         }
633         break;
634 
635         case W_META_DIBCREATEPATTERNBRUSH:
636         {
637             Bitmap  aBmp;
638             BitmapReadAccess* pBmp;
639             sal_uInt32  nRed = 0, nGreen = 0, nBlue = 0, nCount = 1;
640             sal_uInt16  nFunction;
641 
642             *pWMF >> nFunction >> nFunction;
643 
644             ReadDIB(aBmp, *pWMF, false);
645             pBmp = aBmp.AcquireReadAccess();
646             if ( pBmp )
647             {
648                 for ( sal_Int32 y = 0; y < pBmp->Height(); y++ )
649                 {
650                     for ( sal_Int32 x = 0; x < pBmp->Width(); x++ )
651                     {
652                         const BitmapColor aColor( pBmp->GetColor( y, x ) );
653 
654                         nRed += aColor.GetRed();
655                         nGreen += aColor.GetGreen();
656                         nBlue += aColor.GetBlue();
657                     }
658                 }
659                 nCount = pBmp->Height() * pBmp->Width();
660                 if ( !nCount )
661                     nCount++;
662                 aBmp.ReleaseAccess( pBmp );
663             }
664             Color aColor( (sal_uInt8)( nRed / nCount ), (sal_uInt8)( nGreen / nCount ), (sal_uInt8)( nBlue / nCount ) );
665             pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( aColor, sal_False ) );
666         }
667         break;
668 
669         case W_META_DELETEOBJECT:
670         {
671             sal_Int16 nIndex;
672             *pWMF >> nIndex;
673             pOut->DeleteObject( nIndex );
674         }
675         break;
676 
677         case W_META_CREATEPALETTE:
678         {
679             pOut->CreateObject( GDI_DUMMY );
680         }
681         break;
682 
683         case W_META_CREATEBRUSH:
684         {
685             pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ), sal_False ) );
686         }
687         break;
688 
689         case W_META_CREATEPATTERNBRUSH:
690         {
691             pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ), sal_False ) );
692         }
693         break;
694 
695         case W_META_CREATEPENINDIRECT:
696         {
697             LineInfo    aLineInfo;
698             sal_uInt16      nStyle, nWidth, nHeight;
699 
700             *pWMF >> nStyle >> nWidth >> nHeight;
701 
702             if ( nWidth )
703                 aLineInfo.SetWidth( nWidth );
704 
705             sal_Bool bTransparent = sal_False;
706             sal_uInt16 nDashCount = 0;
707             sal_uInt16 nDotCount = 0;
708             switch( nStyle )
709             {
710                 case PS_DASHDOTDOT :
711                     nDotCount++;
712                 case PS_DASHDOT :
713                     nDashCount++;
714                 case PS_DOT :
715                     nDotCount++;
716                 break;
717                 case PS_DASH :
718                     nDashCount++;
719                 break;
720                 case PS_NULL :
721                     bTransparent = sal_True;
722                     aLineInfo.SetStyle( LINE_NONE );
723                 break;
724                 default :
725                 case PS_INSIDEFRAME :
726                 case PS_SOLID :
727                     aLineInfo.SetStyle( LINE_SOLID );
728             }
729             if ( nDashCount | nDotCount )
730             {
731                 aLineInfo.SetStyle( LINE_DASH );
732                 aLineInfo.SetDashCount( nDashCount );
733                 aLineInfo.SetDotCount( nDotCount );
734             }
735             pOut->CreateObject( GDI_PEN, new WinMtfLineStyle( ReadColor(), aLineInfo, bTransparent ) );
736         }
737         break;
738 
739         case W_META_CREATEBRUSHINDIRECT:
740         {
741             sal_uInt16  nStyle;
742             *pWMF >> nStyle;
743             pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( ReadColor(), ( nStyle == BS_HOLLOW ) ? sal_True : sal_False ) );
744         }
745         break;
746 
747         case W_META_CREATEFONTINDIRECT:
748         {
749             Size    aFontSize;
750             char    lfFaceName[ LF_FACESIZE ];
751             sal_Int16   lfEscapement, lfOrientation, lfWeight;  // ( ehemals sal_uInt16 )
752 
753             LOGFONTW aLogFont;
754             aFontSize = ReadYXExt();
755             *pWMF >> lfEscapement >> lfOrientation >> lfWeight
756                     >> aLogFont.lfItalic >> aLogFont.lfUnderline >> aLogFont.lfStrikeOut >> aLogFont.lfCharSet >> aLogFont.lfOutPrecision
757                         >> aLogFont.lfClipPrecision >> aLogFont.lfQuality >> aLogFont.lfPitchAndFamily;
758             pWMF->Read( lfFaceName, LF_FACESIZE );
759             aLogFont.lfWidth = aFontSize.Width();
760             aLogFont.lfHeight = aFontSize.Height();
761             aLogFont.lfEscapement = lfEscapement;
762             aLogFont.lfOrientation = lfOrientation;
763             aLogFont.lfWeight = lfWeight;
764 
765             CharSet eCharSet;
766             if ( ( aLogFont.lfCharSet == OEM_CHARSET ) || ( aLogFont.lfCharSet == DEFAULT_CHARSET ) )
767                 eCharSet = gsl_getSystemTextEncoding();
768             else
769                 eCharSet = rtl_getTextEncodingFromWindowsCharset( aLogFont.lfCharSet );
770             if ( eCharSet == RTL_TEXTENCODING_DONTKNOW )
771                 eCharSet = gsl_getSystemTextEncoding();
772             if ( eCharSet == RTL_TEXTENCODING_SYMBOL )
773                 eCharSet = RTL_TEXTENCODING_MS_1252;
774             aLogFont.alfFaceName = UniString( lfFaceName, eCharSet );
775 
776             pOut->CreateObject( GDI_FONT, new WinMtfFontStyle( aLogFont ) );
777         }
778         break;
779 
780         case W_META_CREATEBITMAPINDIRECT:
781         {
782             pOut->CreateObject( GDI_DUMMY );
783         }
784         break;
785 
786         case W_META_CREATEBITMAP:
787         {
788             pOut->CreateObject( GDI_DUMMY );
789         }
790         break;
791 
792         case W_META_CREATEREGION:
793         {
794             pOut->CreateObject( GDI_DUMMY );
795         }
796         break;
797 
798         case W_META_EXCLUDECLIPRECT :
799         {
800             pOut->ExcludeClipRect( ReadRectangle() );
801         }
802         break;
803 
804         case W_META_PATBLT:
805         {
806             sal_uInt32 nROP, nOldROP;
807             *pWMF >> nROP;
808             Size aSize = ReadYXExt();
809             nOldROP = pOut->SetRasterOp( nROP );
810             pOut->DrawRect( Rectangle( ReadYX(), aSize ), sal_False );
811             pOut->SetRasterOp( nOldROP );
812         }
813         break;
814 
815         case W_META_SELECTCLIPREGION:
816         {
817             sal_Int16 nObjIndex;
818             *pWMF >> nObjIndex;
819             if ( !nObjIndex )
820             {
821                 PolyPolygon aEmptyPolyPoly;
822                 pOut->SetClipPath( aEmptyPolyPoly, RGN_COPY, sal_True );
823             }
824         }
825         break;
826 
827         case W_META_ESCAPE :
828         {
829             // nRecSize has been checked previously to be greater than 3
830             sal_uInt64 nMetaRecSize = static_cast< sal_uInt64 >( nRecSize - 2 ) * 2;
831             sal_uInt64 nMetaRecEndPos = pWMF->Tell() + nMetaRecSize;
832 
833             // taking care that nRecSize does not exceed the maximal stream position
834             if ( nMetaRecEndPos > nEndPos )
835             {
836                 pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
837                 break;
838             }
839             if ( nRecSize >= 4 )    // minimal escape lenght
840             {
841                 sal_uInt16  nMode, nLen;
842                 *pWMF >> nMode
843                       >> nLen;
844                 if ( ( nMode == W_MFCOMMENT ) && ( nLen >= 4 ) )
845                 {
846                     sal_uInt32 nNewMagic; // we have to read int32 for
847                     *pWMF >> nNewMagic;   // META_ESCAPE_ENHANCED_METAFILE CommentIdentifier
848 
849                     if( nNewMagic == 0x2c2a4f4f &&  nLen >= 14 )
850                     {
851                         sal_uInt16 nMagic2;
852                         *pWMF >> nMagic2;
853                         if( nMagic2 == 0x0a ) // 2nd half of magic
854                         {                     // continue with private escape
855                             sal_uInt32 nCheck, nEsc;
856                             *pWMF >> nCheck
857                                   >> nEsc;
858 
859                             sal_uInt32 nEscLen = nLen - 14;
860                             if ( nEscLen <= ( nRecSize * 2 ) )
861                             {
862 #ifdef OSL_BIGENDIAN
863                                 sal_uInt32 nTmp = SWAPLONG( nEsc );
864                                 sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 );
865 #else
866                                 sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 );
867 #endif
868                                 sal_Int8* pData = NULL;
869 
870                                 if ( ( static_cast< sal_uInt64 >( nEscLen ) + pWMF->Tell() ) > nMetaRecEndPos )
871                                 {
872                                     pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
873                                     break;
874                                 }
875                                 if ( nEscLen > 0 )
876                                 {
877                                     pData = new sal_Int8[ nEscLen ];
878                                     pWMF->Read( pData, nEscLen );
879                                     nCheckSum = rtl_crc32( nCheckSum, pData, nEscLen );
880                                 }
881                                 if ( nCheck == nCheckSum )
882                                 {
883                                     switch( nEsc )
884                                     {
885                                         case PRIVATE_ESCAPE_UNICODE :
886                                         {
887                                             // we will use text instead of polygons only if we have the correct font
888                                             if ( Application::GetDefaultDevice()->IsFontAvailable( pOut->GetFont().GetName() ) )
889                                             {
890                                                 Point  aPt;
891                                                 String aString;
892                                                 sal_uInt32  i, nStringLen, nDXCount;
893                                                 sal_Int32* pDXAry = NULL;
894                                                 SvMemoryStream aMemoryStream( nEscLen );
895                                                 aMemoryStream.Write( pData, nEscLen );
896                                                 aMemoryStream.Seek( STREAM_SEEK_TO_BEGIN );
897                                                 aMemoryStream >> aPt.X()
898                                                               >> aPt.Y()
899                                                               >> nStringLen;
900 
901                                                 // AllocBuffer takes an xub_StrLen
902                                                 if ( nStringLen >= STRING_MAXLEN )
903                                                     break;
904 
905                                                 if ( ( static_cast< sal_uInt64 >( nStringLen ) * sizeof( sal_Unicode ) ) < ( nEscLen - aMemoryStream.Tell() ) )
906                                                 {
907                                                     sal_Unicode* pBuf = aString.AllocBuffer( (xub_StrLen)nStringLen );
908                                                     for ( i = 0; i < nStringLen; i++ )
909                                                         aMemoryStream >> pBuf[ i ];
910                                                     aMemoryStream >> nDXCount;
911                                                     if ( ( static_cast< sal_uInt64 >( nDXCount ) * sizeof( sal_Int32 ) ) >= ( nEscLen - aMemoryStream.Tell() ) )
912                                                         nDXCount = 0;
913                                                     // one advance per character; ignore a shorter array
914                                                     if ( nDXCount && ( nDXCount < nStringLen ) )
915                                                         nDXCount = 0;
916                                                     if ( nDXCount )
917                                                         pDXAry = new sal_Int32[ nDXCount ];
918                                                     for  ( i = 0; i < nDXCount; i++ )
919                                                         aMemoryStream >> pDXAry[ i ];
920                                                     aMemoryStream >> nSkipActions;
921                                                     pOut->DrawText( aPt, aString, pDXAry );
922                                                     delete[] pDXAry;
923                                                 }
924                                             }
925                                         }
926                                         break;
927                                     }
928                                 }
929                                 delete[] pData;
930                             }
931                         }
932                     }
933                     else if ( (nNewMagic == static_cast< sal_uInt32 >(0x43464D57)) && (nLen >= 34) && ( (sal_Int32)(nLen + 10) <= (sal_Int32)(nRecSize * 2) ))
934                     {
935                         sal_uInt32 nComType, nVersion, nFlags, nComRecCount,
936                                    nCurRecSize, nRemainingSize, nEMFTotalSize;
937                         sal_uInt16 nCheck;
938 
939                         *pWMF >> nComType >> nVersion >> nCheck >> nFlags
940                               >> nComRecCount >> nCurRecSize
941                               >> nRemainingSize >> nEMFTotalSize; // the nRemainingSize is not mentioned in MSDN documentation
942                                                                   // but it seems to be required to read in data produced by OLE
943 
944                         if( nComType == 0x01 && nVersion == 0x10000 && nComRecCount )
945                         {
946                             if( !nEMFRec )
947                             {   // first EMF comment
948                                 nEMFRecCount    = nComRecCount;
949                                 nEMFSize        = nEMFTotalSize;
950                                 pEMFStream = new SvMemoryStream( nEMFSize );
951                             }
952                             else if( ( nEMFRecCount != nComRecCount ) || ( nEMFSize != nEMFTotalSize ) ) // add additional checks here
953                             {
954                                 // total records should be the same as in previous comments
955                                 nEMFRecCount = 0xFFFFFFFF;
956                                 delete pEMFStream;
957                                 pEMFStream = NULL;
958                             }
959                             nEMFRec++;
960 
961                             if( pEMFStream && nCurRecSize + 34 > nLen )
962                             {
963                                 nEMFRecCount = 0xFFFFFFFF;
964                                 delete pEMFStream;
965                                 pEMFStream = NULL;
966                             }
967 
968                             if( pEMFStream )
969                             {
970                                 sal_Int8* pBuf = new sal_Int8[ nCurRecSize ];
971                                 sal_uInt32 nCount = pWMF->Read( pBuf, nCurRecSize );
972                                 if( nCount == nCurRecSize )
973                                     pEMFStream->Write( pBuf, nCount );
974                                 delete[] pBuf;
975                             }
976                         }
977                     }
978                 }
979             }
980         }
981         break;
982 
983         case W_META_SETRELABS:
984         case W_META_SETPOLYFILLMODE:
985         case W_META_SETSTRETCHBLTMODE:
986         case W_META_SETTEXTCHAREXTRA:
987         case W_META_SETTEXTJUSTIFICATION:
988         case W_META_FLOODFILL :
989         case W_META_FILLREGION:
990         case W_META_FRAMEREGION:
991         case W_META_INVERTREGION:
992         case W_META_PAINTREGION:
993         case W_META_DRAWTEXT:
994         case W_META_SETMAPPERFLAGS:
995         case W_META_SETDIBTODEV:
996         case W_META_SELECTPALETTE:
997         case W_META_REALIZEPALETTE:
998         case W_META_ANIMATEPALETTE:
999         case W_META_SETPALENTRIES:
1000         case W_META_RESIZEPALETTE:
1001         case W_META_EXTFLOODFILL:
1002         case W_META_RESETDC:
1003         case W_META_STARTDOC:
1004         case W_META_STARTPAGE:
1005         case W_META_ENDPAGE:
1006         case W_META_ABORTDOC:
1007         case W_META_ENDDOC:
1008         break;
1009     }
1010 }
1011 
1012 // ------------------------------------------------------------------------
1013 
ReadHeader()1014 sal_Bool WMFReader::ReadHeader()
1015 {
1016     Rectangle   aPlaceableBound;
1017     sal_uInt32  nl, nStrmPos = pWMF->Tell();
1018 
1019     // Einlesen des METAFILEHEADER, falls vorhanden
1020     *pWMF >> nl;
1021 
1022     Size aWMFSize;
1023     if ( nl == 0x9ac6cdd7L )
1024     {
1025         sal_Int16 nVal;
1026 
1027         // hmf (Unused) ueberlesen wir
1028         pWMF->SeekRel(2);
1029 
1030         // BoundRect
1031         *pWMF >> nVal; aPlaceableBound.Left() = nVal;
1032         *pWMF >> nVal; aPlaceableBound.Top() = nVal;
1033         *pWMF >> nVal; aPlaceableBound.Right() = nVal;
1034         *pWMF >> nVal; aPlaceableBound.Bottom() = nVal;
1035 
1036         // inch
1037         *pWMF >> nUnitsPerInch;
1038 
1039         // reserved
1040         pWMF->SeekRel( 4 );
1041 
1042         // checksum  pruefen wir lieber nicht
1043         pWMF->SeekRel( 2 );
1044     }
1045     else
1046     {
1047         nUnitsPerInch = 96;
1048         pWMF->Seek( nStrmPos + 18 );    // set the streampos to the start of the metaactions
1049         GetPlaceableBound( aPlaceableBound, pWMF );
1050         pWMF->Seek( nStrmPos );
1051     }
1052 
1053     pOut->SetWinOrg( aPlaceableBound.TopLeft() );
1054     aWMFSize = Size( labs( aPlaceableBound.GetWidth() ), labs( aPlaceableBound.GetHeight() ) );
1055     pOut->SetWinExt( aWMFSize );
1056 
1057     Size aDevExt( 10000, 10000 );
1058     if( ( labs( aWMFSize.Width() ) > 1 ) && ( labs( aWMFSize.Height() ) > 1 ) )
1059     {
1060         const Fraction  aFrac( 1, nUnitsPerInch );
1061         MapMode         aWMFMap( MAP_INCH, Point(), aFrac, aFrac );
1062         Size            aSize100( OutputDevice::LogicToLogic( aWMFSize, aWMFMap, MAP_100TH_MM ) );
1063         aDevExt = Size( labs( aSize100.Width() ), labs( aSize100.Height() ) );
1064     }
1065     pOut->SetDevExt( aDevExt );
1066 
1067     // Einlesen des METAHEADER
1068     *pWMF >> nl; // Typ und Headergroesse
1069 
1070     if( nl != 0x00090001 )
1071     {
1072         pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
1073         return sal_False;
1074     }
1075 
1076     pWMF->SeekRel( 2 ); // Version (von Windows)
1077     pWMF->SeekRel( 4 ); // Size (der Datei in Words)
1078     pWMF->SeekRel( 2 ); // NoObjects (Maximale Anzahl der gleichzeitigen Objekte)
1079     pWMF->SeekRel( 4 ); // MaxRecord (Groesse des groessten Records in Words)
1080     pWMF->SeekRel( 2 ); // NoParameters (Unused
1081 
1082     return sal_True;
1083 }
1084 
ReadWMF()1085 void WMFReader::ReadWMF()
1086 {
1087     sal_uInt16  nFunction;
1088     sal_uLong   nPos, nPercent, nLastPercent;
1089 
1090     nSkipActions = 0;
1091     nCurrentAction = 0;
1092     nUnicodeEscapeAction = 0;
1093 
1094     pEMFStream      = NULL;
1095     nEMFRecCount    = 0;
1096     nEMFRec         = 0;
1097     nEMFSize        = 0;
1098 
1099     sal_Bool bEMFAvailable = sal_False;
1100 
1101     pOut->SetMapMode( MM_ANISOTROPIC );
1102     pOut->SetWinOrg( Point() );
1103     pOut->SetWinExt( Size( 1, 1 ) );
1104     pOut->SetDevExt( Size( 10000, 10000 ) );
1105 
1106     nEndPos=pWMF->Seek( STREAM_SEEK_TO_END );
1107     pWMF->Seek( nStartPos );
1108     Callback( (sal_uInt16) ( nLastPercent = 0 ) );
1109 
1110     if ( ReadHeader() )
1111     {
1112 
1113         nPos = pWMF->Tell();
1114 
1115         if( nEndPos - nStartPos )
1116         {
1117             while( sal_True )
1118             {
1119                 nCurrentAction++;
1120                 nPercent = ( nPos - nStartPos ) * 100 / ( nEndPos - nStartPos );
1121 
1122                 if( nLastPercent + 4 <= nPercent )
1123                 {
1124                     Callback( (sal_uInt16) nPercent );
1125                     nLastPercent = nPercent;
1126                 }
1127                 *pWMF >> nRecSize >> nFunction;
1128 
1129                 if( pWMF->GetError() || ( nRecSize < 3 ) || ( nRecSize==3 && nFunction==0 ) || pWMF->IsEof() )
1130                 {
1131 
1132                     if( pWMF->IsEof() )
1133                         pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
1134 
1135                     break;
1136                 }
1137                 if ( !bEMFAvailable )
1138                 {
1139                     if( aBmpSaveList.Count() &&
1140                         ( nFunction != W_META_STRETCHDIB ) &&
1141                         ( nFunction != W_META_DIBBITBLT ) &&
1142                         ( nFunction != W_META_DIBSTRETCHBLT ) )
1143                     {
1144                         pOut->ResolveBitmapActions( aBmpSaveList );
1145                     }
1146                     if ( !nSkipActions )
1147                         ReadRecordParams( nFunction );
1148                     else
1149                         nSkipActions--;
1150 
1151                     if( pEMFStream && nEMFRecCount == nEMFRec )
1152                     {
1153                         GDIMetaFile aMeta;
1154                         pEMFStream->Seek( 0 );
1155                         EnhWMFReader* pEMFReader = new EnhWMFReader ( *pEMFStream, aMeta );
1156                         bEMFAvailable = pEMFReader->ReadEnhWMF();
1157                         delete pEMFReader; // destroy first!!!
1158 
1159                         if( bEMFAvailable )
1160                         {
1161                             pOut->AddFromGDIMetaFile( aMeta );
1162                             pOut->SetrclFrame( Rectangle(0, 0, aMeta.GetPrefSize().Width(), aMeta.GetPrefSize().Height() ));
1163 
1164                             // the stream needs to be set to the wmf end position,
1165                             // otherwise the GfxLink that is created will be incorrect
1166                             // (leading to graphic loss after swapout/swapin).
1167                             // so we will proceed normally, but are ignoring further wmf
1168                             // records
1169                         }
1170                         else
1171                         {
1172                             // something went wrong
1173                             // continue with WMF, don't try this again
1174                             delete pEMFStream;
1175                             pEMFStream = NULL;
1176                         }
1177                     }
1178                 }
1179                 nPos += nRecSize * 2;
1180                 if ( nPos <= nEndPos )
1181                     pWMF->Seek( nPos  );
1182                 else
1183                     pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
1184             }
1185         }
1186         else
1187             pWMF->SetError( SVSTREAM_GENERALERROR );
1188 
1189         if( !pWMF->GetError() && aBmpSaveList.Count() )
1190             pOut->ResolveBitmapActions( aBmpSaveList );
1191     }
1192     if ( pWMF->GetError() )
1193         pWMF->Seek( nStartPos );
1194 }
1195 
1196 // ------------------------------------------------------------------------
1197 
GetWinExtMax(const Point & rSource,Rectangle & rPlaceableBound,const sal_Int16 nMapMode)1198 static void GetWinExtMax( const Point& rSource, Rectangle& rPlaceableBound, const sal_Int16 nMapMode )
1199 {
1200     Point aSource( rSource );
1201     if ( nMapMode == MM_HIMETRIC )
1202         aSource.Y() = -rSource.Y();
1203     if ( aSource.X() < rPlaceableBound.Left() )
1204         rPlaceableBound.Left() = aSource.X();
1205     if ( aSource.X() > rPlaceableBound.Right() )
1206         rPlaceableBound.Right() = aSource.X();
1207     if ( aSource.Y() < rPlaceableBound.Top() )
1208         rPlaceableBound.Top() = aSource.Y();
1209     if ( aSource.Y() > rPlaceableBound.Bottom() )
1210         rPlaceableBound.Bottom() = aSource.Y();
1211 }
1212 
GetWinExtMax(const Rectangle & rSource,Rectangle & rPlaceableBound,const sal_Int16 nMapMode)1213 static void GetWinExtMax( const Rectangle& rSource, Rectangle& rPlaceableBound, const sal_Int16 nMapMode )
1214 {
1215     GetWinExtMax( rSource.TopLeft(), rPlaceableBound, nMapMode );
1216     GetWinExtMax( rSource.BottomRight(), rPlaceableBound, nMapMode );
1217 }
1218 
GetPlaceableBound(Rectangle & rPlaceableBound,SvStream * pStm)1219 sal_Bool WMFReader::GetPlaceableBound( Rectangle& rPlaceableBound, SvStream* pStm )
1220 {
1221     sal_Bool bRet = sal_True;
1222 
1223     rPlaceableBound.Left()   = (sal_Int32)0x7fffffff;
1224     rPlaceableBound.Top()    = (sal_Int32)0x7fffffff;
1225     rPlaceableBound.Right()  = (sal_Int32)0x80000000;
1226     rPlaceableBound.Bottom() = (sal_Int32)0x80000000;
1227 
1228     sal_Int16 nMapMode = MM_ANISOTROPIC;
1229 
1230     sal_uInt16 nFunction;
1231     sal_uInt32 nRSize;
1232     sal_uInt32 nPos = pStm->Tell();
1233     sal_uInt32 nEnd = pStm->Seek( STREAM_SEEK_TO_END );
1234 
1235     pStm->Seek( nPos );
1236 
1237     if( nEnd - nPos )
1238     {
1239         while( bRet )
1240         {
1241             *pStm >> nRSize >> nFunction;
1242 
1243             if( pStm->GetError() || ( nRSize < 3 ) || ( nRSize==3 && nFunction==0 ) || pStm->IsEof() )
1244             {
1245                 if( pStm->IsEof() )
1246                 {
1247                     pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1248                     bRet = sal_False;
1249                 }
1250                 break;
1251             }
1252             switch( nFunction )
1253             {
1254                 case W_META_SETWINDOWORG:
1255                 {
1256                     Point aWinOrg;
1257                     aWinOrg = ReadYX();
1258                     rPlaceableBound.SetPos( aWinOrg );
1259                 }
1260                 break;
1261 
1262                 case W_META_SETWINDOWEXT:
1263                 {
1264                     Point aPos0( 0, 0 );
1265                     sal_Int16 nWidth, nHeight;
1266                     *pStm >> nHeight >> nWidth;
1267                     rPlaceableBound.SetSize( Size( nWidth, nHeight ) );
1268                 }
1269                 break;
1270 
1271                 case W_META_SETMAPMODE :
1272                     *pStm >> nMapMode;
1273                 break;
1274 
1275                 case W_META_MOVETO:
1276                 case W_META_LINETO:
1277                     GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode );
1278                 break;
1279 
1280                 case W_META_RECTANGLE:
1281                 case W_META_INTERSECTCLIPRECT:
1282                 case W_META_EXCLUDECLIPRECT :
1283                 case W_META_ELLIPSE:
1284                     GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode );
1285                 break;
1286 
1287                 case W_META_ROUNDRECT:
1288                 {
1289                     Size aSize( ReadYXExt() );
1290                     GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode );
1291                 }
1292                 break;
1293 
1294                 case W_META_ARC:
1295                 case W_META_PIE:
1296                 case W_META_CHORD:
1297                 {
1298                     Point aEnd( ReadYX() );
1299                     Point aStart( ReadYX() );
1300                     GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode );
1301                 }
1302                 break;
1303 
1304                 case W_META_POLYGON:
1305                 {
1306                     sal_uInt16 i,nPoints;
1307                     *pStm >> nPoints;
1308                     for( i = 0; i < nPoints; i++ )
1309                         GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode );
1310                 }
1311                 break;
1312 
1313                 case W_META_POLYPOLYGON:
1314                 {
1315                     sal_uInt16  i, nPoly, nPoints = 0;
1316                     *pStm >> nPoly;
1317                     for( i = 0; i < nPoly; i++ )
1318                     {
1319                         sal_uInt16 nP;
1320                         *pStm >> nP;
1321                         nPoints = nPoints + nP;
1322                     }
1323                     for ( i = 0; i < nPoints; i++ )
1324                         GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode );
1325                 }
1326                 break;
1327 
1328                 case W_META_POLYLINE:
1329                 {
1330                     sal_uInt16 i,nPoints;
1331                     *pStm >> nPoints;
1332                     for( i = 0; i < nPoints; i++ )
1333                         GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode );
1334                 }
1335                 break;
1336 
1337                 case W_META_SETPIXEL:
1338                 {
1339                     const Color aColor = ReadColor();
1340                     GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode );
1341                 }
1342                 break;
1343 
1344                 case W_META_TEXTOUT:
1345                 {
1346                     sal_uInt16 nLength;
1347                     *pStm >> nLength;
1348                     // todo: we also have to take care of the text width
1349                     if ( nLength )
1350                     {
1351                         pStm->SeekRel( ( nLength + 1 ) &~ 1 );
1352                         GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode );
1353                     }
1354                 }
1355                 break;
1356 
1357                 case W_META_EXTTEXTOUT:
1358                 {
1359                     sal_uInt16  nLen, nOptions;
1360                     sal_Int32   nRecordPos, nRecordSize;
1361                     Point       aPosition;
1362                     Rectangle   aRect;
1363 
1364                     pStm->SeekRel(-6);
1365                     nRecordPos = pStm->Tell();
1366                     *pStm >> nRecordSize;
1367                     pStm->SeekRel(2);
1368                     aPosition = ReadYX();
1369                     *pStm >> nLen >> nOptions;
1370                     // todo: we also have to take care of the text width
1371                     if( nLen )
1372                         GetWinExtMax( aPosition, rPlaceableBound, nMapMode );
1373                 }
1374                 break;
1375                 case W_META_BITBLT:
1376                 case W_META_STRETCHBLT:
1377                 case W_META_DIBBITBLT:
1378                 case W_META_DIBSTRETCHBLT:
1379                 case W_META_STRETCHDIB:
1380                 {
1381                     sal_Int32   nWinROP;
1382                     sal_uInt16  nSx, nSy, nSxe, nSye, nUsage;
1383                     *pStm >> nWinROP;
1384 
1385                     if( nFunction == W_META_STRETCHDIB )
1386                         *pStm >> nUsage;
1387 
1388                     // nSye and nSxe is the number of pixels that has to been used
1389                     if( nFunction == W_META_STRETCHDIB || nFunction == W_META_STRETCHBLT || nFunction == W_META_DIBSTRETCHBLT )
1390                         *pStm >> nSye >> nSxe;
1391                     else
1392                         nSye = nSxe = 0;    // set this to zero as indicator not to scale the bitmap later
1393 
1394                     // nSy and nx is the offset of the first pixel
1395                     *pStm >> nSy >> nSx;
1396 
1397                     if( nFunction == W_META_STRETCHDIB || nFunction == W_META_DIBBITBLT || nFunction == W_META_DIBSTRETCHBLT )
1398                     {
1399                         if ( nWinROP == PATCOPY )
1400                             *pStm >> nUsage;    // i don't know anything of this parameter, so its called nUsage
1401                                                 // pOut->DrawRect( Rectangle( ReadYX(), aDestSize ), sal_False );
1402 
1403                         Size aDestSize( ReadYXExt() );
1404                         if ( aDestSize.Width() && aDestSize.Height() )  // #92623# do not try to read buggy bitmaps
1405                         {
1406                             Rectangle aDestRect( ReadYX(), aDestSize );
1407                             GetWinExtMax( aDestRect, rPlaceableBound, nMapMode );
1408                         }
1409                     }
1410                 }
1411                 break;
1412 
1413                 case W_META_PATBLT:
1414                 {
1415                     sal_uInt32 nROP;
1416                     *pStm >> nROP;
1417                     Size aSize = ReadYXExt();
1418                     GetWinExtMax( Rectangle( ReadYX(), aSize ), rPlaceableBound, nMapMode );
1419                 }
1420                 break;
1421             }
1422             nPos += nRSize * 2;
1423             if ( nPos <= nEnd )
1424                 pStm->Seek( nPos );
1425             else
1426             {
1427                 pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1428                 bRet = sal_False;
1429             }
1430 
1431         }
1432     }
1433     else
1434     {
1435         pStm->SetError( SVSTREAM_GENERALERROR );
1436         bRet = sal_False;
1437     }
1438     return bRet;
1439 }
1440 
~WMFReader()1441 WMFReader::~WMFReader()
1442 {
1443     if( pEMFStream )
1444         delete pEMFStream;
1445 }
1446