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