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