LibreOffice Module vcl (master)  1
ios2met.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <osl/thread.h>
21 #include <o3tl/safeint.hxx>
22 #include <tools/poly.hxx>
23 #include <tools/fract.hxx>
24 #include <tools/stream.hxx>
25 #include <sal/log.hxx>
26 #include <vcl/graph.hxx>
27 #include <vcl/dibtools.hxx>
28 #include <vcl/virdev.hxx>
29 #include <vcl/lineinfo.hxx>
30 #include <vcl/gdimtf.hxx>
31 #include <filter/MetReader.hxx>
32 
33 #include <math.h>
34 #include <memory>
35 
36 class FilterConfigItem;
37 
38 namespace {
39 
40 enum PenStyle { PEN_NULL, PEN_SOLID, PEN_DOT, PEN_DASH, PEN_DASHDOT };
41 
42 }
43 
44 // -----------------------------Field Types-------------------------------
45 
46 #define BegDocumnMagic 0xA8A8 /* Begin Document */
47 #define EndDocumnMagic 0xA8A9 /* End Document */
48 
49 #define BegResGrpMagic 0xC6A8 /* Begin Resource Group */
50 #define EndResGrpMagic 0xC6A9 /* End Resource Group */
51 
52 #define BegColAtrMagic 0x77A8 /* Begin Color Attribute Table */
53 #define EndColAtrMagic 0x77A9 /* End Color Attribute Table */
54 #define BlkColAtrMagic 0x77B0 /* Color Attribute Table */
55 #define MapColAtrMagic 0x77AB /* Map Color Attribute Table */
56 
57 #define BegImgObjMagic 0xFBA8 /* Begin Image Object */
58 #define EndImgObjMagic 0xFBA9 /* End Image Object */
59 #define DscImgObjMagic 0xFBA6 /* Image Data Descriptor */
60 #define DatImgObjMagic 0xFBEE /* Image Picture Data */
61 
62 #define BegObEnv1Magic 0xC7A8 /* Begin Object Environment Group */
63 #define EndObEnv1Magic 0xC7A9 /* End Object Environment Group */
64 
65 #define BegGrfObjMagic 0xBBA8 /* Begin Graphics Object */
66 #define EndGrfObjMagic 0xBBA9 /* End Graphics Object */
67 #define DscGrfObjMagic 0xBBA6 /* Graphics Data Descriptor */
68 #define DatGrfObjMagic 0xBBEE /* Graphics Data */
69 
70 #define MapCodFntMagic 0x8AAB /* Map Coded Font */
71 #define MapDatResMagic 0xC3AB /* Map Data Resource */
72 
73 // -----------------------------Order Types-------------------------------
74 
75 #define GOrdGivArc 0xC6 /* 1 Arc at given position */
76 #define GOrdCurArc 0x86 /* 1 Arc at current position */
77 #define GOrdGivBzr 0xE5 /* 1 Beziercurve at given position */
78 #define GOrdCurBzr 0xA5 /* 1 Beziercurve at current position */
79 #define GOrdGivBox 0xC0 /* 1 Box at given position */
80 #define GOrdCurBox 0x80 /* 1 Box at current position */
81 #define GOrdGivFil 0xC5 /* 1 Fillet at given position */
82 #define GOrdCurFil 0x85 /* 1 Fillet at current position */
83 #define GOrdGivCrc 0xC7 /* 1 Full arc (circle) at given position */
84 #define GOrdCurCrc 0x87 /* 1 Full arc (circle) at current position */
85 #define GOrdGivLin 0xC1 /* 1 Line at given position */
86 #define GOrdCurLin 0x81 /* 1 Line at current position */
87 #define GOrdGivMrk 0xC2 /* 1 Marker at given position */
88 #define GOrdCurMrk 0x82 /* 1 Marker at current position */
89 #define GOrdGivArP 0xE3 /* 1 Partial arc at given position */
90 #define GOrdCurArP 0xA3 /* 1 Partial arc at current position */
91 #define GOrdGivRLn 0xE1 /* 1 Relative line at given position */
92 #define GOrdCurRLn 0xA1 /* 1 Relative line at current position */
93 #define GOrdGivSFl 0xE4 /* 1 Sharp fillet at given position */
94 #define GOrdCurSFl 0xA4 /* 1 Sharp fillet at current position */
95 
96 #define GOrdGivStM 0xF1 /* 1 Character string move at given position */
97 #define GOrdCurStM 0xB1 /* 1 Character string move at current position */
98 #define GOrdGivStr 0xC3 /* 1 Character string at given position */
99 #define GOrdCurStr 0x83 /* 1 Character string at current position */
100 #define GOrdGivStx 0xFEF0 /* 2 Character string extended at given position */
101 #define GOrdCurStx 0xFEB0 /* 2 Character string extended at current position */
102 
103 #define GOrdGivImg 0xD1 /* 1 Begin Image at given position */
104 #define GOrdCurImg 0x91 /* 1 Begin Image at current position */
105 #define GOrdImgDat 0x92 /* 1 Image data */
106 #define GOrdEndImg 0x93 /* 1 End Image */
107 #define GOrdBegAra 0x68 /* 0 1 Begin area */
108 #define GOrdEndAra 0x60 /* 1 End area */
109 #define GOrdBegElm 0xD2 /* 1 Begin element */
110 #define GOrdEndElm 0x49 /* 0 1 End element */
111 
112 #define GOrdBegPth 0xD0 /* 1 Begin path */
113 #define GOrdEndPth 0x7F /* 0 1 End path */
114 #define GOrdFilPth 0xD7 /* 1 Fill path */
115 #define GOrdModPth 0xD8 /* 1 Modify path */
116 #define GOrdOutPth 0xD4 /* 1 Outline path */
117 #define GOrdSClPth 0xB4 /* 1 Set clip path */
118 
119 #define GOrdNopNop 0x00 /* 0 0 No operation */
120 #define GOrdRemark 0x01 /* 1 Comment */
121 #define GOrdSegLab 0xD3 /* 1 Label */
122 #define GOrdBitBlt 0xD6 /* 1 Bitblt */
123 #define GOrdCalSeg 0x07 /* 1 Call Segment */
124 #define GOrdSSgBnd 0x32 /* 1 Set segment boundary */
125 #define GOrdSegChr 0x04 /* 1 Segment characteristics */
126 #define GOrdCloFig 0x7D /* 0 1 Close Figure */
127 #define GOrdEndSym 0xFF /* 0 0 End of symbol definition */
128 #define GOrdEndPlg 0x3E /* 0 1 End prolog */
129 #define GOrdEscape 0xD5 /* 1 Escape */
130 #define GOrdExtEsc 0xFED5 /* 2 Extended Escape */
131 #define GOrdPolygn 0xF3 /* 2 Polygons */
132 
133 #define GOrdStkPop 0x3F /* 0 1 Pop */
134 
135 #define GOrdSIvAtr 0x14 /* 1 Set individual attribute */
136 #define GOrdPIvAtr 0x54 /* 1 Push and set individual attribute */
137 #define GOrdSColor 0x0A /* 0 1 Set color */
138 #define GOrdPColor 0x4A /* 0 1 Push and set color */
139 #define GOrdSIxCol 0xA6 /* 1 Set indexed color */
140 #define GOrdPIxCol 0xE6 /* 1 Push and set indexed color */
141 #define GOrdSXtCol 0x26 /* 1 Set extended color */
142 #define GOrdPXtCol 0x66 /* 1 Push and set extended color */
143 #define GOrdSBgCol 0x25 /* 1 Set background color */
144 #define GOrdPBgCol 0x65 /* 1 Push and set background color */
145 #define GOrdSBxCol 0xA7 /* 1 Set background indexed color */
146 #define GOrdPBxCol 0xE7 /* 1 Push and set background indexed color */
147 #define GOrdSMixMd 0x0C /* 0 1 Set mix */
148 #define GOrdPMixMd 0x4C /* 0 1 Push and set mix */
149 #define GOrdSBgMix 0x0D /* 0 1 Set background mix */
150 #define GOrdPBgMix 0x4D /* 0 1 Push and set background mix */
151 
152 #define GOrdSPtSet 0x08 /* 0 1 Set pattern set */
153 #define GOrdPPtSet 0x48 /* 0 1 Push and set pattern set */
154 #define GOrdSPtSym 0x28 /* 0 1 Set pattern symbol */
155 #define GOrdPPtSym 0x09 /* 0 1 Push and set pattern symbol */
156 #define GOrdSPtRef 0xA0 /* 1 Set model pattern reference */
157 #define GOrdPPtRef 0xE0 /* 1 Push and set pattern reference point */
158 
159 #define GOrdSLnEnd 0x1A /* 0 1 Set line end */
160 #define GOrdPLnEnd 0x5A /* 0 1 Push and set line end */
161 #define GOrdSLnJoi 0x1B /* 0 1 Set line join */
162 #define GOrdPLnJoi 0x5B /* 0 1 Push and set line join */
163 #define GOrdSLnTyp 0x18 /* 0 1 Set line type */
164 #define GOrdPLnTyp 0x58 /* 0 1 Push and set line type */
165 #define GOrdSLnWdt 0x19 /* 0 1 Set line width */
166 #define GOrdPLnWdt 0x59 /* 0 1 Push and set line width */
167 #define GOrdSFrLWd 0x11 /* 1 Set fractional line width */
168 #define GOrdPFrLWd 0x51 /* 1 Push and set fractional line width */
169 #define GOrdSStLWd 0x15 /* 1 Set stroke line width */
170 #define GOrdPStLWd 0x55 /* 1 Push and set stroke line width */
171 
172 #define GOrdSChDir 0x3A /* 0 1 Set character direction */
173 #define GOrdPChDir 0x7A /* 0 1 Push and set character direction */
174 #define GOrdSChPrc 0x39 /* 0 1 Set character precision */
175 #define GOrdPChPrc 0x79 /* 0 1 Push and set character precision */
176 #define GOrdSChSet 0x38 /* 0 1 Set character set */
177 #define GOrdPChSet 0x78 /* 0 1 Push and set character set */
178 #define GOrdSChAng 0x34 /* 1 Set character angle */
179 #define GOrdPChAng 0x74 /* 1 Push and set character angle */
180 #define GOrdSChBrx 0x05 /* 1 Set character break extra */
181 #define GOrdPChBrx 0x45 /* 1 Push and set character break extra */
182 #define GOrdSChCel 0x33 /* 1 Set character cell */
183 #define GOrdPChCel 0x03 /* 1 Push and set character cell */
184 #define GOrdSChXtr 0x17 /* 1 Set character extra */
185 #define GOrdPChXtr 0x57 /* 1 Push and set character extra */
186 #define GOrdSChShr 0x35 /* 1 Set character shear */
187 #define GOrdPChShr 0x75 /* 1 Push and set character shear */
188 #define GOrdSTxAlg 0x36 /* 0 2 Set text allingment */
189 #define GOrdPTxAlg 0x76 /* 0 2 Push and set text allingment */
190 
191 #define GOrdSMkPrc 0x3B /* 0 1 Set marker precision */
192 #define GOrdPMkPrc 0x7B /* 0 1 Push and set marker precision */
193 #define GOrdSMkSet 0x3C /* 0 1 Set marker set */
194 #define GOrdPMkSet 0x7C /* 0 1 Push and set marker set */
195 #define GOrdSMkSym 0x29 /* 0 1 Set marker symbol */
196 #define GOrdPMkSym 0x69 /* 0 1 Push and set marker symbol */
197 #define GOrdSMkCel 0x37 /* 1 Set marker cell */
198 #define GOrdPMkCel 0x77 /* 1 Push and set marker cell */
199 
200 #define GOrdSArcPa 0x22 /* 1 Set arc parameters */
201 #define GOrdPArcPa 0x62 /* 1 Push and set arc parameters */
202 
203 #define GOrdSCrPos 0x21 /* 1 Set current position */
204 #define GOrdPCrPos 0x61 /* 1 Push and set current position */
205 
206 #define GOrdSMdTrn 0x24 /* 1 Set model transform */
207 #define GOrdPMdTrn 0x64 /* 1 Push and set model transform */
208 #define GOrdSPkIdn 0x43 /* 1 Set pick identifier */
209 #define GOrdPPkIdn 0x23 /* 1 Push and set pick identifier */
210 #define GOrdSVwTrn 0x31 /* 1 Set viewing transform */
211 #define GOrdSVwWin 0x27 /* 1 Set viewing window */
212 #define GOrdPVwWin 0x67 /* 1 Push and set viewing window */
213 
214 //============================ OS2METReader ==================================
215 
216 namespace {
217 
218 struct OSPalette {
219  OSPalette * pSucc;
220  sal_uInt32 * p0RGB; // May be NULL!
221  size_t nSize;
222 };
223 
224 struct OSArea {
225  OSArea * pSucc;
226  sal_uInt8 nFlags;
227  tools::PolyPolygon aPPoly;
228  bool bClosed;
229  Color aCol;
230  Color aBgCol;
231  RasterOp eMix;
232  RasterOp eBgMix;
233  bool bFill;
234 
235  OSArea()
236  : pSucc(nullptr)
237  , nFlags(0)
238  , bClosed(false)
239  , eMix(RasterOp::OverPaint)
240  , eBgMix(RasterOp::OverPaint)
241  , bFill(false)
242  {
243  }
244 };
245 
246 struct OSPath
247 {
248  OSPath* pSucc;
249  sal_uInt32 nID;
250  tools::PolyPolygon aPPoly;
251  bool bClosed;
252  bool bStroke;
253 
254  OSPath()
255  : pSucc(nullptr)
256  , nID(0)
257  , bClosed(false)
258  , bStroke(false)
259  {
260  }
261 };
262 
263 struct OSFont {
264  OSFont * pSucc;
265  sal_uInt32 nID;
266  vcl::Font aFont;
267 
268  OSFont()
269  : pSucc(nullptr)
270  , nID(0)
271  {
272  }
273 };
274 
275 struct OSBitmap {
276  OSBitmap * pSucc;
277  sal_uInt32 nID;
278  BitmapEx aBitmapEx;
279 
280  // required during reading of the bitmap:
281  SvStream * pBMP; // pointer to temporary Windows-BMP file or NULL
282  sal_uInt32 nWidth, nHeight;
283  sal_uInt16 nBitsPerPixel;
284  sal_uInt32 nMapPos;
285 };
286 
287 struct OSAttr
288 {
289  OSAttr * pSucc;
290  sal_uInt16 nPushOrder;
291  sal_uInt8 nIvAttrA, nIvAttrP; // special variables for the Order "GOrdPIvAtr"
292 
293  Color aLinCol;
294  Color aLinBgCol;
295  RasterOp eLinMix;
296  RasterOp eLinBgMix;
297  Color aChrCol;
298  Color aChrBgCol;
299  RasterOp eChrMix;
300  RasterOp eChrBgMix;
301  Color aMrkCol;
302  Color aMrkBgCol;
303  RasterOp eMrkMix;
304  RasterOp eMrkBgMix;
305  Color aPatCol;
306  Color aPatBgCol;
307  RasterOp ePatMix;
308  RasterOp ePatBgMix;
309  Color aImgCol;
310  Color aImgBgCol;
311  RasterOp eImgMix;
312  RasterOp eImgBgMix;
313  sal_Int32 nArcP, nArcQ, nArcR, nArcS;
314  Degree10 nChrAng;
315  Size aChrCellSize;
316  sal_uInt32 nChrSet;
317  Point aCurPos;
318  PenStyle eLinStyle;
319  sal_uInt16 nLinWidth;
320  Size aMrkCellSize;
321  sal_uInt8 nMrkPrec;
322  sal_uInt8 nMrkSet;
323  sal_uInt8 nMrkSymbol;
324  bool bFill;
325  sal_uInt16 nStrLinWidth;
326 
327  OSAttr()
328  : pSucc(nullptr)
329  , nPushOrder(0)
330  , nIvAttrA(0)
331  , nIvAttrP(0)
332  , eLinMix(RasterOp::OverPaint)
333  , eLinBgMix(RasterOp::OverPaint)
334  , eChrMix(RasterOp::OverPaint)
335  , eChrBgMix(RasterOp::OverPaint)
336  , eMrkMix(RasterOp::OverPaint)
337  , eMrkBgMix(RasterOp::OverPaint)
338  , ePatMix(RasterOp::OverPaint)
339  , ePatBgMix(RasterOp::OverPaint)
340  , eImgMix(RasterOp::OverPaint)
341  , eImgBgMix(RasterOp::OverPaint)
342  , nArcP(0)
343  , nArcQ(0)
344  , nArcR(0)
345  , nArcS(0)
346  , nChrAng(0)
347  , nChrSet(0)
348  , eLinStyle(PEN_NULL)
349  , nLinWidth(0)
350  , nMrkPrec(0)
351  , nMrkSet(0)
352  , nMrkSymbol(0)
353  , bFill(false)
354  , nStrLinWidth(0)
355  {
356  }
357 };
358 
359 class OS2METReader {
360 
361 private:
362 
363  int ErrorCode;
364 
365  SvStream * pOS2MET; // the OS2MET file to be read
366  VclPtr<VirtualDevice> pVirDev; // here the drawing methods are being called
367  // While doing this a recording in the GDIMetaFile
368  // will take place.
369  tools::Rectangle aBoundingRect; // bounding rectangle as stored in the file
370  tools::Rectangle aCalcBndRect; // bounding rectangle calculated on our own
371  MapMode aGlobMapMode; // resolution of the picture
372  bool bCoord32;
373 
374  OSPalette * pPaletteStack;
375 
376  LineInfo aLineInfo;
377 
378  OSArea * pAreaStack; // Areas that are being worked on
379 
380  OSPath * pPathStack; // Paths that are being worked on
381  OSPath * pPathList; // finished Paths
382 
383  OSFont * pFontList;
384 
385  OSBitmap * pBitmapList;
386 
387  OSAttr aDefAttr;
388  OSAttr aAttr;
389  OSAttr * pAttrStack;
390 
391  std::unique_ptr<SvMemoryStream> xOrdFile;
392 
393  void AddPointsToPath(const tools::Polygon & rPoly);
394  void AddPointsToArea(const tools::Polygon & rPoly);
395  void CloseFigure();
396  void PushAttr(sal_uInt16 nPushOrder);
397  void PopAttr();
398 
399  void ChangeBrush( const Color& rPatColor, bool bFill );
400  void SetPen( const Color& rColor, sal_uInt16 nStrLinWidth = 0, PenStyle ePenStyle = PEN_SOLID );
401  void SetRasterOp(RasterOp eROP);
402 
403  void SetPalette0RGB(sal_uInt16 nIndex, sal_uInt32 nCol);
404  sal_uInt32 GetPalette0RGB(sal_uInt32 nIndex) const;
405  // gets color from palette, or, if it doesn't exist,
406  // interprets nIndex as immediate RGB value.
407  Color GetPaletteColor(sal_uInt32 nIndex) const;
408 
409 
410  bool IsLineInfo() const;
411  void DrawPolyLine( const tools::Polygon& rPolygon );
412  void DrawPolygon( const tools::Polygon& rPolygon );
413  void DrawPolyPolygon( const tools::PolyPolygon& rPolygon );
414  sal_uInt16 ReadBigEndianWord();
415  sal_uInt32 ReadBigEndian3BytesLong();
416  sal_uInt32 ReadLittleEndian3BytesLong();
417  sal_Int32 ReadCoord(bool b32);
418  Point ReadPoint( const bool bAdjustBoundRect = true );
419  static RasterOp OS2MixToRasterOp(sal_uInt8 nMix);
420  void ReadLine(bool bGivenPos, sal_uInt16 nOrderLen);
421  void ReadRelLine(bool bGivenPos, sal_uInt16 nOrderLen);
422  void ReadBox(bool bGivenPos);
423  void ReadBitBlt();
424  void ReadChrStr(bool bGivenPos, bool bMove, bool bExtra, sal_uInt16 nOrderLen);
425  void ReadArc(bool bGivenPos);
426  void ReadFullArc(bool bGivenPos, sal_uInt16 nOrderSize);
427  void ReadPartialArc(bool bGivenPos, sal_uInt16 nOrderSize);
428  void ReadPolygons();
429  void ReadBezier(bool bGivenPos, sal_uInt16 nOrderLen);
430  void ReadFillet(bool bGivenPos, sal_uInt16 nOrderLen);
431  void ReadFilletSharp(bool bGivenPos, sal_uInt16 nOrderLen);
432  void ReadMarker(bool bGivenPos, sal_uInt16 nOrderLen);
433  void ReadOrder(sal_uInt16 nOrderID, sal_uInt16 nOrderLen);
434  void ReadDsc(sal_uInt16 nDscID);
435  void ReadImageData(sal_uInt16 nDataID, sal_uInt16 nDataLen);
436  void ReadFont(sal_uInt16 nFieldSize);
437  void ReadField(sal_uInt16 nFieldType, sal_uInt16 nFieldSize);
438 
439 public:
440 
441  OS2METReader();
442  ~OS2METReader();
443 
444  void ReadOS2MET( SvStream & rStreamOS2MET, GDIMetaFile & rGDIMetaFile );
445  // Reads from the stream an OS2MET file and fills up the GDIMetaFile
446 
447 };
448 
449 }
450 
451 //=================== Methods of OS2METReader ==============================
452 
453 OS2METReader::OS2METReader()
454  : ErrorCode(0)
455  , pOS2MET(nullptr)
456  , pVirDev(VclPtr<VirtualDevice>::Create())
457  , bCoord32(false)
458  , pPaletteStack(nullptr)
459  , pAreaStack(nullptr)
460  , pPathStack(nullptr)
461  , pPathList(nullptr)
462  , pFontList(nullptr)
463  , pBitmapList(nullptr)
464  , pAttrStack(nullptr)
465 {
466  pVirDev->EnableOutput(false);
467 }
468 
469 OS2METReader::~OS2METReader()
470 {
471  pVirDev.disposeAndClear();
472 
473  while (pAreaStack!=nullptr) {
474  OSArea * p=pAreaStack;
475  pAreaStack=p->pSucc;
476  delete p;
477  }
478 
479  while (pPathStack!=nullptr) {
480  OSPath * p=pPathStack;
481  pPathStack=p->pSucc;
482  delete p;
483  }
484 
485  while (pPathList!=nullptr) {
486  OSPath * p=pPathList;
487  pPathList=p->pSucc;
488  delete p;
489  }
490 
491  while (pFontList!=nullptr) {
492  OSFont * p=pFontList;
493  pFontList=p->pSucc;
494  delete p;
495  }
496 
497  while (pBitmapList!=nullptr) {
498  OSBitmap * p=pBitmapList;
499  pBitmapList=p->pSucc;
500  delete p->pBMP;
501  delete p;
502  }
503 
504  while (pAttrStack!=nullptr) {
505  OSAttr * p=pAttrStack;
506  pAttrStack=p->pSucc;
507  delete p;
508  }
509 
510  while (pPaletteStack!=nullptr) {
511  OSPalette * p=pPaletteStack;
512  pPaletteStack=p->pSucc;
513  delete[] p->p0RGB;
514  delete p;
515  }
516 }
517 
518 bool OS2METReader::IsLineInfo() const
519 {
520  return ( ! ( aLineInfo.IsDefault() || ( aLineInfo.GetStyle() == LineStyle::NONE ) || ( pVirDev->GetLineColor() == COL_TRANSPARENT ) ) );
521 }
522 
523 void OS2METReader::DrawPolyLine( const tools::Polygon& rPolygon )
524 {
525  if ( aLineInfo.GetStyle() == LineStyle::Dash || ( aLineInfo.GetWidth() > 1 ) )
526  pVirDev->DrawPolyLine( rPolygon, aLineInfo );
527  else
528  pVirDev->DrawPolyLine( rPolygon );
529 }
530 
531 void OS2METReader::DrawPolygon( const tools::Polygon& rPolygon )
532 {
533  if ( IsLineInfo() )
534  {
535  pVirDev->Push( vcl::PushFlags::LINECOLOR );
536  pVirDev->SetLineColor( COL_TRANSPARENT );
537  pVirDev->DrawPolygon( rPolygon );
538  pVirDev->Pop();
539  pVirDev->DrawPolyLine( rPolygon, aLineInfo );
540  }
541  else
542  pVirDev->DrawPolygon( rPolygon );
543 }
544 
545 void OS2METReader::DrawPolyPolygon( const tools::PolyPolygon& rPolyPolygon )
546 {
547  if ( IsLineInfo() )
548  {
549  pVirDev->Push( vcl::PushFlags::LINECOLOR );
550  pVirDev->SetLineColor( COL_TRANSPARENT );
551  pVirDev->DrawPolyPolygon( rPolyPolygon );
552  pVirDev->Pop();
553  for ( sal_uInt16 i = 0; i < rPolyPolygon.Count(); i++ )
554  pVirDev->DrawPolyLine( rPolyPolygon.GetObject( i ), aLineInfo );
555  }
556  else
557  pVirDev->DrawPolyPolygon( rPolyPolygon );
558 }
559 
560 void OS2METReader::AddPointsToArea(const tools::Polygon & rPoly)
561 {
562  sal_uInt16 nOldSize, nNewSize,i;
563 
564  if (pAreaStack==nullptr || rPoly.GetSize()==0) return;
565  tools::PolyPolygon * pPP=&(pAreaStack->aPPoly);
566  if (pPP->Count()==0 || pAreaStack->bClosed) pPP->Insert(rPoly);
567  else {
568  tools::Polygon aLastPoly(pPP->GetObject(pPP->Count()-1));
569  nOldSize=aLastPoly.GetSize();
570  if (nOldSize && aLastPoly.GetPoint(nOldSize-1)==rPoly.GetPoint(0)) nOldSize--;
571  nNewSize=nOldSize+rPoly.GetSize();
572  aLastPoly.SetSize(nNewSize);
573  for (i=nOldSize; i<nNewSize; i++) {
574  aLastPoly.SetPoint(rPoly.GetPoint(i-nOldSize),i);
575  }
576  pPP->Replace(aLastPoly,pPP->Count()-1);
577  }
578  pAreaStack->bClosed=false;
579 }
580 
581 void OS2METReader::AddPointsToPath(const tools::Polygon & rPoly)
582 {
583  sal_uInt16 nOldSize, nNewSize,i;
584 
585  if (pPathStack==nullptr || rPoly.GetSize()==0) return;
586  tools::PolyPolygon * pPP=&(pPathStack->aPPoly);
587  if (pPP->Count()==0 /*|| pPathStack->bClosed==sal_True*/) pPP->Insert(rPoly);
588  else {
589  tools::Polygon aLastPoly(pPP->GetObject(pPP->Count()-1));
590  nOldSize=aLastPoly.GetSize();
591  if (nOldSize && aLastPoly.GetPoint(nOldSize-1)!=rPoly.GetPoint(0)) pPP->Insert(rPoly);
592  else {
593  nOldSize--;
594  nNewSize=nOldSize+rPoly.GetSize();
595  aLastPoly.SetSize(nNewSize);
596  for (i=nOldSize; i<nNewSize; i++) {
597  aLastPoly.SetPoint(rPoly.GetPoint(i-nOldSize),i);
598  }
599  pPP->Replace(aLastPoly,pPP->Count()-1);
600  }
601  }
602  pPathStack->bClosed=false;
603 }
604 
605 void OS2METReader::CloseFigure()
606 {
607  if (pAreaStack!=nullptr) pAreaStack->bClosed=true;
608  else if (pPathStack!=nullptr) pPathStack->bClosed=true;
609 }
610 
611 void OS2METReader::PushAttr(sal_uInt16 nPushOrder)
612 {
613  OSAttr * p;
614  p=new OSAttr;
615  *p=aAttr;
616  p->pSucc=pAttrStack; pAttrStack=p;
617  p->nPushOrder=nPushOrder;
618 }
619 
620 void OS2METReader::PopAttr()
621 {
622  OSAttr * p=pAttrStack;
623 
624  if (p==nullptr) return;
625  switch (p->nPushOrder) {
626 
627  case GOrdPIvAtr:
628  switch (p->nIvAttrA) {
629  case 1: switch (p->nIvAttrP) {
630  case 1: aAttr.aLinCol=p->aLinCol; break;
631  case 2: aAttr.aChrCol=p->aChrCol; break;
632  case 3: aAttr.aMrkCol=p->aMrkCol; break;
633  case 4: aAttr.aPatCol=p->aPatCol; break;
634  case 5: aAttr.aImgCol=p->aImgCol; break;
635  } break;
636  case 2: switch (p->nIvAttrP) {
637  case 1: aAttr.aLinBgCol=p->aLinBgCol; break;
638  case 2: aAttr.aChrBgCol=p->aChrBgCol; break;
639  case 3: aAttr.aMrkBgCol=p->aMrkBgCol; break;
640  case 4: aAttr.aPatBgCol=p->aPatBgCol; break;
641  case 5: aAttr.aImgBgCol=p->aImgBgCol; break;
642  } break;
643  case 3: switch (p->nIvAttrP) {
644  case 1: aAttr.eLinMix=p->eLinMix; break;
645  case 2: aAttr.eChrMix=p->eChrMix; break;
646  case 3: aAttr.eMrkMix=p->eMrkMix; break;
647  case 4: aAttr.ePatMix=p->ePatMix; break;
648  case 5: aAttr.eImgMix=p->eImgMix; break;
649  } break;
650  case 4: switch (p->nIvAttrP) {
651  case 1: aAttr.eLinBgMix=p->eLinBgMix; break;
652  case 2: aAttr.eChrBgMix=p->eChrBgMix; break;
653  case 3: aAttr.eMrkBgMix=p->eMrkBgMix; break;
654  case 4: aAttr.ePatBgMix=p->ePatBgMix; break;
655  case 5: aAttr.eImgBgMix=p->eImgBgMix; break;
656  } break;
657  }
658  break;
659 
660  case GOrdPLnTyp: aAttr.eLinStyle=p->eLinStyle; break;
661 
662  case GOrdPLnWdt: aAttr.nLinWidth=p->nLinWidth; break;
663 
664  case GOrdPStLWd: aAttr.nStrLinWidth=p->nStrLinWidth; break;
665 
666  case GOrdPChSet: aAttr.nChrSet=p->nChrSet; break;
667 
668  case GOrdPChAng: aAttr.nChrAng=p->nChrAng; break;
669 
670  case GOrdPMixMd:
671  aAttr.eLinMix=p->eLinMix;
672  aAttr.eChrMix=p->eChrMix;
673  aAttr.eMrkMix=p->eMrkMix;
674  aAttr.ePatMix=p->ePatMix;
675  aAttr.eImgMix=p->eImgMix;
676  break;
677 
678  case GOrdPBgMix:
679  aAttr.eLinBgMix=p->eLinBgMix;
680  aAttr.eChrBgMix=p->eChrBgMix;
681  aAttr.eMrkBgMix=p->eMrkBgMix;
682  aAttr.ePatBgMix=p->ePatBgMix;
683  aAttr.eImgBgMix=p->eImgBgMix;
684  break;
685 
686  case GOrdPPtSym: aAttr.bFill = p->bFill; break;
687 
688  case GOrdPColor:
689  case GOrdPIxCol:
690  case GOrdPXtCol:
691  aAttr.aLinCol=p->aLinCol;
692  aAttr.aChrCol=p->aChrCol;
693  aAttr.aMrkCol=p->aMrkCol;
694  aAttr.aPatCol=p->aPatCol;
695  aAttr.aImgCol=p->aImgCol;
696  break;
697 
698  case GOrdPBgCol:
699  case GOrdPBxCol:
700  aAttr.aLinBgCol=p->aLinBgCol;
701  aAttr.aChrBgCol=p->aChrBgCol;
702  aAttr.aMrkBgCol=p->aMrkBgCol;
703  aAttr.aPatBgCol=p->aPatBgCol;
704  aAttr.aImgBgCol=p->aImgBgCol;
705  break;
706 
707  case GOrdPMkPrc: aAttr.nMrkPrec=aDefAttr.nMrkPrec; break;
708 
709  case GOrdPMkSet: aAttr.nMrkSet=aDefAttr.nMrkSet; break;
710 
711  case GOrdPMkSym: aAttr.nMrkSymbol=aDefAttr.nMrkSymbol; break;
712 
713  case GOrdPMkCel: aAttr.aMrkCellSize=aDefAttr.aMrkCellSize; break;
714 
715  case GOrdPArcPa:
716  aAttr.nArcP=p->nArcP; aAttr.nArcQ=p->nArcQ;
717  aAttr.nArcR=p->nArcR; aAttr.nArcS=p->nArcS;
718  break;
719 
720  case GOrdPCrPos:
721  aAttr.aCurPos=p->aCurPos;
722  break;
723  }
724  pAttrStack=p->pSucc;
725  delete p;
726 }
727 
728 void OS2METReader::ChangeBrush(const Color& rPatColor, bool bFill )
729 {
730  Color aColor;
731 
732  if( bFill )
733  aColor = rPatColor;
734  else
735  aColor = COL_TRANSPARENT;
736 
737  if( pVirDev->GetFillColor() != aColor )
738  pVirDev->SetFillColor( aColor );
739 }
740 
741 void OS2METReader::SetPen( const Color& rColor, sal_uInt16 nLineWidth, PenStyle ePenStyle )
742 {
743  LineStyle eLineStyle( LineStyle::Solid );
744 
745  if ( pVirDev->GetLineColor() != rColor )
746  pVirDev->SetLineColor( rColor );
747  aLineInfo.SetWidth( nLineWidth );
748 
749  sal_uInt16 nDotCount = 0;
750  sal_uInt16 nDashCount = 0;
751  switch ( ePenStyle )
752  {
753  case PEN_NULL :
754  eLineStyle = LineStyle::NONE;
755  break;
756  case PEN_DASHDOT :
757  nDashCount++;
758  [[fallthrough]];
759  case PEN_DOT :
760  nDotCount++;
761  nDashCount--;
762  [[fallthrough]];
763  case PEN_DASH :
764  nDashCount++;
765  aLineInfo.SetDotCount( nDotCount );
766  aLineInfo.SetDashCount( nDashCount );
767  aLineInfo.SetDistance( nLineWidth );
768  aLineInfo.SetDotLen( nLineWidth );
769  aLineInfo.SetDashLen( nLineWidth << 2 );
770  eLineStyle = LineStyle::Dash;
771  break;
772  case PEN_SOLID:
773  break; // -Wall not handled...
774  }
775  aLineInfo.SetStyle( eLineStyle );
776 }
777 
778 void OS2METReader::SetRasterOp(RasterOp eROP)
779 {
780  if (pVirDev->GetRasterOp()!=eROP) pVirDev->SetRasterOp(eROP);
781 }
782 
783 void OS2METReader::SetPalette0RGB(sal_uInt16 nIndex, sal_uInt32 nCol)
784 {
785  if (pPaletteStack==nullptr) {
786  pPaletteStack=new OSPalette;
787  pPaletteStack->pSucc=nullptr;
788  pPaletteStack->p0RGB=nullptr;
789  pPaletteStack->nSize=0;
790  }
791  if (pPaletteStack->p0RGB==nullptr || nIndex>=pPaletteStack->nSize) {
792  sal_uInt32 * pOld0RGB=pPaletteStack->p0RGB;
793  size_t nOldSize = pPaletteStack->nSize;
794  if (pOld0RGB==nullptr) nOldSize=0;
795  pPaletteStack->nSize=2*(nIndex+1);
796  if (pPaletteStack->nSize<256) pPaletteStack->nSize=256;
797  pPaletteStack->p0RGB = new sal_uInt32[pPaletteStack->nSize];
798  for (size_t i=0; i < pPaletteStack->nSize; ++i)
799  {
800  if (i<nOldSize) pPaletteStack->p0RGB[i]=pOld0RGB[i];
801  else if (i==0) pPaletteStack->p0RGB[i]=0x00ffffff;
802  else pPaletteStack->p0RGB[i]=0;
803  }
804  delete[] pOld0RGB;
805  }
806  pPaletteStack->p0RGB[nIndex]=nCol;
807 }
808 
809 sal_uInt32 OS2METReader::GetPalette0RGB(sal_uInt32 nIndex) const
810 {
811  if (pPaletteStack!=nullptr && pPaletteStack->p0RGB!=nullptr &&
812  pPaletteStack->nSize>nIndex) nIndex=pPaletteStack->p0RGB[nIndex];
813  return nIndex;
814 }
815 
816 Color OS2METReader::GetPaletteColor(sal_uInt32 nIndex) const
817 {
818  nIndex=GetPalette0RGB(nIndex);
819  return Color(sal::static_int_cast< sal_uInt8 >((nIndex>>16)&0xff),
820  sal::static_int_cast< sal_uInt8 >((nIndex>>8)&0xff),
821  sal::static_int_cast< sal_uInt8 >(nIndex&0xff));
822 }
823 
824 sal_uInt16 OS2METReader::ReadBigEndianWord()
825 {
826  sal_uInt8 nLo(0), nHi(0);
827  pOS2MET->ReadUChar( nHi ).ReadUChar( nLo );
828  return (static_cast<sal_uInt16>(nHi)<<8)|(static_cast<sal_uInt16>(nLo)&0x00ff);
829 }
830 
831 sal_uInt32 OS2METReader::ReadBigEndian3BytesLong()
832 {
833  sal_uInt8 nHi(0);
834  pOS2MET->ReadUChar( nHi );
835  sal_uInt16 nLo = ReadBigEndianWord();
836  return ((static_cast<sal_uInt32>(nHi)<<16)&0x00ff0000)|static_cast<sal_uInt32>(nLo);
837 }
838 
839 sal_uInt32 OS2METReader::ReadLittleEndian3BytesLong()
840 {
841  sal_uInt8 nHi(0), nMed(0), nLo(0);
842 
843  pOS2MET->ReadUChar( nLo ).ReadUChar( nMed ).ReadUChar( nHi );
844  return ((static_cast<sal_uInt32>(nHi)&0xff)<<16)|((static_cast<sal_uInt32>(nMed)&0xff)<<8)|(static_cast<sal_uInt32>(nLo)&0xff);
845 }
846 
847 sal_Int32 OS2METReader::ReadCoord(bool b32)
848 {
849  sal_Int32 l(0);
850 
851  if (b32) pOS2MET->ReadInt32( l );
852  else { short s(0); pOS2MET->ReadInt16( s ); l = static_cast<sal_Int32>(s); }
853  return l;
854 }
855 
856 Point OS2METReader::ReadPoint( const bool bAdjustBoundRect )
857 {
858  sal_Int32 x = ReadCoord(bCoord32);
859  sal_Int32 y = ReadCoord(bCoord32);
860  x=x-aBoundingRect.Left();
861  y=aBoundingRect.Bottom()-y;
862 
863  if (bAdjustBoundRect)
864  {
865  if (x == SAL_MAX_INT32 || y == SAL_MAX_INT32)
866  pOS2MET->SetError(SVSTREAM_FILEFORMAT_ERROR);
867  else
868  aCalcBndRect.Union(tools::Rectangle(x, y, x + 1, y + 1));
869  }
870 
871  return Point(x,y);
872 }
873 
874 RasterOp OS2METReader::OS2MixToRasterOp(sal_uInt8 nMix)
875 {
876  switch (nMix) {
877  case 0x0c: return RasterOp::Invert;
878  case 0x04: return RasterOp::Xor;
879  case 0x0b: return RasterOp::Xor;
880  default: return RasterOp::OverPaint;
881  }
882 }
883 
884 void OS2METReader::ReadLine(bool bGivenPos, sal_uInt16 nOrderLen)
885 {
886  sal_uInt16 i,nPolySize;
887 
888  if (bCoord32) nPolySize=nOrderLen/8; else nPolySize=nOrderLen/4;
889  if (!bGivenPos) nPolySize++;
890  if (nPolySize==0) return;
891  tools::Polygon aPolygon(nPolySize);
892  for (i=0; i<nPolySize; i++) {
893  if (i==0 && !bGivenPos) aPolygon.SetPoint(aAttr.aCurPos,i);
894  else aPolygon.SetPoint(ReadPoint(),i);
895  }
896  aAttr.aCurPos=aPolygon.GetPoint(nPolySize-1);
897  if (pAreaStack!=nullptr) AddPointsToArea(aPolygon);
898  else if (pPathStack!=nullptr) AddPointsToPath(aPolygon);
899  else
900  {
901  SetPen( aAttr.aLinCol, aAttr.nStrLinWidth, aAttr.eLinStyle );
902  SetRasterOp(aAttr.eLinMix);
903  DrawPolyLine( aPolygon );
904  }
905 }
906 
907 void OS2METReader::ReadRelLine(bool bGivenPos, sal_uInt16 nOrderLen)
908 {
909  sal_uInt16 i,nPolySize;
910  Point aP0;
911 
912  if (bGivenPos) {
913  aP0=ReadPoint();
914  if (bCoord32) nOrderLen-=8; else nOrderLen-=4;
915  }
916  else aP0=aAttr.aCurPos;
917  if (nOrderLen > pOS2MET->remainingSize())
918  throw css::uno::Exception("attempt to read past end of input", nullptr);
919  nPolySize=nOrderLen/2;
920  if (nPolySize==0) return;
921  tools::Polygon aPolygon(nPolySize);
922  for (i=0; i<nPolySize; i++) {
923  sal_Int8 nsignedbyte;
924  pOS2MET->ReadSChar( nsignedbyte ); aP0.AdjustX(static_cast<sal_Int32>(nsignedbyte));
925  pOS2MET->ReadSChar( nsignedbyte ); aP0.AdjustY(-static_cast<sal_Int32>(nsignedbyte));
926  aCalcBndRect.Union(tools::Rectangle(aP0,Size(1,1)));
927  aPolygon.SetPoint(aP0,i);
928  }
929  aAttr.aCurPos=aPolygon.GetPoint(nPolySize-1);
930  if (pAreaStack!=nullptr) AddPointsToArea(aPolygon);
931  else if (pPathStack!=nullptr) AddPointsToPath(aPolygon);
932  else
933  {
934  SetPen( aAttr.aLinCol, aAttr.nStrLinWidth, aAttr.eLinStyle );
935  SetRasterOp(aAttr.eLinMix);
936  DrawPolyLine( aPolygon );
937  }
938 }
939 
940 void OS2METReader::ReadBox(bool bGivenPos)
941 {
942  sal_uInt8 nFlags;
943  Point P0;
944 
945  pOS2MET->ReadUChar( nFlags );
946  pOS2MET->SeekRel(1);
947 
948  if ( bGivenPos )
949  P0 = ReadPoint();
950  else
951  P0 = aAttr.aCurPos;
952 
953  aAttr.aCurPos = ReadPoint();
954  sal_Int32 nHRound = ReadCoord(bCoord32);
955  sal_Int32 nVRound = ReadCoord(bCoord32);
956 
957  if (!pOS2MET->good())
958  {
959  SAL_WARN("filter.os2met", "OS2METReader::ReadBox: short read");
960  return;
961  }
962 
963  tools::Rectangle aBoxRect( P0, aAttr.aCurPos );
964 
965  if ( pAreaStack )
966  AddPointsToArea( tools::Polygon( aBoxRect ) );
967  else if ( pPathStack )
968  AddPointsToPath( tools::Polygon( aBoxRect ) );
969  else
970  {
971  if ( nFlags & 0x20 )
972  SetPen( aAttr.aLinCol, aAttr.nStrLinWidth, aAttr.eLinStyle );
973  else
974  SetPen( COL_TRANSPARENT );
975 
976  if ( nFlags & 0x40 )
977  {
978  ChangeBrush(aAttr.aPatCol, aAttr.bFill);
979  SetRasterOp(aAttr.ePatMix);
980  }
981  else
982  {
983  ChangeBrush( COL_TRANSPARENT, false );
984  SetRasterOp(aAttr.eLinMix);
985  }
986 
987  if ( IsLineInfo() )
988  {
989  tools::Polygon aPolygon( aBoxRect, nHRound, nVRound );
990  if ( nFlags & 0x40 )
991  {
992  pVirDev->Push( vcl::PushFlags::LINECOLOR );
993  pVirDev->SetLineColor( COL_TRANSPARENT );
994  pVirDev->DrawRect( aBoxRect, nHRound, nVRound );
995  pVirDev->Pop();
996  }
997  pVirDev->DrawPolyLine( aPolygon, aLineInfo );
998  }
999  else
1000  pVirDev->DrawRect( aBoxRect, nHRound, nVRound );
1001  }
1002 }
1003 
1004 void OS2METReader::ReadBitBlt()
1005 {
1006  pOS2MET->SeekRel(4);
1007  sal_uInt32 nID(0);
1008  pOS2MET->ReadUInt32( nID );
1009  pOS2MET->SeekRel(4);
1010  Point aP1 = ReadPoint();
1011  Point aP2 = ReadPoint();
1012  if (aP1.X() > aP2.X()) { auto nt=aP1.X(); aP1.setX(aP2.X() ); aP2.setX(nt ); }
1013  if (aP1.Y() > aP2.Y()) { auto nt=aP1.Y(); aP1.setY(aP2.Y() ); aP2.setY(nt ); }
1014  Size aSize(aP2.X() - aP1.X(), aP2.Y() - aP1.Y());
1015 
1016  OSBitmap* pB = pBitmapList;
1017  while (pB!=nullptr && pB->nID!=nID) pB=pB->pSucc;
1018  if (pB!=nullptr) {
1019  SetRasterOp(aAttr.ePatMix);
1020  pVirDev->DrawBitmapEx(aP1,aSize,pB->aBitmapEx);
1021  }
1022 }
1023 
1024 void OS2METReader::ReadChrStr(bool bGivenPos, bool bMove, bool bExtra, sal_uInt16 nOrderLen)
1025 {
1026  Point aP0;
1027  sal_uInt16 nLen;
1028  OSFont * pF;
1029  vcl::Font aFont;
1030  Size aSize;
1031 
1032  pF = pFontList;
1033  while (pF!=nullptr && pF->nID!=aAttr.nChrSet) pF=pF->pSucc;
1034  if (pF!=nullptr)
1035  aFont = pF->aFont;
1036  aFont.SetColor(aAttr.aChrCol);
1037  aFont.SetFontSize(Size(0,aAttr.aChrCellSize.Height()));
1038  if ( aAttr.nChrAng )
1039  aFont.SetOrientation(aAttr.nChrAng);
1040 
1041  if (bGivenPos)
1042  aP0 = ReadPoint();
1043  else
1044  aP0 = aAttr.aCurPos;
1045  if (bExtra)
1046  {
1047  pOS2MET->SeekRel(2);
1048  ReadPoint( false );
1049  ReadPoint( false );
1050  pOS2MET->ReadUInt16( nLen );
1051  }
1052  else
1053  {
1054  if ( !bGivenPos )
1055  nLen = nOrderLen;
1056  else if ( bCoord32 )
1057  nLen = nOrderLen-8;
1058  else
1059  nLen = nOrderLen-4;
1060  }
1061  if (!pOS2MET->good() || nLen > pOS2MET->remainingSize())
1062  throw css::uno::Exception("attempt to read past end of input", nullptr);
1063  std::unique_ptr<char[]> pChr(new char[nLen+1]);
1064  for (sal_uInt16 i=0; i<nLen; i++)
1065  pOS2MET->ReadChar( pChr[i] );
1066  pChr[nLen] = 0;
1067  OUString aStr( pChr.get(), strlen(pChr.get()), osl_getThreadTextEncoding() );
1068  SetRasterOp(aAttr.eChrMix);
1069  if (pVirDev->GetFont()!=aFont)
1070  pVirDev->SetFont(aFont);
1071  pVirDev->DrawText(aP0,aStr);
1072 
1073  aSize = Size( pVirDev->GetTextWidth(aStr), pVirDev->GetTextHeight() );
1074  if ( !aAttr.nChrAng )
1075  {
1076  aCalcBndRect.Union(tools::Rectangle( Point(aP0.X(),aP0.Y()-aSize.Height()),
1077  Size(aSize.Width(),aSize.Height()*2)));
1078  if (bMove)
1079  aAttr.aCurPos = Point( aP0.X() + aSize.Width(), aP0.Y());
1080  }
1081  else
1082  {
1083  tools::Polygon aDummyPoly(4);
1084 
1085  aDummyPoly.SetPoint( Point( aP0.X(), aP0.Y() ), 0); // TOP LEFT
1086  aDummyPoly.SetPoint( Point( aP0.X(), aP0.Y() - aSize.Height() ), 1); // BOTTOM LEFT
1087  aDummyPoly.SetPoint( Point( aP0.X() + aSize.Width(), aP0.Y() ), 2); // TOP RIGHT
1088  aDummyPoly.SetPoint( Point( aP0.X() + aSize.Width(), aP0.Y() - aSize.Height() ), 3);// BOTTOM RIGHT
1089  aDummyPoly.Rotate( aP0, aAttr.nChrAng );
1090  if ( bMove )
1091  aAttr.aCurPos = aDummyPoly.GetPoint( 0 );
1092  aCalcBndRect.Union( tools::Rectangle( aDummyPoly.GetPoint( 0 ), aDummyPoly.GetPoint( 3 ) ) );
1093  aCalcBndRect.Union( tools::Rectangle( aDummyPoly.GetPoint( 1 ), aDummyPoly.GetPoint( 2 ) ) );
1094  }
1095 }
1096 
1097 void OS2METReader::ReadArc(bool bGivenPos)
1098 {
1099  Point aP1, aP2, aP3;
1100  double x1,y1,x2,y2,x3,y3,p,q,cx,cy,ncx,ncy,r,rx,ry,w1,w3;
1101  if (bGivenPos) aP1=ReadPoint(); else aP1=aAttr.aCurPos;
1102  aP2=ReadPoint(); aP3=ReadPoint();
1103  aAttr.aCurPos=aP3;
1104  SetPen( aAttr.aLinCol, aAttr.nStrLinWidth, aAttr.eLinStyle );
1105  SetRasterOp(aAttr.eLinMix);
1106  // Ok, given are 3 point of the ellipse, and the relation
1107  // of width and height (as p to q):
1108  x1=aP1.X(); y1=aP1.Y();
1109  x2=aP2.X(); y2=aP2.Y();
1110  x3=aP3.X(); y3=aP3.Y();
1111  p=aAttr.nArcP;q=aAttr.nArcQ;
1112  // Calculation of the center point cx, cy of the ellipse:
1113  ncy=2*p*p*((y3-y1)*(x2-x1)-(y1-y2)*(x1-x3));
1114  ncx=2*q*q*(x2-x1);
1115  if ( (ncx<0.001 && ncx>-0.001) || (ncy<0.001 && ncy>-0.001) ) {
1116  // Calculation impossible, points are all on the same straight line
1117  pVirDev->DrawLine(aP1,aP2);
1118  pVirDev->DrawLine(aP2,aP3);
1119  return;
1120  }
1121  cy=( q*q*((x3*x3-x1*x1)*(x2-x1)+(x2*x2-x1*x1)*(x1-x3)) +
1122  p*p*((y3*y3-y1*y1)*(x2-x1)+(y2*y2-y1*y1)*(x1-x3)) ) / ncy;
1123  cx=( q*q*(x2*x2-x1*x1)+p*p*(y2*y2-y1*y1)+cy*2*p*p*(y1-y2) ) / ncx;
1124  // now we still need the radius in x and y direction:
1125  r=sqrt(q*q*(x1-cx)*(x1-cx)+p*p*(y1-cy)*(y1-cy));
1126  rx=r/q; ry=r/p;
1127  // We now have to find out how the starting and the end point
1128  // have to be chosen so that point no. 2 lies inside the drawn arc:
1129  w1=fmod((atan2(x1-cx,y1-cy)-atan2(x2-cx,y2-cy)),6.28318530718); if (w1<0) w1+=6.28318530718;
1130  w3=fmod((atan2(x3-cx,y3-cy)-atan2(x2-cx,y2-cy)),6.28318530718); if (w3<0) w3+=6.28318530718;
1131  if (w3<w1) {
1132  pVirDev->DrawArc(tools::Rectangle(static_cast<sal_Int32>(cx-rx),static_cast<sal_Int32>(cy-ry),
1133  static_cast<sal_Int32>(cx+rx),static_cast<sal_Int32>(cy+ry)),aP1,aP3);
1134  }
1135  else {
1136  pVirDev->DrawArc(tools::Rectangle(static_cast<sal_Int32>(cx-rx),static_cast<sal_Int32>(cy-ry),
1137  static_cast<sal_Int32>(cx+rx),static_cast<sal_Int32>(cy+ry)),aP3,aP1);
1138  }
1139 }
1140 
1141 void OS2METReader::ReadFullArc(bool bGivenPos, sal_uInt16 nOrderSize)
1142 {
1143  Point aCenter;
1144  tools::Rectangle aRect;
1145 
1146  if (bGivenPos) {
1147  aCenter=ReadPoint();
1148  if (bCoord32) nOrderSize-=8; else nOrderSize-=4;
1149  }
1150  else aCenter=aAttr.aCurPos;
1151 
1152  sal_Int32 nP = aAttr.nArcP;
1153  sal_Int32 nQ = aAttr.nArcQ;
1154  if (nP < 0)
1156  if (nQ < 0)
1158  sal_uInt32 nMul(0);
1159  if (nOrderSize>=4)
1160  pOS2MET->ReadUInt32( nMul );
1161  else {
1162  sal_uInt16 nMulS(0);
1163  pOS2MET->ReadUInt16( nMulS );
1164  nMul=static_cast<sal_uInt32>(nMulS)<<8;
1165  }
1166  if (nMul!=0x00010000) {
1167  nP=(nP*nMul)>>16;
1168  nQ=(nQ*nMul)>>16;
1169  }
1170 
1171  aRect=tools::Rectangle(aCenter.X()-nP,aCenter.Y()-nQ,
1172  aCenter.X()+nP,aCenter.Y()+nQ);
1173  aCalcBndRect.Union(aRect);
1174 
1175  if (pAreaStack!=nullptr) {
1176  ChangeBrush(aAttr.aPatCol, aAttr.bFill);
1177  SetRasterOp(aAttr.ePatMix);
1178  if ((pAreaStack->nFlags&0x40)!=0)
1179  SetPen( aAttr.aLinCol, aAttr.nStrLinWidth, aAttr.eLinStyle );
1180  else
1181  SetPen( COL_TRANSPARENT, 0, PEN_NULL );
1182  }
1183  else
1184  {
1185  SetPen( aAttr.aLinCol, aAttr.nStrLinWidth, aAttr.eLinStyle );
1186  ChangeBrush(COL_TRANSPARENT, false);
1187  SetRasterOp(aAttr.eLinMix);
1188  }
1189  pVirDev->DrawEllipse(aRect);
1190 }
1191 
1192 void OS2METReader::ReadPartialArc(bool bGivenPos, sal_uInt16 nOrderSize)
1193 {
1194  Point aP0, aCenter,aPStart,aPEnd;
1195  tools::Rectangle aRect;
1196 
1197  if (bGivenPos) {
1198  aP0=ReadPoint();
1199  if (bCoord32) nOrderSize-=8; else nOrderSize-=4;
1200  }
1201  else aP0=aAttr.aCurPos;
1202  aCenter=ReadPoint();
1203 
1204  sal_Int32 nP = aAttr.nArcP;
1205  sal_Int32 nQ = aAttr.nArcQ;
1206  if (nP < 0)
1208  if (nQ < 0)
1210  sal_uInt32 nMul(0);
1211  if (nOrderSize>=12)
1212  pOS2MET->ReadUInt32( nMul );
1213  else {
1214  sal_uInt16 nMulS(0);
1215  pOS2MET->ReadUInt16( nMulS );
1216  nMul=static_cast<sal_uInt32>(nMulS)<<8;
1217  }
1218  if (nMul!=0x00010000) {
1219  nP=(nP*nMul)>>16;
1220  nQ=(nQ*nMul)>>16;
1221  }
1222 
1223  sal_Int32 nStart(0), nSweep(0);
1224  pOS2MET->ReadInt32( nStart ).ReadInt32( nSweep );
1225  double fStart = static_cast<double>(nStart)/65536.0/180.0*3.14159265359;
1226  double fEnd = fStart+ static_cast<double>(nSweep)/65536.0/180.0*3.14159265359;
1227  aPStart=Point(aCenter.X()+static_cast<sal_Int32>( cos(fStart)*nP),
1228  aCenter.Y()+static_cast<sal_Int32>(-sin(fStart)*nQ));
1229  aPEnd= Point(aCenter.X()+static_cast<sal_Int32>( cos(fEnd)*nP),
1230  aCenter.Y()+static_cast<sal_Int32>(-sin(fEnd)*nQ));
1231 
1232  aRect=tools::Rectangle(aCenter.X()-nP,aCenter.Y()-nQ,
1233  aCenter.X()+nP,aCenter.Y()+nQ);
1234  aCalcBndRect.Union(aRect);
1235 
1236  SetPen( aAttr.aLinCol, aAttr.nStrLinWidth, aAttr.eLinStyle );
1237  SetRasterOp(aAttr.eLinMix);
1238 
1239  pVirDev->DrawLine(aP0,aPStart);
1240  pVirDev->DrawArc(aRect,aPStart,aPEnd);
1241  aAttr.aCurPos=aPEnd;
1242 }
1243 
1244 void OS2METReader::ReadPolygons()
1245 {
1246  tools::PolyPolygon aPolyPoly;
1247  tools::Polygon aPoly;
1248  Point aPoint;
1249 
1250  sal_uInt8 nFlags(0);
1251  sal_uInt32 nNumPolys(0);
1252  pOS2MET->ReadUChar(nFlags).ReadUInt32(nNumPolys);
1253 
1254  if (!pOS2MET->good() || nNumPolys > SAL_MAX_UINT16)
1255  {
1256  pOS2MET->SetError(SVSTREAM_FILEFORMAT_ERROR);
1257  ErrorCode=11;
1258  return;
1259  }
1260 
1261  for (sal_uInt32 i=0; i<nNumPolys; ++i)
1262  {
1263  sal_uInt32 nNumPoints(0);
1264  pOS2MET->ReadUInt32(nNumPoints);
1265  sal_uInt32 nLimit = SAL_MAX_UINT16;
1266  if (i==0) --nLimit;
1267  if (!pOS2MET->good() || nNumPoints > nLimit)
1268  {
1269  pOS2MET->SetError(SVSTREAM_FILEFORMAT_ERROR);
1270  ErrorCode=11;
1271  return;
1272  }
1273  if (i==0) ++nNumPoints;
1274  aPoly.SetSize(static_cast<short>(nNumPoints));
1275  for (sal_uInt32 j=0; j<nNumPoints; ++j)
1276  {
1277  if (i==0 && j==0) aPoint=aAttr.aCurPos;
1278  else aPoint=ReadPoint();
1279  aPoly.SetPoint(aPoint,static_cast<short>(j));
1280  if (i==nNumPolys-1 && j==nNumPoints-1) aAttr.aCurPos=aPoint;
1281  }
1282  aPolyPoly.Insert(aPoly);
1283  }
1284 
1285  ChangeBrush(aAttr.aPatCol, aAttr.bFill);
1286  SetRasterOp(aAttr.ePatMix);
1287  if ((nFlags&0x01)!=0)
1288  SetPen( aAttr.aLinCol, aAttr.nStrLinWidth, aAttr.eLinStyle );
1289  else
1290  SetPen( COL_TRANSPARENT, 0, PEN_NULL );
1291  DrawPolyPolygon( aPolyPoly );
1292 }
1293 
1294 void OS2METReader::ReadBezier(bool bGivenPos, sal_uInt16 nOrderLen)
1295 {
1296  sal_uInt16 i, nNumPoints = nOrderLen / ( bCoord32 ? 8 : 4 );
1297 
1298  if( !bGivenPos )
1299  nNumPoints++;
1300 
1301  if( !nNumPoints )
1302  return;
1303 
1304  tools::Polygon aPolygon( nNumPoints );
1305 
1306  for( i=0; i < nNumPoints; i++ )
1307  {
1308  if( i==0 && !bGivenPos)
1309  aPolygon.SetPoint( aAttr.aCurPos, i );
1310  else
1311  aPolygon.SetPoint( ReadPoint(), i );
1312  }
1313 
1314  if( !( nNumPoints % 4 ) )
1315  {
1316  // create bezier polygon
1317  const sal_uInt16 nSegPoints = 25;
1318  const sal_uInt16 nSegments = aPolygon.GetSize() >> 2;
1319  tools::Polygon aBezPoly( nSegments * nSegPoints );
1320 
1321  sal_uInt16 nSeg, nBezPos, nStartPos;
1322  for( nSeg = 0, nBezPos = 0, nStartPos = 0; nSeg < nSegments; nSeg++, nStartPos += 4 )
1323  {
1324  const tools::Polygon aSegPoly( aPolygon[ nStartPos ], aPolygon[ nStartPos + 1 ],
1325  aPolygon[ nStartPos + 3 ], aPolygon[ nStartPos + 2 ],
1326  nSegPoints );
1327 
1328  for( sal_uInt16 nSegPos = 0; nSegPos < nSegPoints; )
1329  aBezPoly[ nBezPos++ ] = aSegPoly[ nSegPos++ ];
1330  }
1331 
1332  nNumPoints = nBezPos;
1333 
1334  if( nNumPoints != aBezPoly.GetSize() )
1335  aBezPoly.SetSize( nNumPoints );
1336 
1337  aPolygon = aBezPoly;
1338  }
1339 
1340  aAttr.aCurPos = aPolygon[ nNumPoints - 1 ];
1341 
1342  if (pAreaStack!=nullptr)
1343  AddPointsToArea(aPolygon);
1344  else if (pPathStack!=nullptr)
1345  AddPointsToPath(aPolygon);
1346  else
1347  {
1348  SetPen( aAttr.aLinCol, aAttr.nStrLinWidth, aAttr.eLinStyle );
1349  SetRasterOp(aAttr.eLinMix);
1350  DrawPolyLine( aPolygon );
1351  }
1352 }
1353 
1354 void OS2METReader::ReadFillet(bool bGivenPos, sal_uInt16 nOrderLen)
1355 {
1356  sal_uInt16 i,nNumPoints;
1357 
1358  if (bCoord32) nNumPoints=nOrderLen/8; else nNumPoints=nOrderLen/4;
1359  if (!bGivenPos) nNumPoints++;
1360  if (nNumPoints==0) return;
1361  tools::Polygon aPolygon(nNumPoints);
1362  for (i=0; i<nNumPoints; i++) {
1363  if (i==0 && !bGivenPos) aPolygon.SetPoint(aAttr.aCurPos,i);
1364  else aPolygon.SetPoint(ReadPoint(),i);
1365  }
1366  aAttr.aCurPos=aPolygon.GetPoint(nNumPoints-1);
1367  if (pAreaStack!=nullptr) AddPointsToArea(aPolygon);
1368  else if (pPathStack!=nullptr) AddPointsToPath(aPolygon);
1369  else {
1370  SetPen( aAttr.aLinCol, aAttr.nStrLinWidth, aAttr.eLinStyle );
1371  SetRasterOp(aAttr.eLinMix);
1372  DrawPolyLine( aPolygon );
1373  }
1374 }
1375 
1376 void OS2METReader::ReadFilletSharp(bool bGivenPos, sal_uInt16 nOrderLen)
1377 {
1378  sal_uInt16 i,nNumPoints;
1379 
1380  if (bGivenPos) {
1381  aAttr.aCurPos=ReadPoint();
1382  if (bCoord32) nOrderLen-=8; else nOrderLen-=4;
1383  }
1384  if (bCoord32) nNumPoints=1+nOrderLen/10;
1385  else nNumPoints=1+nOrderLen/6;
1386  tools::Polygon aPolygon(nNumPoints);
1387  aPolygon.SetPoint(aAttr.aCurPos,0);
1388  for (i=1; i<nNumPoints; i++) aPolygon.SetPoint(ReadPoint(),i);
1389  aAttr.aCurPos=aPolygon.GetPoint(nNumPoints-1);
1390  if (pAreaStack!=nullptr) AddPointsToArea(aPolygon);
1391  else if (pPathStack!=nullptr) AddPointsToPath(aPolygon);
1392  else
1393  {
1394  SetPen( aAttr.aLinCol, aAttr.nStrLinWidth, aAttr.eLinStyle );
1395  SetRasterOp(aAttr.eLinMix);
1396  DrawPolyLine( aPolygon );
1397  }
1398 }
1399 
1400 void OS2METReader::ReadMarker(bool bGivenPos, sal_uInt16 nOrderLen)
1401 {
1402  sal_uInt16 i,nNumPoints;
1403 
1404  SetPen( aAttr.aMrkCol );
1405  SetRasterOp(aAttr.eMrkMix);
1406  if (aAttr.nMrkSymbol>=5 && aAttr.nMrkSymbol<=9)
1407  {
1408  ChangeBrush(aAttr.aMrkCol, true);
1409  }
1410  else
1411  {
1412  ChangeBrush(COL_TRANSPARENT, false);
1413  }
1414  if (bCoord32) nNumPoints=nOrderLen/8; else nNumPoints=nOrderLen/4;
1415  if (!bGivenPos) nNumPoints++;
1416  for (i=0; i<nNumPoints; i++) {
1417  if (i!=0 || bGivenPos) aAttr.aCurPos=ReadPoint();
1418  const auto x = aAttr.aCurPos.X();
1419  const auto y = aAttr.aCurPos.Y();
1420  aCalcBndRect.Union(tools::Rectangle(x-5,y-5,x+5,y+5));
1421  switch (aAttr.nMrkSymbol) {
1422  case 2: // PLUS
1423  pVirDev->DrawLine(Point(x-4,y),Point(x+4,y));
1424  pVirDev->DrawLine(Point(x,y-4),Point(x,y+4));
1425  break;
1426  case 3: // DIAMOND
1427  case 7: { // SOLIDDIAMOND
1428  tools::Polygon aPoly(4);
1429  aPoly.SetPoint(Point(x,y+4),0);
1430  aPoly.SetPoint(Point(x+4,y),1);
1431  aPoly.SetPoint(Point(x,y-4),2);
1432  aPoly.SetPoint(Point(x-4,y),3);
1433  pVirDev->DrawPolygon(aPoly);
1434  break;
1435  }
1436  case 4: // SQUARE
1437  case 8: { // SOLIDSUARE
1438  tools::Polygon aPoly(4);
1439  aPoly.SetPoint(Point(x+4,y+4),0);
1440  aPoly.SetPoint(Point(x+4,y-4),1);
1441  aPoly.SetPoint(Point(x-4,y-4),2);
1442  aPoly.SetPoint(Point(x-4,y+4),3);
1443  pVirDev->DrawPolygon(aPoly);
1444  break;
1445  }
1446  case 5: { // SIXPOINTSTAR
1447  tools::Polygon aPoly(12);
1448  aPoly.SetPoint(Point(x ,y-4),0);
1449  aPoly.SetPoint(Point(x+2,y-2),1);
1450  aPoly.SetPoint(Point(x+4,y-2),2);
1451  aPoly.SetPoint(Point(x+2,y ),3);
1452  aPoly.SetPoint(Point(x+4,y+2),4);
1453  aPoly.SetPoint(Point(x+2,y+2),5);
1454  aPoly.SetPoint(Point(x ,y+4),6);
1455  aPoly.SetPoint(Point(x-2,y+2),7);
1456  aPoly.SetPoint(Point(x-4,y+2),8);
1457  aPoly.SetPoint(Point(x-2,y ),9);
1458  aPoly.SetPoint(Point(x-4,y-2),10);
1459  aPoly.SetPoint(Point(x-2,y-2),11);
1460  pVirDev->DrawPolygon(aPoly);
1461  break;
1462  }
1463  case 6: { // EIGHTPOINTSTAR
1464  tools::Polygon aPoly(16);
1465  aPoly.SetPoint(Point(x ,y-4),0);
1466  aPoly.SetPoint(Point(x+1,y-2),1);
1467  aPoly.SetPoint(Point(x+3,y-3),2);
1468  aPoly.SetPoint(Point(x+2,y-1),3);
1469  aPoly.SetPoint(Point(x+4,y ),4);
1470  aPoly.SetPoint(Point(x+2,y+1),5);
1471  aPoly.SetPoint(Point(x+3,y+3),6);
1472  aPoly.SetPoint(Point(x+1,y+2),7);
1473  aPoly.SetPoint(Point(x ,y+4),8);
1474  aPoly.SetPoint(Point(x-1,y+2),9);
1475  aPoly.SetPoint(Point(x-3,y+3),10);
1476  aPoly.SetPoint(Point(x-2,y+1),11);
1477  aPoly.SetPoint(Point(x-4,y ),12);
1478  aPoly.SetPoint(Point(x-2,y-1),13);
1479  aPoly.SetPoint(Point(x-3,y-3),14);
1480  aPoly.SetPoint(Point(x-1,y-2),15);
1481  pVirDev->DrawPolygon(aPoly);
1482  break;
1483  }
1484  case 9: // DOT
1485  pVirDev->DrawEllipse(tools::Rectangle(x-1,y-1,x+1,y+1));
1486  break;
1487  case 10: // SMALLCIRCLE
1488  pVirDev->DrawEllipse(tools::Rectangle(x-2,y-2,x+2,y+2));
1489  break;
1490  case 64: // BLANK
1491  break;
1492  default: // (=1) CROSS
1493  pVirDev->DrawLine(Point(x-4,y-4),Point(x+4,y+4));
1494  pVirDev->DrawLine(Point(x-4,y+4),Point(x+4,y-4));
1495  break;
1496  }
1497  }
1498 }
1499 
1500 void OS2METReader::ReadOrder(sal_uInt16 nOrderID, sal_uInt16 nOrderLen)
1501 {
1502  switch (nOrderID) {
1503 
1504  case GOrdGivArc: ReadArc(true); break;
1505  case GOrdCurArc: ReadArc(false); break;
1506 
1507  case GOrdGivBzr: ReadBezier(true,nOrderLen); break;
1508  case GOrdCurBzr: ReadBezier(false,nOrderLen); break;
1509 
1510  case GOrdGivBox: ReadBox(true); break;
1511  case GOrdCurBox: ReadBox(false); break;
1512 
1513  case GOrdGivFil: ReadFillet(true,nOrderLen); break;
1514  case GOrdCurFil: ReadFillet(false,nOrderLen); break;
1515 
1516  case GOrdGivCrc: ReadFullArc(true,nOrderLen); break;
1517  case GOrdCurCrc: ReadFullArc(false,nOrderLen); break;
1518 
1519  case GOrdGivLin: ReadLine(true, nOrderLen); break;
1520  case GOrdCurLin: ReadLine(false, nOrderLen); break;
1521 
1522  case GOrdGivMrk: ReadMarker(true, nOrderLen); break;
1523  case GOrdCurMrk: ReadMarker(false, nOrderLen); break;
1524 
1525  case GOrdGivArP: ReadPartialArc(true,nOrderLen); break;
1526  case GOrdCurArP: ReadPartialArc(false,nOrderLen); break;
1527 
1528  case GOrdGivRLn: ReadRelLine(true,nOrderLen); break;
1529  case GOrdCurRLn: ReadRelLine(false,nOrderLen); break;
1530 
1531  case GOrdGivSFl: ReadFilletSharp(true,nOrderLen); break;
1532  case GOrdCurSFl: ReadFilletSharp(false,nOrderLen); break;
1533 
1534  case GOrdGivStM: ReadChrStr(true , true , false, nOrderLen); break;
1535  case GOrdCurStM: ReadChrStr(false, true , false, nOrderLen); break;
1536  case GOrdGivStr: ReadChrStr(true , false, false, nOrderLen); break;
1537  case GOrdCurStr: ReadChrStr(false, false, false, nOrderLen); break;
1538  case GOrdGivStx: ReadChrStr(true , false, true , nOrderLen); break;
1539  case GOrdCurStx: ReadChrStr(false, false, true , nOrderLen); break;
1540 
1541  case GOrdGivImg: SAL_INFO("filter.os2met","GOrdGivImg");
1542  break;
1543  case GOrdCurImg: SAL_INFO("filter.os2met","GOrdCurImg");
1544  break;
1545  case GOrdImgDat: SAL_INFO("filter.os2met","GOrdImgDat");
1546  break;
1547  case GOrdEndImg: SAL_INFO("filter.os2met","GOrdEndImg");
1548  break;
1549 
1550  case GOrdBegAra: {
1551  OSArea * p=new OSArea;
1552  p->bClosed=false;
1553  p->pSucc=pAreaStack; pAreaStack=p;
1554  pOS2MET->ReadUChar( p->nFlags );
1555  p->aCol=aAttr.aPatCol;
1556  p->aBgCol=aAttr.aPatBgCol;
1557  p->eMix=aAttr.ePatMix;
1558  p->eBgMix=aAttr.ePatBgMix;
1559  p->bFill=aAttr.bFill;
1560  break;
1561  }
1562  case GOrdEndAra:
1563  {
1564  OSArea * p=pAreaStack;
1565  if ( p )
1566  {
1567  pAreaStack = p->pSucc;
1568  if ( pPathStack )
1569  {
1570  for ( sal_uInt16 i=0; i<p->aPPoly.Count(); i++ )
1571  {
1572  AddPointsToPath( p->aPPoly.GetObject( i ) );
1573  CloseFigure();
1574  }
1575  }
1576  else
1577  {
1578  if ( ( p->nFlags & 0x40 ) == 0 )
1579  SetPen( COL_TRANSPARENT, 0, PEN_NULL );
1580  else
1581  SetPen( aAttr.aLinCol, aAttr.nStrLinWidth, aAttr.eLinStyle );
1582 
1583  ChangeBrush(p->aCol, p->bFill);
1584  SetRasterOp(p->eMix);
1585  DrawPolyPolygon( p->aPPoly );
1586  }
1587  delete p;
1588  }
1589  }
1590  break;
1591 
1592  case GOrdBegElm: SAL_INFO("filter.os2met","GOrdBegElm");
1593  break;
1594  case GOrdEndElm: SAL_INFO("filter.os2met","GOrdEndElm");
1595  break;
1596 
1597  case GOrdBegPth: {
1598  OSPath * p=new OSPath;
1599  p->pSucc=pPathStack; pPathStack=p;
1600  pOS2MET->SeekRel(2);
1601  pOS2MET->ReadUInt32( p->nID );
1602  p->bClosed=false;
1603  p->bStroke=false;
1604  break;
1605  }
1606  case GOrdEndPth: {
1607  OSPath * p, * pprev, * psucc;
1608  if (pPathStack==nullptr) break;
1609  p=pPathList; pprev=nullptr;
1610  while (p!=nullptr) {
1611  psucc=p->pSucc;
1612  if (p->nID==pPathStack->nID) {
1613  if (pprev==nullptr) pPathList=psucc; else pprev->pSucc=psucc;
1614  delete p;
1615  }
1616  else pprev=p;
1617  p=psucc;
1618  }
1619  p=pPathStack;
1620  pPathStack=p->pSucc;
1621  p->pSucc=pPathList; pPathList=p;
1622  break;
1623  }
1624  case GOrdFilPth:
1625  {
1626  sal_uInt32 nID(0);
1627  sal_uInt16 nDummy(0);
1628  OSPath* p = pPathList;
1629 
1630  pOS2MET->ReadUInt16( nDummy )
1631  .ReadUInt32( nID );
1632 
1633  if ( ! ( nDummy & 0x20 ) ) // #30933# i do not know the exact meaning of this bit,
1634  { // but if set it seems to be better not to fill this path
1635  while( p && p->nID != nID )
1636  p = p->pSucc;
1637 
1638  if( p )
1639  {
1640  if( p->bStroke )
1641  {
1642  SetPen( aAttr.aPatCol, aAttr.nStrLinWidth );
1643  ChangeBrush(COL_TRANSPARENT, false);
1644  SetRasterOp( aAttr.ePatMix );
1645  if ( IsLineInfo() )
1646  {
1647  for ( sal_uInt16 i = 0; i < p->aPPoly.Count(); i++ )
1648  pVirDev->DrawPolyLine( p->aPPoly.GetObject( i ), aLineInfo );
1649  }
1650  else
1651  pVirDev->DrawPolyPolygon( p->aPPoly );
1652  }
1653  else
1654  {
1655  SetPen( COL_TRANSPARENT, 0, PEN_NULL );
1656  ChangeBrush( aAttr.aPatCol, aAttr.bFill );
1657  SetRasterOp( aAttr.ePatMix );
1658  pVirDev->DrawPolyPolygon( p->aPPoly );
1659  }
1660  }
1661  }
1662  }
1663  break;
1664 
1665  case GOrdModPth:
1666  {
1667  OSPath* p = pPathList;
1668 
1669  while( p && p->nID != 1 )
1670  p = p->pSucc;
1671 
1672  if( p )
1673  p->bStroke = true;
1674  }
1675  break;
1676 
1677  case GOrdOutPth:
1678  {
1679  sal_uInt32 nID;
1680  sal_uInt16 i,nC;
1681  OSPath* p=pPathList;
1682  pOS2MET->SeekRel(2);
1683  pOS2MET->ReadUInt32( nID );
1684  while (p && pOS2MET->good() && p->nID != nID)
1685  p = p->pSucc;
1686 
1687  if (p)
1688  {
1689  SetPen( aAttr.aLinCol, aAttr.nStrLinWidth, aAttr.eLinStyle );
1690  SetRasterOp(aAttr.eLinMix);
1691  ChangeBrush(COL_TRANSPARENT, false);
1692  nC=p->aPPoly.Count();
1693  for (i=0; i<nC; i++)
1694  {
1695  if (i+1<nC || p->bClosed)
1696  DrawPolygon( p->aPPoly.GetObject( i ) );
1697  else
1698  DrawPolyLine( p->aPPoly.GetObject( i ) );
1699  }
1700  }
1701  break;
1702  }
1703  case GOrdSClPth: {
1704  SAL_INFO("filter.os2met","GOrdSClPth");
1705  sal_uInt32 nID(0);
1706  OSPath * p=pPathList;
1707  pOS2MET->SeekRel(2);
1708  pOS2MET->ReadUInt32( nID );
1709  if (nID==0) p=nullptr;
1710  while (p!=nullptr && p->nID!=nID) p=p->pSucc;
1711  if (p!=nullptr) pVirDev->SetClipRegion(vcl::Region(p->aPPoly));
1712  else pVirDev->SetClipRegion();
1713  break;
1714  }
1715  case GOrdNopNop:
1716  break;
1717  case GOrdRemark: SAL_INFO("filter.os2met","GOrdRemark");
1718  break;
1719  case GOrdSegLab: SAL_INFO("filter.os2met","GOrdSegLab");
1720  break;
1721 
1722  case GOrdBitBlt: ReadBitBlt(); break;
1723 
1724  case GOrdCalSeg: SAL_INFO("filter.os2met","GOrdCalSeg");
1725  break;
1726  case GOrdSSgBnd: SAL_INFO("filter.os2met","GOrdSSgBnd");
1727  break;
1728  case GOrdSegChr: SAL_INFO("filter.os2met","GOrdSegChr");
1729  break;
1730  case GOrdCloFig:
1731  CloseFigure();
1732  break;
1733  case GOrdEndSym: SAL_INFO("filter.os2met","GOrdEndSym");
1734  break;
1735  case GOrdEndPlg: SAL_INFO("filter.os2met","GOrdEndPlg");
1736  break;
1737  case GOrdEscape: SAL_INFO("filter.os2met","GOrdEscape");
1738  break;
1739  case GOrdExtEsc: SAL_INFO("filter.os2met","GOrdExtEsc");
1740  break;
1741 
1742  case GOrdPolygn: ReadPolygons(); break;
1743 
1744  case GOrdStkPop: PopAttr(); break;
1745 
1746  case GOrdPIvAtr: PushAttr(nOrderID);
1747  [[fallthrough]];
1748  case GOrdSIvAtr: {
1749  sal_uInt8 nA(0), nP(0), nFlags(0);
1750  Color aCol;
1751  RasterOp eROP;
1752  pOS2MET->ReadUChar( nA ).ReadUChar( nP ).ReadUChar( nFlags );
1753  if (nOrderID==GOrdPIvAtr) {
1754  pAttrStack->nIvAttrA=nA;
1755  pAttrStack->nIvAttrP=nP;
1756  }
1757  if (nA<=2) {
1758  if ((nFlags&0x80)!=0) {
1759  if (nA==1) switch (nP) {
1760  case 1: aAttr.aLinCol=aDefAttr.aLinCol; break;
1761  case 2: aAttr.aChrCol=aDefAttr.aChrCol; break;
1762  case 3: aAttr.aMrkCol=aDefAttr.aMrkCol; break;
1763  case 4: aAttr.aPatCol=aDefAttr.aPatCol; break;
1764  case 5: aAttr.aImgCol=aDefAttr.aImgCol; break;
1765  }
1766  else switch (nP) {
1767  case 1: aAttr.aLinBgCol=aDefAttr.aLinBgCol; break;
1768  case 2: aAttr.aChrBgCol=aDefAttr.aChrBgCol; break;
1769  case 3: aAttr.aMrkBgCol=aDefAttr.aMrkBgCol; break;
1770  case 4: aAttr.aPatBgCol=aDefAttr.aPatBgCol; break;
1771  case 5: aAttr.aImgBgCol=aDefAttr.aImgBgCol; break;
1772  }
1773  }
1774  else {
1775  const auto nVal = ReadLittleEndian3BytesLong();
1776  if ((nFlags&0x40)!=0 && nVal==1) aCol=COL_BLACK;
1777  else if ((nFlags&0x40)!=0 && nVal==2) aCol=COL_WHITE;
1778  else if ((nFlags&0x40)!=0 && nVal==4) aCol=COL_WHITE;
1779  else if ((nFlags&0x40)!=0 && nVal==5) aCol=COL_BLACK;
1780  else aCol=GetPaletteColor(nVal);
1781  if (nA==1) switch (nP) {
1782  case 1: aAttr.aLinCol=aCol; break;
1783  case 2: aAttr.aChrCol=aCol; break;
1784  case 3: aAttr.aMrkCol=aCol; break;
1785  case 4: aAttr.aPatCol=aCol; break;
1786  case 5: aAttr.aImgCol=aCol; break;
1787  }
1788  else switch (nP) {
1789  case 1: aAttr.aLinBgCol=aCol; break;
1790  case 2: aAttr.aChrBgCol=aCol; break;
1791  case 3: aAttr.aMrkBgCol=aCol; break;
1792  case 4: aAttr.aPatBgCol=aCol; break;
1793  case 5: aAttr.aImgBgCol=aCol; break;
1794  }
1795  }
1796  }
1797  else {
1798  sal_uInt8 nMix(0);
1799  pOS2MET->ReadUChar( nMix );
1800  if (nMix==0) {
1801  switch (nP) {
1802  case 1: aAttr.eLinBgMix=aDefAttr.eLinBgMix; break;
1803  case 2: aAttr.eChrBgMix=aDefAttr.eChrBgMix; break;
1804  case 3: aAttr.eMrkBgMix=aDefAttr.eMrkBgMix; break;
1805  case 4: aAttr.ePatBgMix=aDefAttr.ePatBgMix; break;
1806  case 5: aAttr.eImgBgMix=aDefAttr.eImgBgMix; break;
1807  }
1808  }
1809  else {
1810  eROP=OS2MixToRasterOp(nMix);
1811  switch (nP) {
1812  case 1: aAttr.eLinBgMix=eROP; break;
1813  case 2: aAttr.eChrBgMix=eROP; break;
1814  case 3: aAttr.eMrkBgMix=eROP; break;
1815  case 4: aAttr.ePatBgMix=eROP; break;
1816  case 5: aAttr.eImgBgMix=eROP; break;
1817  }
1818  }
1819  }
1820  break;
1821  }
1822  case GOrdPIxCol: PushAttr(nOrderID);
1823  [[fallthrough]];
1824  case GOrdSIxCol: {
1825  sal_uInt8 nFlags(0);
1826  pOS2MET->ReadUChar( nFlags );
1827  if ((nFlags&0x80)!=0) {
1828  aAttr.aLinCol=aDefAttr.aLinCol;
1829  aAttr.aChrCol=aDefAttr.aChrCol;
1830  aAttr.aMrkCol=aDefAttr.aMrkCol;
1831  aAttr.aPatCol=aDefAttr.aPatCol;
1832  aAttr.aImgCol=aDefAttr.aImgCol;
1833  }
1834  else {
1835  Color aCol;
1836  const auto nVal = ReadLittleEndian3BytesLong();
1837  if ((nFlags&0x40)!=0 && nVal==1) aCol=COL_BLACK;
1838  else if ((nFlags&0x40)!=0 && nVal==2) aCol=COL_WHITE;
1839  else if ((nFlags&0x40)!=0 && nVal==4) aCol=COL_WHITE;
1840  else if ((nFlags&0x40)!=0 && nVal==5) aCol=COL_BLACK;
1841  else aCol=GetPaletteColor(nVal);
1842  aAttr.aLinCol = aAttr.aChrCol = aAttr.aMrkCol = aAttr.aPatCol =
1843  aAttr.aImgCol = aCol;
1844  }
1845  break;
1846  }
1847 
1848  case GOrdPColor:
1849  case GOrdPXtCol: PushAttr(nOrderID);
1850  [[fallthrough]];
1851  case GOrdSColor:
1852  case GOrdSXtCol: {
1853  sal_uInt16 nVal(0);
1854  if (nOrderID==GOrdPColor || nOrderID==GOrdSColor) {
1855  sal_uInt8 nbyte(0);
1856  pOS2MET->ReadUChar( nbyte ); nVal=static_cast<sal_uInt16>(nbyte)|0xff00;
1857  }
1858  else pOS2MET->ReadUInt16( nVal );
1859  if (nVal==0x0000 || nVal==0xff00) {
1860  aAttr.aLinCol=aDefAttr.aLinCol;
1861  aAttr.aChrCol=aDefAttr.aChrCol;
1862  aAttr.aMrkCol=aDefAttr.aMrkCol;
1863  aAttr.aPatCol=aDefAttr.aPatCol;
1864  aAttr.aImgCol=aDefAttr.aImgCol;
1865  }
1866  else {
1867  Color aCol;
1868  if (nVal==0x0007) aCol=COL_WHITE;
1869  else if (nVal==0x0008) aCol=COL_BLACK;
1870  else if (nVal==0xff08) aCol=GetPaletteColor(1);
1871  else aCol=GetPaletteColor(static_cast<sal_uInt32>(nVal) & 0x000000ff);
1872  aAttr.aLinCol = aAttr.aChrCol = aAttr.aMrkCol = aAttr.aPatCol =
1873  aAttr.aImgCol = aCol;
1874  }
1875  break;
1876  }
1877 
1878  case GOrdPBgCol: PushAttr(nOrderID);
1879  [[fallthrough]];
1880  case GOrdSBgCol: {
1881  sal_uInt16 nVal(0);
1882  pOS2MET->ReadUInt16( nVal );
1883  if (nVal==0x0000 || nVal==0xff00) {
1884  aAttr.aLinBgCol=aDefAttr.aLinBgCol;
1885  aAttr.aChrBgCol=aDefAttr.aChrBgCol;
1886  aAttr.aMrkBgCol=aDefAttr.aMrkBgCol;
1887  aAttr.aPatBgCol=aDefAttr.aPatBgCol;
1888  aAttr.aImgBgCol=aDefAttr.aImgBgCol;
1889  }
1890  else {
1891  Color aCol;
1892  if (nVal==0x0007) aCol=COL_WHITE;
1893  else if (nVal==0x0008) aCol=COL_BLACK;
1894  else if (nVal==0xff08) aCol=GetPaletteColor(0);
1895  else aCol=GetPaletteColor(static_cast<sal_uInt32>(nVal) & 0x000000ff);
1896  aAttr.aLinBgCol = aAttr.aChrBgCol = aAttr.aMrkBgCol =
1897  aAttr.aPatBgCol = aAttr.aImgBgCol = aCol;
1898  }
1899  break;
1900  }
1901  case GOrdPBxCol: PushAttr(nOrderID);
1902  [[fallthrough]];
1903  case GOrdSBxCol: {
1904  sal_uInt8 nFlags(0);
1905  pOS2MET->ReadUChar( nFlags );
1906  if ((nFlags&0x80)!=0) {
1907  aAttr.aLinBgCol=aDefAttr.aLinBgCol;
1908  aAttr.aChrBgCol=aDefAttr.aChrBgCol;
1909  aAttr.aMrkBgCol=aDefAttr.aMrkBgCol;
1910  aAttr.aPatBgCol=aDefAttr.aPatBgCol;
1911  aAttr.aImgBgCol=aDefAttr.aImgBgCol;
1912  }
1913  else {
1914  Color aCol;
1915  const auto nVal = ReadLittleEndian3BytesLong();
1916  if ((nFlags&0x40)!=0 && nVal==1) aCol=COL_BLACK;
1917  else if ((nFlags&0x40)!=0 && nVal==2) aCol=COL_WHITE;
1918  else if ((nFlags&0x40)!=0 && nVal==4) aCol=COL_WHITE;
1919  else if ((nFlags&0x40)!=0 && nVal==5) aCol=COL_BLACK;
1920  else aCol=GetPaletteColor(nVal);
1921  aAttr.aLinBgCol = aAttr.aChrBgCol = aAttr.aMrkBgCol =
1922  aAttr.aPatBgCol = aAttr.aImgBgCol = aCol;
1923  }
1924  break;
1925  }
1926 
1927  case GOrdPMixMd: PushAttr(nOrderID);
1928  [[fallthrough]];
1929  case GOrdSMixMd: {
1930  sal_uInt8 nMix(0);
1931  pOS2MET->ReadUChar( nMix );
1932  if (nMix==0) {
1933  aAttr.eLinMix=aDefAttr.eLinMix;
1934  aAttr.eChrMix=aDefAttr.eChrMix;
1935  aAttr.eMrkMix=aDefAttr.eMrkMix;
1936  aAttr.ePatMix=aDefAttr.ePatMix;
1937  aAttr.eImgMix=aDefAttr.eImgMix;
1938  }
1939  else {
1940  aAttr.eLinMix = aAttr.eChrMix = aAttr.eMrkMix =
1941  aAttr.ePatMix = aAttr.eImgMix = OS2MixToRasterOp(nMix);
1942  }
1943  break;
1944  }
1945  case GOrdPBgMix: PushAttr(nOrderID);
1946  [[fallthrough]];
1947  case GOrdSBgMix: {
1948  sal_uInt8 nMix(0);
1949  pOS2MET->ReadUChar( nMix );
1950  if (nMix==0) {
1951  aAttr.eLinBgMix=aDefAttr.eLinBgMix;
1952  aAttr.eChrBgMix=aDefAttr.eChrBgMix;
1953  aAttr.eMrkBgMix=aDefAttr.eMrkBgMix;
1954  aAttr.ePatBgMix=aDefAttr.ePatBgMix;
1955  aAttr.eImgBgMix=aDefAttr.eImgBgMix;
1956  }
1957  else {
1958  aAttr.eLinBgMix = aAttr.eChrBgMix = aAttr.eMrkBgMix =
1959  aAttr.ePatBgMix = aAttr.eImgBgMix = OS2MixToRasterOp(nMix);
1960  }
1961  break;
1962  }
1963  case GOrdPPtSet: PushAttr(nOrderID);
1964  [[fallthrough]];
1965  case GOrdSPtSet: SAL_INFO("filter.os2met","GOrdSPtSet");
1966  break;
1967 
1968  case GOrdPPtSym: PushAttr(nOrderID);
1969  [[fallthrough]];
1970  case GOrdSPtSym: {
1971  sal_uInt8 nPatt(0);
1972  pOS2MET->ReadUChar( nPatt );
1973  aAttr.bFill = ( nPatt != 0x0f );
1974  break;
1975  }
1976 
1977  case GOrdPPtRef: PushAttr(nOrderID);
1978  [[fallthrough]];
1979  case GOrdSPtRef: SAL_INFO("filter.os2met","GOrdSPtRef");
1980  break;
1981 
1982  case GOrdPLnEnd: PushAttr(nOrderID);
1983  [[fallthrough]];
1984  case GOrdSLnEnd:
1985  break;
1986 
1987  case GOrdPLnJoi: PushAttr(nOrderID);
1988  [[fallthrough]];
1989  case GOrdSLnJoi:
1990  break;
1991 
1992  case GOrdPLnTyp: PushAttr(nOrderID);
1993  [[fallthrough]];
1994  case GOrdSLnTyp: {
1995  sal_uInt8 nType(0);
1996  pOS2MET->ReadUChar( nType );
1997  switch (nType) {
1998  case 0: aAttr.eLinStyle=aDefAttr.eLinStyle; break;
1999  case 1: case 4: aAttr.eLinStyle=PEN_DOT; break;
2000  case 2: case 5: aAttr.eLinStyle=PEN_DASH; break;
2001  case 3: case 6: aAttr.eLinStyle=PEN_DASHDOT; break;
2002  case 8: aAttr.eLinStyle=PEN_NULL; break;
2003  default: aAttr.eLinStyle=PEN_SOLID;
2004  }
2005  break;
2006  }
2007  case GOrdPLnWdt: PushAttr(nOrderID);
2008  [[fallthrough]];
2009  case GOrdSLnWdt: {
2010  sal_uInt8 nbyte(0);
2011  pOS2MET->ReadUChar( nbyte );
2012  if (nbyte==0) aAttr.nLinWidth=aDefAttr.nLinWidth;
2013  else aAttr.nLinWidth=static_cast<sal_uInt16>(nbyte)-1;
2014  break;
2015  }
2016  case GOrdPFrLWd: PushAttr(nOrderID);
2017  [[fallthrough]];
2018  case GOrdSFrLWd:
2019  break;
2020 
2021  case GOrdPStLWd: PushAttr(nOrderID);
2022  [[fallthrough]];
2023  case GOrdSStLWd :
2024  {
2025  sal_uInt8 nFlags(0);
2026 
2027  pOS2MET->ReadUChar( nFlags );
2028  if ( nFlags & 0x80 )
2029  aAttr.nStrLinWidth = aDefAttr.nStrLinWidth;
2030  else
2031  {
2032  pOS2MET->SeekRel( 1 );
2033  sal_Int32 nWd = ReadCoord( bCoord32 );
2034  if (nWd < 0)
2035  nWd = o3tl::saturating_toggle_sign(nWd);
2036  aAttr.nStrLinWidth = static_cast<sal_uInt16>(nWd);
2037  }
2038  break;
2039  }
2040  case GOrdPChDir: PushAttr(nOrderID);
2041  [[fallthrough]];
2042  case GOrdSChDir:
2043  break;
2044 
2045  case GOrdPChPrc: PushAttr(nOrderID);
2046  [[fallthrough]];
2047  case GOrdSChPrc:
2048  break;
2049 
2050  case GOrdPChSet: PushAttr(nOrderID);
2051  [[fallthrough]];
2052  case GOrdSChSet: {
2053  sal_uInt8 nbyte(0);
2054  pOS2MET->ReadUChar( nbyte );
2055  aAttr.nChrSet=static_cast<sal_uInt32>(nbyte)&0xff;
2056  break;
2057  }
2058  case GOrdPChAng: PushAttr(nOrderID);
2059  [[fallthrough]];
2060  case GOrdSChAng: {
2061  sal_Int32 nX = ReadCoord(bCoord32);
2062  sal_Int32 nY = ReadCoord(bCoord32);
2063  if (nX>=0 && nY==0) aAttr.nChrAng=0_deg10;
2064  else {
2065  aAttr.nChrAng = Degree10(static_cast<short>(atan2(static_cast<double>(nY),static_cast<double>(nX))/3.1415926539*1800.0));
2066  while (aAttr.nChrAng < 0_deg10) aAttr.nChrAng += 3600_deg10;
2067  aAttr.nChrAng %= 3600_deg10;
2068  }
2069  break;
2070  }
2071  case GOrdPChBrx: PushAttr(nOrderID);
2072  [[fallthrough]];
2073  case GOrdSChBrx:
2074  break;
2075 
2076  case GOrdPChCel: PushAttr(nOrderID);
2077  [[fallthrough]];
2078  case GOrdSChCel: {
2079  sal_uInt16 nLen=nOrderLen;
2080  auto nWidth = ReadCoord(bCoord32);
2081  auto nHeight = ReadCoord(bCoord32);
2082  if (nWidth < 0 || nHeight < 0)
2083  aAttr.aChrCellSize = aDefAttr.aChrCellSize;
2084  else
2085  aAttr.aChrCellSize = Size(nWidth, nHeight);
2086  if (bCoord32) nLen-=8; else nLen-=4;
2087  if (nLen>=4) {
2088  pOS2MET->SeekRel(4); nLen-=4;
2089  }
2090  if (nLen>=2) {
2091  sal_uInt8 nbyte(0);
2092  pOS2MET->ReadUChar( nbyte );
2093  if ((nbyte&0x80)==0 && aAttr.aChrCellSize==Size(0,0))
2094  aAttr.aChrCellSize = aDefAttr.aChrCellSize;
2095  }
2096  break;
2097  }
2098  case GOrdPChXtr: PushAttr(nOrderID);
2099  [[fallthrough]];
2100  case GOrdSChXtr:
2101  break;
2102 
2103  case GOrdPChShr: PushAttr(nOrderID);
2104  [[fallthrough]];
2105  case GOrdSChShr:
2106  break;
2107 
2108  case GOrdPTxAlg: PushAttr(nOrderID);
2109  [[fallthrough]];
2110  case GOrdSTxAlg: SAL_INFO("filter.os2met","GOrdSTxAlg");
2111  break;
2112 
2113  case GOrdPMkPrc: PushAttr(nOrderID);
2114  [[fallthrough]];
2115  case GOrdSMkPrc: {
2116  sal_uInt8 nbyte(0);
2117  pOS2MET->ReadUChar( nbyte );
2118  if (nbyte==0) aAttr.nMrkPrec=aDefAttr.nMrkPrec;
2119  else aAttr.nMrkPrec=nbyte;
2120  break;
2121  }
2122 
2123  case GOrdPMkSet: PushAttr(nOrderID);
2124  [[fallthrough]];
2125  case GOrdSMkSet: {
2126  sal_uInt8 nbyte(0);
2127  pOS2MET->ReadUChar( nbyte );
2128  if (nbyte==0) aAttr.nMrkSet=aDefAttr.nMrkSet;
2129  else aAttr.nMrkSet=nbyte;
2130  break;
2131  }
2132 
2133  case GOrdPMkSym: PushAttr(nOrderID);
2134  [[fallthrough]];
2135  case GOrdSMkSym: {
2136  sal_uInt8 nbyte(0);
2137  pOS2MET->ReadUChar( nbyte );
2138  if (nbyte==0) aAttr.nMrkSymbol=aDefAttr.nMrkSymbol;
2139  else aAttr.nMrkSymbol=nbyte;
2140  break;
2141  }
2142 
2143  case GOrdPMkCel: PushAttr(nOrderID);
2144  [[fallthrough]];
2145  case GOrdSMkCel: {
2146  sal_uInt16 nLen=nOrderLen;
2147  aAttr.aMrkCellSize.setWidth(ReadCoord(bCoord32) );
2148  aAttr.aMrkCellSize.setHeight(ReadCoord(bCoord32) );
2149  if (bCoord32) nLen-=8; else nLen-=4;
2150  if (nLen>=2) {
2151  sal_uInt8 nbyte(0);
2152  pOS2MET->ReadUChar( nbyte );
2153  if ((nbyte&0x80)==0 && aAttr.aMrkCellSize==Size(0,0))
2154  aAttr.aMrkCellSize=aDefAttr.aMrkCellSize;
2155  }
2156  break;
2157  }
2158 
2159  case GOrdPArcPa: PushAttr(nOrderID);
2160  [[fallthrough]];
2161  case GOrdSArcPa:
2162  aAttr.nArcP=ReadCoord(bCoord32);
2163  aAttr.nArcQ=ReadCoord(bCoord32);
2164  aAttr.nArcR=ReadCoord(bCoord32);
2165  aAttr.nArcS=ReadCoord(bCoord32);
2166  break;
2167 
2168  case GOrdPCrPos: PushAttr(nOrderID);
2169  [[fallthrough]];
2170  case GOrdSCrPos:
2171  aAttr.aCurPos=ReadPoint();
2172  break;
2173 
2174  case GOrdPMdTrn: PushAttr(nOrderID);
2175  [[fallthrough]];
2176  case GOrdSMdTrn: SAL_INFO("filter.os2met","GOrdSMdTrn");
2177  break;
2178 
2179  case GOrdPPkIdn: PushAttr(nOrderID);
2180  [[fallthrough]];
2181  case GOrdSPkIdn: SAL_INFO("filter.os2met","GOrdSPkIdn");
2182  break;
2183 
2184  case GOrdSVwTrn: SAL_INFO("filter.os2met","GOrdSVwTrn");
2185  break;
2186 
2187  case GOrdPVwWin: PushAttr(nOrderID);
2188  [[fallthrough]];
2189  case GOrdSVwWin: SAL_INFO("filter.os2met","GOrdSVwWin");
2190  break;
2191  default: SAL_INFO("filter.os2met","Unknown order: " << nOrderID);
2192  }
2193 }
2194 
2195 void OS2METReader::ReadDsc(sal_uInt16 nDscID)
2196 {
2197  switch (nDscID) {
2198  case 0x00f7: { // 'Specify GVM Subset'
2199  sal_uInt8 nbyte(0);
2200  pOS2MET->SeekRel(6);
2201  pOS2MET->ReadUChar( nbyte );
2202  if (nbyte==0x05) bCoord32=true;
2203  else if (nbyte==0x04) bCoord32=false;
2204  else {
2205  pOS2MET->SetError(SVSTREAM_FILEFORMAT_ERROR);
2206  ErrorCode=1;
2207  }
2208  break;
2209  }
2210  case 0x00f6:
2211  {
2212  // 'Set Picture Descriptor'
2213  bool b32;
2214  sal_uInt8 nbyte(0), nUnitType(0);
2215 
2216  pOS2MET->SeekRel(2);
2217  pOS2MET->ReadUChar( nbyte );
2218 
2219  if (nbyte==0x05)
2220  b32=true;
2221  else if(nbyte==0x04)
2222  b32=false;
2223  else
2224  {
2225  b32 = false; // -Wall added the case.
2226  pOS2MET->SetError(SVSTREAM_FILEFORMAT_ERROR);
2227  ErrorCode=2;
2228  }
2229 
2230  pOS2MET->ReadUChar( nUnitType );
2231 
2232  sal_Int32 xr = ReadCoord(b32);
2233  sal_Int32 yr = ReadCoord(b32);
2234 
2235  ReadCoord(b32);
2236 
2237  if (nUnitType==0x00 && xr>0 && yr>0)
2238  aGlobMapMode=MapMode(MapUnit::MapInch,Point(0,0),Fraction(10,xr),Fraction(10,yr));
2239  else if (nUnitType==0x01 && xr>0 && yr>0)
2240  aGlobMapMode=MapMode(MapUnit::MapCM,Point(0,0),Fraction(10,xr),Fraction(10,yr));
2241  else
2242  aGlobMapMode=MapMode();
2243 
2244  sal_Int32 x1 = ReadCoord(b32);
2245  sal_Int32 x2 = ReadCoord(b32);
2246  sal_Int32 y1 = ReadCoord(b32);
2247  sal_Int32 y2 = ReadCoord(b32);
2248 
2249  if (x1>x2)
2250  {
2251  const auto nt = x1;
2252  x1=x2;
2253  x2=nt;
2254  }
2255 
2256  if (y1>y2)
2257  {
2258  const auto nt = y1;
2259  y1=y2;
2260  y2=nt;
2261  }
2262 
2263  aBoundingRect.SetLeft( x1 );
2264  aBoundingRect.SetRight( x2 );
2265  aBoundingRect.SetTop( y1 );
2266  aBoundingRect.SetBottom( y2 );
2267 
2268  // no output beside this bounding rect
2269  pVirDev->IntersectClipRegion( tools::Rectangle( Point(), aBoundingRect.GetSize() ) );
2270 
2271  break;
2272  }
2273  case 0x0021: // 'Set Current Defaults'
2274  break;
2275  }
2276 }
2277 
2278 void OS2METReader::ReadImageData(sal_uInt16 nDataID, sal_uInt16 nDataLen)
2279 {
2280  OSBitmap * p=pBitmapList; if (p==nullptr) return;
2281 
2282  switch (nDataID) {
2283 
2284  case 0x0070: // Begin Segment
2285  break;
2286 
2287  case 0x0091: // Begin Image Content
2288  break;
2289 
2290  case 0x0094: // Image Size
2291  pOS2MET->SeekRel(5);
2292  p->nHeight=ReadBigEndianWord();
2293  p->nWidth=ReadBigEndianWord();
2294  break;
2295 
2296  case 0x0095: // Image Encoding
2297  break;
2298 
2299  case 0x0096: { // Image IDE-Size
2300  sal_uInt8 nbyte(0);
2301  pOS2MET->ReadUChar( nbyte ); p->nBitsPerPixel=nbyte;
2302  break;
2303  }
2304 
2305  case 0x0097: // Image LUT-ID
2306  break;
2307 
2308  case 0x009b: // IDE Structure
2309  break;
2310 
2311  case 0xfe92: { // Image Data
2312  // At the latest we now need the temporary BMP file and
2313  // inside this file we need the header and the palette.
2314  if (p->pBMP==nullptr) {
2315  p->pBMP=new SvMemoryStream();
2316  p->pBMP->SetEndian(SvStreamEndian::LITTLE);
2317  if (p->nWidth==0 || p->nHeight==0 || p->nBitsPerPixel==0) {
2318  pOS2MET->SetError(SVSTREAM_FILEFORMAT_ERROR);
2319  ErrorCode=3;
2320  return;
2321  }
2322  // write (Windows-)BITMAPINFOHEADER:
2323  p->pBMP->WriteUInt32( 40 ).WriteUInt32( p->nWidth ).WriteUInt32( p->nHeight );
2324  p->pBMP->WriteUInt16( 1 ).WriteUInt16( p->nBitsPerPixel );
2325  p->pBMP->WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 );
2326  p->pBMP->WriteUInt32( 0 ).WriteUInt32( 0 );
2327  // write color table:
2328  if (p->nBitsPerPixel<=8) {
2329  sal_uInt16 i, nColTabSize=1<<(p->nBitsPerPixel);
2330  for (i=0; i<nColTabSize; i++) p->pBMP->WriteUInt32( GetPalette0RGB(i) );
2331  }
2332  }
2333  // OK, now the map data is being pushed. Unfortunately OS2 and BMP
2334  // do have a different RGB ordering when using 24-bit
2335  std::unique_ptr<sal_uInt8[]> pBuf(new sal_uInt8[nDataLen]);
2336  pOS2MET->ReadBytes(pBuf.get(), nDataLen);
2337  sal_uInt32 nBytesPerLineToSwap = (p->nBitsPerPixel == 24) ?
2338  ((p->nWidth * 3 + 3) & 0xfffffffc) : 0;
2339  if (nBytesPerLineToSwap) {
2340  sal_uInt32 nAlign = p->nMapPos - (p->nMapPos % nBytesPerLineToSwap);
2341  sal_uInt32 i=0;
2342  while (nAlign+i+2<p->nMapPos+nDataLen) {
2343  if (nAlign+i>=p->nMapPos) {
2344  sal_uInt32 j = nAlign + i - p->nMapPos;
2345  std::swap(pBuf[j], pBuf[j+2]);
2346  }
2347  i+=3;
2348  if (i + 2 >= nBytesPerLineToSwap) {
2349  nAlign += nBytesPerLineToSwap;
2350  i=0;
2351  }
2352  }
2353  }
2354  p->pBMP->WriteBytes(pBuf.get(), nDataLen);
2355  p->nMapPos+=nDataLen;
2356  break;
2357  }
2358  case 0x0093: // End Image Content
2359  break;
2360 
2361  case 0x0071: // End Segment
2362  break;
2363  }
2364 }
2365 
2366 void OS2METReader::ReadFont(sal_uInt16 nFieldSize)
2367 {
2368  OSFont * pF=new OSFont;
2369  pF->pSucc=pFontList; pFontList=pF;
2370  pF->nID=0;
2371  pF->aFont.SetTransparent(true);
2372  pF->aFont.SetAlignment(ALIGN_BASELINE);
2373 
2374  auto nPos=pOS2MET->Tell();
2375  auto nMaxPos = nPos + nFieldSize;
2376  pOS2MET->SeekRel(2); nPos+=2;
2377  while (nPos<nMaxPos && pOS2MET->good()) {
2378  sal_uInt8 nByte(0);
2379  pOS2MET->ReadUChar(nByte);
2380  sal_uInt16 nLen = static_cast<sal_uInt16>(nByte) & 0x00ff;
2381  if (nLen == 0)
2382  {
2383  pOS2MET->SetError(SVSTREAM_FILEFORMAT_ERROR);
2384  ErrorCode=4;
2385  }
2386  sal_uInt8 nTripType(0);
2387  pOS2MET->ReadUChar( nTripType );
2388  switch (nTripType) {
2389  case 0x02:
2390  {
2391  sal_uInt8 nTripType2(0);
2392  pOS2MET->ReadUChar( nTripType2 );
2393  switch (nTripType2) {
2394  case 0x84: // Font name
2395  break;
2396  case 0x08: { // Font Typeface
2397  char str[33];
2398  pOS2MET->SeekRel(1);
2399  str[pOS2MET->ReadBytes(str, 32)] = 0;
2400  OUString aStr( str, strlen(str), osl_getThreadTextEncoding() );
2401  if ( aStr.equalsIgnoreAsciiCase( "Helv" ) )
2402  aStr = "Helvetica";
2403  pF->aFont.SetFamilyName( aStr );
2404  break;
2405  }
2406  }
2407  break;
2408  }
2409  case 0x24: // Icid
2410  {
2411  sal_uInt8 nTripType2(0);
2412  pOS2MET->ReadUChar( nTripType2 );
2413  switch (nTripType2) {
2414  case 0x05: //Icid
2415  pOS2MET->ReadUChar( nByte );
2416  pF->nID=static_cast<sal_uInt32>(nByte)&0xff;
2417  break;
2418  }
2419  break;
2420  }
2421  case 0x20: // Font Binary GCID
2422  break;
2423  case 0x1f: { // Font Attributes
2424  FontWeight eWeight;
2425  sal_uInt8 nbyte(0);
2426  pOS2MET->ReadUChar( nbyte );
2427  switch (nbyte) {
2428  case 1: eWeight=WEIGHT_THIN; break;
2429  case 2: eWeight=WEIGHT_ULTRALIGHT; break;
2430  case 3: eWeight=WEIGHT_LIGHT; break;
2431  case 4: eWeight=WEIGHT_SEMILIGHT; break;
2432  case 5: eWeight=WEIGHT_NORMAL; break;
2433  case 6: eWeight=WEIGHT_SEMIBOLD; break;
2434  case 7: eWeight=WEIGHT_BOLD; break;
2435  case 8: eWeight=WEIGHT_ULTRABOLD; break;
2436  case 9: eWeight=WEIGHT_BLACK; break;
2437  default: eWeight=WEIGHT_DONTKNOW;
2438  }
2439  pF->aFont.SetWeight(eWeight);
2440  break;
2441  }
2442  }
2443  nPos+=nLen;
2444  pOS2MET->Seek(nPos);
2445  }
2446 }
2447 
2448 void OS2METReader::ReadField(sal_uInt16 nFieldType, sal_uInt16 nFieldSize)
2449 {
2450  switch (nFieldType) {
2451  case BegDocumnMagic:
2452  break;
2453  case EndDocumnMagic:
2454  break;
2455  case BegResGrpMagic:
2456  break;
2457  case EndResGrpMagic:
2458  break;
2459  case BegColAtrMagic:
2460  break;
2461  case EndColAtrMagic:
2462  break;
2463  case BlkColAtrMagic: {
2464  sal_uInt8 nbyte;
2465  sal_uInt16 nStartIndex, nEndIndex, i, nElemLen, nBytesPerCol;
2466 
2467  auto nPos = pOS2MET->Tell();
2468  auto nMaxPos = nPos + nFieldSize;
2469  pOS2MET->SeekRel(3); nPos+=3;
2470  while (nPos<nMaxPos && pOS2MET->GetError()==ERRCODE_NONE) {
2471  pOS2MET->ReadUChar( nbyte ); nElemLen=static_cast<sal_uInt16>(nbyte) & 0x00ff;
2472  if (nElemLen>11) {
2473  pOS2MET->SeekRel(4);
2474  nStartIndex=ReadBigEndianWord();
2475  pOS2MET->SeekRel(3);
2476  pOS2MET->ReadUChar( nbyte );
2477  nBytesPerCol=static_cast<sal_uInt16>(nbyte) & 0x00ff;
2478  if (nBytesPerCol == 0)
2479  {
2480  pOS2MET->SetError(SVSTREAM_FILEFORMAT_ERROR);
2481  ErrorCode=4;
2482  break;
2483  }
2484  nEndIndex=nStartIndex+(nElemLen-11)/nBytesPerCol;
2485  for (i=nStartIndex; i<nEndIndex; i++) {
2486  if (nBytesPerCol > 3) pOS2MET->SeekRel(nBytesPerCol-3);
2487  auto nCol = ReadBigEndian3BytesLong();
2488  SetPalette0RGB(i, nCol);
2489  }
2490  }
2491  else if (nElemLen<10) {
2492  pOS2MET->SetError(SVSTREAM_FILEFORMAT_ERROR);
2493  ErrorCode=4;
2494  }
2495  nPos += nElemLen;
2496  pOS2MET->Seek(nPos);
2497  }
2498  break;
2499  }
2500  case MapColAtrMagic:
2501  break;
2502  case BegImgObjMagic: {
2503  // create new bitmap by now: (will be filled later)
2504  OSBitmap * pB=new OSBitmap;
2505  pB->pSucc=pBitmapList; pBitmapList=pB;
2506  pB->pBMP=nullptr; pB->nWidth=0; pB->nHeight=0; pB->nBitsPerPixel=0;
2507  pB->nMapPos=0;
2508  // determine ID of the bitmap:
2509  pB->nID=0;
2510  for (sal_uInt8 i = 0; i < 4; ++i) {
2511  sal_uInt8 nbyte(0),nbyte2(0);
2512  pOS2MET->ReadUChar(nbyte).ReadUChar(nbyte2);
2513  nbyte -= 0x30;
2514  nbyte2 -= 0x30;
2515  nbyte = (nbyte << 4) | nbyte2;
2516  pB->nID=(pB->nID>>8)|(static_cast<sal_uInt32>(nbyte)<<24);
2517  }
2518  // put new palette on the palette stack: (will be filled later)
2519  OSPalette * pP=new OSPalette;
2520  pP->pSucc=pPaletteStack; pPaletteStack=pP;
2521  pP->p0RGB=nullptr; pP->nSize=0;
2522  break;
2523  }
2524  case EndImgObjMagic: {
2525  // read temporary Windows BMP file:
2526  if (pBitmapList==nullptr || pBitmapList->pBMP==nullptr ||
2527  pBitmapList->pBMP->GetError()!=ERRCODE_NONE) {
2528  pOS2MET->SetError(SVSTREAM_FILEFORMAT_ERROR);
2529  ErrorCode=5;
2530  return;
2531  }
2532  pBitmapList->pBMP->Seek(0);
2533 
2534  ReadDIBBitmapEx(pBitmapList->aBitmapEx, *(pBitmapList->pBMP), false);
2535 
2536  if (pBitmapList->pBMP->GetError()!=ERRCODE_NONE) {
2537  pOS2MET->SetError(SVSTREAM_FILEFORMAT_ERROR);
2538  ErrorCode=6;
2539  }
2540  delete pBitmapList->pBMP; pBitmapList->pBMP=nullptr;
2541  // kill palette from stack:
2542  OSPalette * pP=pPaletteStack;
2543  if (pP!=nullptr) {
2544  pPaletteStack=pP->pSucc;
2545  delete[] pP->p0RGB;
2546  delete pP;
2547  }
2548  break;
2549  }
2550  case DscImgObjMagic:
2551  break;
2552  case DatImgObjMagic: {
2553  sal_uInt16 nDataID, nDataLen;
2554  sal_uInt8 nbyte;
2555 
2556  auto nPos = pOS2MET->Tell();
2557  auto nMaxPos = nPos + nFieldSize;
2558  while (nPos<nMaxPos && pOS2MET->GetError()==ERRCODE_NONE) {
2559  pOS2MET->ReadUChar( nbyte ); nDataID=static_cast<sal_uInt16>(nbyte)&0x00ff;
2560  if (nDataID==0x00fe) {
2561  pOS2MET->ReadUChar( nbyte );
2562  nDataID=(nDataID<<8)|(static_cast<sal_uInt16>(nbyte)&0x00ff);
2563  nDataLen=ReadBigEndianWord();
2564  nPos+=4;
2565  }
2566  else {
2567  pOS2MET->ReadUChar( nbyte ); nDataLen=static_cast<sal_uInt16>(nbyte)&0x00ff;
2568  nPos+=2;
2569  }
2570  ReadImageData(nDataID, nDataLen);
2571  nPos += nDataLen;
2572  pOS2MET->Seek(nPos);
2573  }
2574  break;
2575  }
2576 
2577  case BegObEnv1Magic:
2578  break;
2579  case EndObEnv1Magic:
2580  break;
2581  case BegGrfObjMagic:
2582  break;
2583  case EndGrfObjMagic: {
2584  if (!xOrdFile)
2585  break;
2586 
2587  auto nMaxPos = xOrdFile->Tell();
2588  if (!nMaxPos)
2589  break;
2590 
2591  // In xOrdFile all "DatGrfObj" fields were collected so that the
2592  // therein contained "Orders" are continuous and not segmented by fields.
2593  // To read them from the memory stream without having any trouble,
2594  // we use a little trick:
2595 
2596  SvStream *pSave = pOS2MET;
2597  pOS2MET=xOrdFile.get(); //(!)
2598  pOS2MET->Seek(0);
2599 
2600  // in a sane world this block is just: pOS2MET->SetStreamSize(nMaxPos);
2601  if (nMaxPos)
2602  {
2603 #ifndef NDEBUG
2604  const sal_uInt8 nLastByte = static_cast<const sal_uInt8*>(xOrdFile->GetData())[nMaxPos-1];
2605 #endif
2606  pOS2MET->SetStreamSize(nMaxPos); // shrink stream to written portion
2607  assert(pOS2MET->remainingSize() == nMaxPos || pOS2MET->remainingSize() == nMaxPos - 1);
2608  SAL_WARN_IF(pOS2MET->remainingSize() == nMaxPos, "filter.os2met", "this SetStreamSize workaround is no longer needed");
2609  // The shrink case of SvMemoryStream::ReAllocateMemory, i.e. nEndOfData = nNewSize - 1, looks buggy to me, workaround
2610  // it by using Seek to move the nEndOfData to the sane position
2611  if (pOS2MET->remainingSize() < nMaxPos)
2612  {
2613  pOS2MET->Seek(nMaxPos);
2614  pOS2MET->Seek(0);
2615  }
2616 
2617  assert(nLastByte == static_cast<const sal_uInt8*>(xOrdFile->GetData())[nMaxPos-1]);
2618  }
2619 
2620  assert(pOS2MET->remainingSize() == nMaxPos);
2621 
2622  // disable stream growing past its current size
2623  xOrdFile->SetResizeOffset(0);
2624 
2625 
2626  // "Segment header":
2627  sal_uInt8 nbyte(0);
2628  pOS2MET->ReadUChar( nbyte );
2629  if (nbyte==0x70) { // header exists
2630  pOS2MET->SeekRel(15); // but we don't need it
2631  }
2632  else pOS2MET->SeekRel(-1); // no header, go back one byte
2633 
2634  // loop through Order:
2635  while (pOS2MET->Tell()<nMaxPos && pOS2MET->GetError()==ERRCODE_NONE) {
2636  pOS2MET->ReadUChar( nbyte );
2637  sal_uInt16 nOrderID = static_cast<sal_uInt16>(nbyte) & 0x00ff;
2638  if (nOrderID==0x00fe) {
2639  pOS2MET->ReadUChar( nbyte );
2640  nOrderID=(nOrderID << 8) | (static_cast<sal_uInt16>(nbyte) & 0x00ff);
2641  }
2642  sal_uInt16 nOrderLen;
2643  if (nOrderID>0x00ff || nOrderID==GOrdPolygn) {
2644  // ooo: As written in OS2 documentation, the order length should now
2645  // be written as big endian word. (Quote: "Highorder byte precedes loworder byte").
2646  // In reality there are files in which the length is stored as little endian word
2647  // (at least for nOrderID==GOrdPolygn)
2648  // So we throw a coin or what else can we do?
2649  pOS2MET->ReadUChar( nbyte ); nOrderLen=static_cast<sal_uInt16>(nbyte)&0x00ff;
2650  pOS2MET->ReadUChar( nbyte ); if (nbyte!=0) nOrderLen=nOrderLen<<8|(static_cast<sal_uInt16>(nbyte)&0x00ff);
2651  }
2652  else if (nOrderID==GOrdSTxAlg || nOrderID==GOrdPTxAlg) nOrderLen=2;
2653  else if ((nOrderID&0xff88)==0x0008) nOrderLen=1;
2654  else if (nOrderID==0x0000 || nOrderID==0x00ff) nOrderLen=0;
2655  else { pOS2MET->ReadUChar( nbyte ); nOrderLen=static_cast<sal_uInt16>(nbyte) & 0x00ff; }
2656  auto nPos=pOS2MET->Tell();
2657  ReadOrder(nOrderID, nOrderLen);
2658  if (nPos+nOrderLen < pOS2MET->Tell()) {
2659  SAL_INFO("filter.os2met","Order is shorter than expected. OrderID: " << nOrderID << " Position: " << nPos);
2660  }
2661  else if (nPos+nOrderLen != pOS2MET->Tell()) {
2662  SAL_INFO("filter.os2met","Order was not read completely. OrderID: " << nOrderID << " Position: " << nPos);
2663  }
2664  pOS2MET->Seek(nPos+nOrderLen);
2665  }
2666 
2667  pOS2MET=pSave;
2668  if (xOrdFile->GetError()) {
2670  ErrorCode=10;
2671  }
2672  xOrdFile.reset();
2673  break;
2674  }
2675  case DscGrfObjMagic: {
2676  sal_uInt16 nDscID, nDscLen;
2677  sal_uInt8 nbyte;
2678 
2679  auto nMaxPos = pOS2MET->Tell() + nFieldSize;
2680  while (pOS2MET->Tell()<nMaxPos && pOS2MET->GetError()==ERRCODE_NONE) {
2681  pOS2MET->ReadUChar( nbyte ); nDscID =static_cast<sal_uInt16>(nbyte) & 0x00ff;
2682  pOS2MET->ReadUChar( nbyte ); nDscLen=static_cast<sal_uInt16>(nbyte) & 0x00ff;
2683  auto nPos = pOS2MET->Tell();
2684  ReadDsc(nDscID);
2685  pOS2MET->Seek(nPos+nDscLen);
2686  }
2687  break;
2688  }
2689  case DatGrfObjMagic: {
2690  if (!xOrdFile) {
2691  xOrdFile.reset(new SvMemoryStream);
2692  xOrdFile->SetEndian(SvStreamEndian::LITTLE);
2693  }
2694  std::unique_ptr<sal_uInt8[]> pBuf(new sal_uInt8[nFieldSize]);
2695  pOS2MET->ReadBytes(pBuf.get(), nFieldSize);
2696  xOrdFile->WriteBytes(pBuf.get(), nFieldSize);
2697  break;
2698  }
2699  case MapCodFntMagic:
2700  ReadFont(nFieldSize);
2701  break;
2702 
2703  case MapDatResMagic:
2704  break;
2705  }
2706 }
2707 
2708 void OS2METReader::ReadOS2MET( SvStream & rStreamOS2MET, GDIMetaFile & rGDIMetaFile )
2709 {
2710  ErrorCode=0;
2711 
2712  pOS2MET = &rStreamOS2MET;
2713  auto nOrigPos = pOS2MET->Tell();
2714  SvStreamEndian nOrigNumberFormat = pOS2MET->GetEndian();
2715 
2716  bCoord32 = true;
2717  pPaletteStack=nullptr;
2718  pAreaStack=nullptr;
2719  pPathStack=nullptr;
2720  pPathList=nullptr;
2721  pFontList=nullptr;
2722  pBitmapList=nullptr;
2723  pAttrStack=nullptr;
2724 
2725  aDefAttr.aLinCol =COL_BLACK;
2726  aDefAttr.aLinBgCol =COL_WHITE;
2727  aDefAttr.eLinMix =RasterOp::OverPaint;
2728  aDefAttr.eLinBgMix =RasterOp::OverPaint;
2729  aDefAttr.aChrCol =COL_BLACK;
2730  aDefAttr.aChrBgCol =COL_WHITE;
2731  aDefAttr.eChrMix =RasterOp::OverPaint;
2732  aDefAttr.eChrBgMix =RasterOp::OverPaint;
2733  aDefAttr.aMrkCol =COL_BLACK;
2734  aDefAttr.aMrkBgCol =COL_WHITE;
2735  aDefAttr.eMrkMix =RasterOp::OverPaint;
2736  aDefAttr.eMrkBgMix =RasterOp::OverPaint;
2737  aDefAttr.aPatCol =COL_BLACK;
2738  aDefAttr.aPatBgCol =COL_WHITE;
2739  aDefAttr.ePatMix =RasterOp::OverPaint;
2740  aDefAttr.ePatBgMix =RasterOp::OverPaint;
2741  aDefAttr.aImgCol =COL_BLACK;
2742  aDefAttr.aImgBgCol =COL_WHITE;
2743  aDefAttr.eImgMix =RasterOp::OverPaint;
2744  aDefAttr.eImgBgMix =RasterOp::OverPaint;
2745  aDefAttr.nArcP =1;
2746  aDefAttr.nArcQ =1;
2747  aDefAttr.nArcR =0;
2748  aDefAttr.nArcS =0;
2749  aDefAttr.nChrAng =0_deg10;
2750  aDefAttr.aChrCellSize=Size(12,12);
2751  aDefAttr.nChrSet =0;
2752  aDefAttr.aCurPos =Point(0,0);
2753  aDefAttr.eLinStyle =PEN_SOLID;
2754  aDefAttr.nLinWidth =0;
2755  aDefAttr.aMrkCellSize=Size(10,10);
2756  aDefAttr.nMrkPrec =0x01;
2757  aDefAttr.nMrkSet =0xff;
2758  aDefAttr.nMrkSymbol =0x01;
2759  aDefAttr.bFill =true;
2760  aDefAttr.nStrLinWidth=0;
2761 
2762  aAttr=aDefAttr;
2763 
2764  xOrdFile.reset();
2765 
2766  rGDIMetaFile.Record(pVirDev);
2767 
2768  pOS2MET->SetEndian(SvStreamEndian::LITTLE);
2769 
2770  sal_uInt64 nPos = pOS2MET->Tell();
2771 
2772  for (;;) {
2773 
2774  sal_uInt16 nFieldSize = ReadBigEndianWord();
2775  sal_uInt8 nMagicByte(0);
2776  pOS2MET->ReadUChar( nMagicByte );
2777  if (nMagicByte!=0xd3) {
2778  pOS2MET->SetError(SVSTREAM_FILEFORMAT_ERROR);
2779  ErrorCode=7;
2780  break;
2781  }
2782 
2783  sal_uInt16 nFieldType(0);
2784  pOS2MET->ReadUInt16(nFieldType);
2785 
2786  pOS2MET->SeekRel(3);
2787 
2788  if (pOS2MET->GetError())
2789  break;
2790 
2791  if (nFieldType==EndDocumnMagic)
2792  break;
2793 
2794  if (pOS2MET->eof() || nFieldSize < 8)
2795  {
2796  pOS2MET->SetError(SVSTREAM_FILEFORMAT_ERROR);
2797  ErrorCode=8;
2798  break;
2799  }
2800 
2801  nPos+=8; nFieldSize-=8;
2802 
2803  if (nFieldSize > pOS2MET->remainingSize())
2804  {
2805  pOS2MET->SetError(SVSTREAM_FILEFORMAT_ERROR);
2806  ErrorCode=8;
2807  break;
2808  }
2809 
2810  ReadField(nFieldType, nFieldSize);
2811  nPos += nFieldSize;
2812 
2813  if (pOS2MET->Tell() > nPos)
2814  {
2815  pOS2MET->SetError(SVSTREAM_FILEFORMAT_ERROR);
2816  ErrorCode=9;
2817  break;
2818  }
2819  pOS2MET->Seek(nPos);
2820  }
2821 
2822  rGDIMetaFile.Stop();
2823 
2824  rGDIMetaFile.SetPrefMapMode( aGlobMapMode );
2825 
2826  if( aBoundingRect.GetWidth() && aBoundingRect.GetHeight() )
2827  rGDIMetaFile.SetPrefSize( aBoundingRect.GetSize() );
2828  else
2829  {
2830  if( aCalcBndRect.Left() || aCalcBndRect.Top() )
2831  rGDIMetaFile.Move( -aCalcBndRect.Left(), -aCalcBndRect.Top() );
2832 
2833  rGDIMetaFile.SetPrefSize( aCalcBndRect.GetSize() );
2834  }
2835 
2836  pOS2MET->SetEndian(nOrigNumberFormat);
2837 
2838  if (pOS2MET->GetError()) {
2839  SAL_INFO("filter.os2met","Error code: " << ErrorCode);
2840  pOS2MET->Seek(nOrigPos);
2841  }
2842 }
2843 
2844 //================== GraphicImport - the exported function ================
2845 
2846 bool ImportMetGraphic(SvStream & rStream, Graphic & rGraphic)
2847 {
2848  OS2METReader aOS2METReader;
2849  GDIMetaFile aMTF;
2850  bool bRet = false;
2851 
2852  try
2853  {
2854  aOS2METReader.ReadOS2MET( rStream, aMTF );
2855 
2856  if ( !rStream.GetError() )
2857  {
2858  rGraphic=Graphic( aMTF );
2859  bRet = true;
2860  }
2861  }
2862  catch (const css::uno::Exception&)
2863  {
2864  }
2865 
2866  return bRet;
2867 }
2868 
2869 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt16 Count() const
#define GOrdSLnJoi
Definition: ios2met.cxx:161
#define GOrdGivSFl
Definition: ios2met.cxx:93
#define GOrdSMdTrn
Definition: ios2met.cxx:206
#define GOrdSMkPrc
Definition: ios2met.cxx:191
#define GOrdSColor
Definition: ios2met.cxx:137
#define GOrdBegPth
Definition: ios2met.cxx:112
#define GOrdPChShr
Definition: ios2met.cxx:187
#define GOrdSCrPos
Definition: ios2met.cxx:203
sal_Int32 nIndex
#define DatGrfObjMagic
Definition: ios2met.cxx:68
const tools::Polygon & GetObject(sal_uInt16 nPos) const
void SetFontSize(const Size &)
Definition: font/font.cxx:127
#define EndResGrpMagic
Definition: ios2met.cxx:50
#define GOrdImgDat
Definition: ios2met.cxx:105
#define MapDatResMagic
Definition: ios2met.cxx:71
#define GOrdEscape
Definition: ios2met.cxx:129
#define GOrdPStLWd
Definition: ios2met.cxx:170
#define GOrdPMkSet
Definition: ios2met.cxx:194
#define GOrdStkPop
Definition: ios2met.cxx:133
#define GOrdEndElm
Definition: ios2met.cxx:110
#define GOrdOutPth
Definition: ios2met.cxx:116
#define GOrdEndPlg
Definition: ios2met.cxx:128
signed char sal_Int8
#define GOrdBitBlt
Definition: ios2met.cxx:122
#define GOrdSBgMix
Definition: ios2met.cxx:149
#define GOrdGivMrk
Definition: ios2met.cxx:87
#define BegResGrpMagic
Definition: ios2met.cxx:49
void Create(SwFormatVertOrient &rItem, SvStream &rStrm, sal_uInt16 nVersionAbusedAsSize)
#define GOrdSChCel
Definition: ios2met.cxx:182
#define GOrdEndPth
Definition: ios2met.cxx:113
#define BlkColAtrMagic
Definition: ios2met.cxx:54
constexpr::Color COL_TRANSPARENT(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
#define GOrdPIxCol
Definition: ios2met.cxx:140
#define GOrdCurCrc
Definition: ios2met.cxx:84
#define GOrdPPkIdn
Definition: ios2met.cxx:209
#define GOrdPBgMix
Definition: ios2met.cxx:150
#define GOrdCurStr
Definition: ios2met.cxx:99
WEIGHT_THIN
#define GOrdPTxAlg
Definition: ios2met.cxx:189
#define GOrdCalSeg
Definition: ios2met.cxx:123
void SetPrefSize(const Size &rSize)
Definition: gdimtf.hxx:173
WEIGHT_BLACK
sal_uInt64 Seek(sal_uInt64 nPos)
#define GOrdEndSym
Definition: ios2met.cxx:127
WEIGHT_SEMIBOLD
void SetSize(sal_uInt16 nNewSize)
#define GOrdCurArP
Definition: ios2met.cxx:90
#define GOrdSBgCol
Definition: ios2met.cxx:143
#define GOrdSPkIdn
Definition: ios2met.cxx:208
#define GOrdPPtRef
Definition: ios2met.cxx:157
#define GOrdPIvAtr
Definition: ios2met.cxx:136
#define GOrdGivStx
Definition: ios2met.cxx:100
void SetPoint(const Point &rPt, sal_uInt16 nPos)
float x
#define GOrdGivBzr
Definition: ios2met.cxx:77
#define GOrdSLnWdt
Definition: ios2met.cxx:165
WEIGHT_LIGHT
#define GOrdCurBox
Definition: ios2met.cxx:80
#define GOrdFilPth
Definition: ios2met.cxx:114
#define GOrdEndAra
Definition: ios2met.cxx:108
#define GOrdCurStx
Definition: ios2met.cxx:101
WEIGHT_BOLD
constexpr tools::Long Width() const
#define GOrdPChAng
Definition: ios2met.cxx:179
ErrCode GetError() const
void Record(OutputDevice *pOutDev)
Definition: gdimtf.cxx:311
#define GOrdPXtCol
Definition: ios2met.cxx:142
#define GOrdPolygn
Definition: ios2met.cxx:131
bool ReadDIBBitmapEx(BitmapEx &rTarget, SvStream &rIStm, bool bFileHeader, bool bMSOFormat)
Definition: dibtools.cxx:1704
LineStyle
Definition: vclenum.hxx:184
#define SAL_MAX_UINT16
#define EndObEnv1Magic
Definition: ios2met.cxx:63
#define GOrdSStLWd
Definition: ios2met.cxx:169
std::enable_if< std::is_signed< T >::value, T >::type saturating_toggle_sign(T a)
void Insert(const tools::Polygon &rPoly, sal_uInt16 nPos=POLYPOLY_APPEND)
#define GOrdSMkSym
Definition: ios2met.cxx:195
#define GOrdSIvAtr
Definition: ios2met.cxx:135
#define GOrdPChDir
Definition: ios2met.cxx:173
#define GOrdSTxAlg
Definition: ios2met.cxx:188
#define GOrdGivArc
Definition: ios2met.cxx:75
#define GOrdCloFig
Definition: ios2met.cxx:126
#define GOrdPMdTrn
Definition: ios2met.cxx:207
#define GOrdSegChr
Definition: ios2met.cxx:125
#define DatImgObjMagic
Definition: ios2met.cxx:60
#define GOrdSMixMd
Definition: ios2met.cxx:147
float y
WEIGHT_DONTKNOW
#define GOrdPChCel
Definition: ios2met.cxx:183
#define DscGrfObjMagic
Definition: ios2met.cxx:67
#define GOrdGivStr
Definition: ios2met.cxx:98
#define GOrdSMkCel
Definition: ios2met.cxx:197
void Replace(const Polygon &rPoly, sal_uInt16 nPos)
WEIGHT_SEMILIGHT
#define GOrdSPtRef
Definition: ios2met.cxx:156
#define BegColAtrMagic
Definition: ios2met.cxx:52
#define GOrdSLnEnd
Definition: ios2met.cxx:159
#define GOrdModPth
Definition: ios2met.cxx:115
#define GOrdSVwTrn
Definition: ios2met.cxx:210
int i
#define GOrdRemark
Definition: ios2met.cxx:120
#define GOrdPLnEnd
Definition: ios2met.cxx:160
#define GOrdSPtSet
Definition: ios2met.cxx:152
#define GOrdSBxCol
Definition: ios2met.cxx:145
void SetOrientation(Degree10 nLineOrientation)
Definition: font/font.cxx:202
#define GOrdCurRLn
Definition: ios2met.cxx:92
#define GOrdSXtCol
Definition: ios2met.cxx:141
#define GOrdSIxCol
Definition: ios2met.cxx:139
#define GOrdCurLin
Definition: ios2met.cxx:86
#define GOrdSVwWin
Definition: ios2met.cxx:211
#define GOrdPBxCol
Definition: ios2met.cxx:146
WEIGHT_NORMAL
#define GOrdGivLin
Definition: ios2met.cxx:85
#define GOrdCurArc
Definition: ios2met.cxx:76
WEIGHT_ULTRALIGHT
PenStyle
Definition: ios2met.cxx:40
#define GOrdSChBrx
Definition: ios2met.cxx:180
void SetError(ErrCode nErrorCode)
#define GOrdSSgBnd
Definition: ios2met.cxx:124
sal_uInt16 GetSize() const
#define GOrdSChXtr
Definition: ios2met.cxx:184
#define GOrdCurMrk
Definition: ios2met.cxx:88
#define GOrdBegAra
Definition: ios2met.cxx:107
void Move(tools::Long nX, tools::Long nY)
Definition: gdimtf.cxx:630
#define EndGrfObjMagic
Definition: ios2met.cxx:66
#define GOrdCurFil
Definition: ios2met.cxx:82
#define GOrdPBgCol
Definition: ios2met.cxx:144
WEIGHT_ULTRABOLD
#define GOrdSMkSet
Definition: ios2met.cxx:193
#define GOrdSChPrc
Definition: ios2met.cxx:174
ErrorCode
#define MapColAtrMagic
Definition: ios2met.cxx:55
#define GOrdSegLab
Definition: ios2met.cxx:121
RasterOp
Definition: RasterOp.hxx:22
#define GOrdGivImg
Definition: ios2met.cxx:103
#define GOrdPMkPrc
Definition: ios2met.cxx:192
#define GOrdPFrLWd
Definition: ios2met.cxx:168
#define GOrdGivRLn
Definition: ios2met.cxx:91
#define GOrdPColor
Definition: ios2met.cxx:138
void SetColor(const Color &)
Definition: font/font.cxx:90
#define GOrdCurSFl
Definition: ios2met.cxx:94
#define GOrdGivStM
Definition: ios2met.cxx:96
#define GOrdSChDir
Definition: ios2met.cxx:172
#define GOrdSClPth
Definition: ios2met.cxx:117
#define GOrdSPtSym
Definition: ios2met.cxx:154
const Point & GetPoint(sal_uInt16 nPos) const
#define GOrdExtEsc
Definition: ios2met.cxx:130
#define EndDocumnMagic
Definition: ios2met.cxx:47
void Stop()
Definition: gdimtf.cxx:536
#define MapCodFntMagic
Definition: ios2met.cxx:70
FontWeight
#define GOrdBegElm
Definition: ios2met.cxx:109
#define GOrdCurImg
Definition: ios2met.cxx:104
#define DscImgObjMagic
Definition: ios2met.cxx:59
#define GOrdPMixMd
Definition: ios2met.cxx:148
#define GOrdSFrLWd
Definition: ios2met.cxx:167
#define GOrdGivArP
Definition: ios2met.cxx:89
#define GOrdPChSet
Definition: ios2met.cxx:177
tools::Rectangle & Union(const tools::Rectangle &rRect)
#define SAL_WARN_IF(condition, area, stream)
#define ERRCODE_NONE
Definition: errcode.hxx:196
constexpr tools::Long Height() const
unsigned char sal_uInt8
#define EndColAtrMagic
Definition: ios2met.cxx:53
SvStream & ReadFont(SvStream &rIStm, vcl::Font &rFont)
Definition: font/font.cxx:516
bool ImportMetGraphic(SvStream &rStream, Graphic &rGraphic)
Definition: ios2met.cxx:2846
#define GOrdPChBrx
Definition: ios2met.cxx:181
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_WHITE
#define SAL_INFO(area, stream)
#define GOrdSArcPa
Definition: ios2met.cxx:200
if(aStr!=aBuf) UpdateName_Impl(m_xFollowLb.get()
int GetError()
#define GOrdGivCrc
Definition: ios2met.cxx:83
#define GOrdPPtSym
Definition: ios2met.cxx:155
#define BegObEnv1Magic
Definition: ios2met.cxx:62
#define GOrdPMkSym
Definition: ios2met.cxx:196
#define SVSTREAM_FILEFORMAT_ERROR
Definition: errcode.hxx:260
#define GOrdCurStM
Definition: ios2met.cxx:97
#define GOrdNopNop
Definition: ios2met.cxx:119
sal_uInt64 Tell() const
void * p
QPRO_FUNC_TYPE nType
#define BegGrfObjMagic
Definition: ios2met.cxx:65
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_BLACK
#define GOrdEndImg
Definition: ios2met.cxx:106
Sequence< double > P0
#define GOrdPArcPa
Definition: ios2met.cxx:201
#define GOrdCurBzr
Definition: ios2met.cxx:78
#define BegImgObjMagic
Definition: ios2met.cxx:57
#define GOrdSChSet
Definition: ios2met.cxx:176
#define SAL_WARN(area, stream)
SvStreamEndian
#define GOrdPChPrc
Definition: ios2met.cxx:175
#define GOrdPPtSet
Definition: ios2met.cxx:153
#define GOrdPLnJoi
Definition: ios2met.cxx:162
aStr
#define GOrdSLnTyp
Definition: ios2met.cxx:163
#define GOrdPChXtr
Definition: ios2met.cxx:185
#define GOrdPLnTyp
Definition: ios2met.cxx:164
#define GOrdGivBox
Definition: ios2met.cxx:79
#define GOrdGivFil
Definition: ios2met.cxx:81
#define GOrdPCrPos
Definition: ios2met.cxx:204
#define GOrdPMkCel
Definition: ios2met.cxx:198
#define GOrdPLnWdt
Definition: ios2met.cxx:166
#define EndImgObjMagic
Definition: ios2met.cxx:58
sal_uInt16 nPos
void SetPrefMapMode(const MapMode &rMapMode)
Definition: gdimtf.hxx:176
#define GOrdPVwWin
Definition: ios2met.cxx:212
#define BegDocumnMagic
Definition: ios2met.cxx:46
#define GOrdSChAng
Definition: ios2met.cxx:178
#define GOrdSChShr
Definition: ios2met.cxx:186