bump product version to 7.2.5.1
[LibreOffice.git] / vcl / source / gdi / svmconverter.cxx
blob75f9482b12082eb6e5ece12f2b55e48e2361283f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <algorithm>
21 #include <string.h>
23 #include <o3tl/safeint.hxx>
24 #include <osl/thread.h>
25 #include <tools/fract.hxx>
26 #include <tools/stream.hxx>
27 #include <vcl/dibtools.hxx>
28 #include <vcl/virdev.hxx>
29 #include <vcl/lineinfo.hxx>
30 #include <vcl/metaact.hxx>
31 #include <sal/log.hxx>
32 #include <osl/diagnose.h>
34 #include <vcl/TypeSerializer.hxx>
35 #include <svmconverter.hxx>
36 #include <memory>
37 #include <stack>
39 // Inlines
40 static void ImplReadRect( SvStream& rIStm, tools::Rectangle& rRect )
42 Point aTL;
43 Point aBR;
45 TypeSerializer aSerializer(rIStm);
46 aSerializer.readPoint(aTL);
47 aSerializer.readPoint(aBR);
49 rRect = tools::Rectangle( aTL, aBR );
52 static bool ImplReadPoly(SvStream& rIStm, tools::Polygon& rPoly)
54 TypeSerializer aSerializer(rIStm);
56 sal_Int32 nSize32(0);
57 rIStm.ReadInt32(nSize32);
58 sal_uInt16 nSize = nSize32;
60 const size_t nMaxPossiblePoints = rIStm.remainingSize() / 2 * sizeof(sal_Int32);
61 if (nSize > nMaxPossiblePoints)
63 SAL_WARN("vcl.gdi", "svm record claims to have: " << nSize << " points, but only " << nMaxPossiblePoints << " possible");
64 return false;
67 rPoly = tools::Polygon(nSize);
69 for (sal_uInt16 i = 0; i < nSize && rIStm.good(); ++i)
71 aSerializer.readPoint(rPoly[i]);
73 return rIStm.good();
76 static bool ImplReadPolyPoly(SvStream& rIStm, tools::PolyPolygon& rPolyPoly)
78 bool bSuccess = true;
80 tools::Polygon aPoly;
81 sal_Int32 nPolyCount32(0);
82 rIStm.ReadInt32(nPolyCount32);
83 sal_uInt16 nPolyCount = static_cast<sal_uInt16>(nPolyCount32);
85 for (sal_uInt16 i = 0; i < nPolyCount && rIStm.good(); ++i)
87 if (!ImplReadPoly(rIStm, aPoly))
89 bSuccess = false;
90 break;
92 rPolyPoly.Insert(aPoly);
95 return bSuccess && rIStm.good();
98 static void ImplReadColor( SvStream& rIStm, Color& rColor )
100 sal_Int16 nVal(0);
102 rIStm.ReadInt16( nVal ); rColor.SetRed( sal::static_int_cast<sal_uInt8>(static_cast<sal_uInt16>(nVal) >> 8) );
103 rIStm.ReadInt16( nVal ); rColor.SetGreen( sal::static_int_cast<sal_uInt8>(static_cast<sal_uInt16>(nVal) >> 8) );
104 rIStm.ReadInt16( nVal ); rColor.SetBlue( sal::static_int_cast<sal_uInt8>(static_cast<sal_uInt16>(nVal) >> 8) );
107 static bool ImplReadMapMode(SvStream& rIStm, MapMode& rMapMode)
109 sal_Int16 nUnit(0);
110 rIStm.ReadInt16(nUnit);
112 Point aOrg;
113 TypeSerializer aSerializer(rIStm);
114 aSerializer.readPoint(aOrg);
116 sal_Int32 nXNum(0), nXDenom(0), nYNum(0), nYDenom(0);
117 rIStm.ReadInt32(nXNum).ReadInt32(nXDenom).ReadInt32(nYNum).ReadInt32(nYDenom);
119 if (!rIStm.good() || nXDenom <= 0 || nYDenom <= 0 || nXNum <= 0 || nYNum <= 0)
121 SAL_WARN("vcl.gdi", "Parsing error: invalid mapmode fraction");
122 return false;
125 if (nUnit < sal_Int16(MapUnit::Map100thMM) || nUnit > sal_Int16(MapUnit::LAST))
127 SAL_WARN("vcl.gdi", "Parsing error: invalid mapmode");
128 return false;
131 rMapMode = MapMode(static_cast<MapUnit>(nUnit), aOrg, Fraction(nXNum, nXDenom), Fraction(nYNum, nYDenom));
133 return true;
136 static void ImplReadUnicodeComment( sal_uInt32 nStrmPos, SvStream& rIStm, OUString& rString )
138 sal_uInt32 nOld = rIStm.Tell();
139 if ( nStrmPos )
141 sal_uInt16 nType;
142 sal_uInt32 nActionSize;
143 std::size_t nStringLen;
145 rIStm.Seek( nStrmPos );
146 rIStm .ReadUInt16( nType )
147 .ReadUInt32( nActionSize );
149 nStringLen = (nActionSize - 4) >> 1;
151 if ( nStringLen && ( nType == GDI_UNICODE_COMMENT ) )
152 rString = read_uInt16s_ToOUString(rIStm, nStringLen);
154 rIStm.Seek( nOld );
157 static void ImplSkipActions(SvStream& rIStm, sal_uLong nSkipCount)
159 sal_Int32 nActionSize;
160 sal_Int16 nType;
161 for (sal_uLong i = 0; i < nSkipCount; ++i)
163 rIStm.ReadInt16(nType).ReadInt32(nActionSize);
164 if (!rIStm.good() || nActionSize < 4)
165 break;
166 rIStm.SeekRel(nActionSize - 4);
170 static void ImplReadExtendedPolyPolygonAction(SvStream& rIStm, tools::PolyPolygon& rPolyPoly)
172 TypeSerializer aSerializer(rIStm);
174 rPolyPoly.Clear();
175 sal_uInt16 nPolygonCount(0);
176 rIStm.ReadUInt16( nPolygonCount );
178 if (!nPolygonCount)
179 return;
181 const size_t nMinRecordSize = sizeof(sal_uInt16);
182 const size_t nMaxRecords = rIStm.remainingSize() / nMinRecordSize;
183 if (nPolygonCount > nMaxRecords)
185 SAL_WARN("vcl.gdi", "Parsing error: " << nMaxRecords <<
186 " max possible entries, but " << nPolygonCount << " claimed, truncating");
187 nPolygonCount = nMaxRecords;
190 for(sal_uInt16 a(0); a < nPolygonCount; a++)
192 sal_uInt16 nPointCount(0);
193 rIStm.ReadUInt16(nPointCount);
195 const size_t nMinPolygonSize = sizeof(sal_Int32) * 2;
196 const size_t nMaxPolygons = rIStm.remainingSize() / nMinPolygonSize;
197 if (nPointCount > nMaxPolygons)
199 SAL_WARN("vcl.gdi", "Parsing error: " << nMaxPolygons <<
200 " max possible entries, but " << nPointCount << " claimed, truncating");
201 nPointCount = nMaxPolygons;
204 tools::Polygon aCandidate(nPointCount);
206 if (nPointCount)
208 for(sal_uInt16 b(0); b < nPointCount; b++)
210 aSerializer.readPoint(aCandidate[b]);
213 sal_uInt8 bHasFlags(int(false));
214 rIStm.ReadUChar( bHasFlags );
216 if(bHasFlags)
218 sal_uInt8 aPolyFlags(0);
220 for(sal_uInt16 c(0); c < nPointCount; c++)
222 rIStm.ReadUChar( aPolyFlags );
223 aCandidate.SetFlags(c, static_cast<PolyFlags>(aPolyFlags));
228 rPolyPoly.Insert(aCandidate);
232 SVMConverter::SVMConverter( SvStream& rStm, GDIMetaFile& rMtf )
234 if( !rStm.GetError() )
236 ImplConvertFromSVM1( rStm, rMtf );
240 namespace
242 sal_Int32 SkipActions(sal_Int32 i, sal_Int32 nFollowingActionCount, sal_Int32 nActions)
244 sal_Int32 remainingActions = nActions - i;
245 if (nFollowingActionCount < 0)
246 nFollowingActionCount = remainingActions;
247 return std::min(remainingActions, nFollowingActionCount);
251 #define LF_FACESIZE 32
253 void static lcl_error( SvStream& rIStm, const SvStreamEndian& nOldFormat, sal_uLong nPos)
255 rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
256 rIStm.SetEndian(nOldFormat);
257 rIStm.Seek(nPos);
258 return;
260 void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf )
262 const sal_uLong nPos = rIStm.Tell();
263 const SvStreamEndian nOldFormat = rIStm.GetEndian();
265 rIStm.SetEndian( SvStreamEndian::LITTLE );
267 char aCode[ 5 ];
268 Size aPrefSz;
270 // read header
271 rIStm.ReadBytes(aCode, sizeof(aCode)); // Identifier
272 sal_Int16 nSize(0);
273 rIStm.ReadInt16( nSize ); // Size
274 sal_Int16 nVersion(0);
275 rIStm.ReadInt16( nVersion ); // Version
276 sal_Int32 nTmp32(0);
277 rIStm.ReadInt32( nTmp32 );
278 if (nTmp32 < 0)
280 SAL_WARN("vcl.gdi", "svm: value for width should be positive");
281 lcl_error(rIStm, nOldFormat, nPos);
282 return;
284 aPrefSz.setWidth( nTmp32 ); // PrefSize.Width()
285 rIStm.ReadInt32( nTmp32 );
286 if (nTmp32 < 0)
288 SAL_WARN("vcl.gdi", "svm: value for height should be positive");
289 lcl_error(rIStm, nOldFormat, nPos);
290 return;
292 aPrefSz.setHeight( nTmp32 ); // PrefSize.Height()
294 // check header-magic and version
295 if( rIStm.GetError()
296 || ( memcmp( aCode, "SVGDI", sizeof( aCode ) ) != 0 )
297 || ( nVersion != 200 ) )
299 SAL_WARN("vcl.gdi", "svm: wrong check for header-magic and version");
300 lcl_error(rIStm, nOldFormat, nPos);
301 return;
304 LineInfo aLineInfo( LineStyle::NONE, 0 );
305 std::stack<std::unique_ptr<LineInfo>> aLIStack;
306 ScopedVclPtrInstance< VirtualDevice > aFontVDev;
307 rtl_TextEncoding eActualCharSet = osl_getThreadTextEncoding();
308 bool bFatLine = false;
310 tools::Polygon aActionPoly;
311 tools::Rectangle aRect;
312 Point aPt, aPt1;
313 Size aSz;
314 Color aActionColor;
316 sal_uInt32 nUnicodeCommentStreamPos = 0;
317 sal_Int32 nUnicodeCommentActionNumber = 0;
319 rMtf.SetPrefSize(aPrefSz);
321 MapMode aMapMode;
322 if (ImplReadMapMode(rIStm, aMapMode)) // MapMode
323 rMtf.SetPrefMapMode(aMapMode);
325 sal_Int32 nActions(0);
326 rIStm.ReadInt32(nActions); // Action count
327 if (nActions < 0)
329 SAL_WARN("vcl.gdi", "svm claims negative action count (" << nActions << ")");
330 nActions = 0;
333 const size_t nMinActionSize = sizeof(sal_uInt16) + sizeof(sal_Int32);
334 const size_t nMaxPossibleActions = rIStm.remainingSize() / nMinActionSize;
335 if (o3tl::make_unsigned(nActions) > nMaxPossibleActions)
337 SAL_WARN("vcl.gdi", "svm claims more actions (" << nActions << ") than stream could provide, truncating");
338 nActions = nMaxPossibleActions;
341 size_t nLastPolygonAction(0);
343 TypeSerializer aSerializer(rIStm);
345 for (sal_Int32 i = 0; i < nActions && rIStm.good(); ++i)
347 sal_Int16 nType(0);
348 rIStm.ReadInt16(nType);
349 sal_Int32 nActBegin = rIStm.Tell();
350 sal_Int32 nActionSize(0);
351 rIStm.ReadInt32(nActionSize);
353 SAL_WARN_IF( ( nType > 33 ) && ( nType < 1024 ), "vcl.gdi", "Unknown GDIMetaAction while converting!" );
355 switch( nType )
357 case GDI_PIXEL_ACTION:
359 aSerializer.readPoint(aPt);
360 ImplReadColor( rIStm, aActionColor );
361 rMtf.AddAction( new MetaPixelAction( aPt, aActionColor ) );
363 break;
365 case GDI_POINT_ACTION:
367 aSerializer.readPoint(aPt);
368 rMtf.AddAction( new MetaPointAction( aPt ) );
370 break;
372 case GDI_LINE_ACTION:
374 aSerializer.readPoint(aPt);
375 aSerializer.readPoint(aPt1);
376 rMtf.AddAction( new MetaLineAction( aPt, aPt1, aLineInfo ) );
378 break;
380 case GDI_LINEJOIN_ACTION :
382 sal_Int16 nLineJoin(0);
383 rIStm.ReadInt16( nLineJoin );
384 aLineInfo.SetLineJoin(static_cast<basegfx::B2DLineJoin>(nLineJoin));
386 break;
388 case GDI_LINECAP_ACTION :
390 sal_Int16 nLineCap(0);
391 rIStm.ReadInt16( nLineCap );
392 aLineInfo.SetLineCap(static_cast<css::drawing::LineCap>(nLineCap));
394 break;
396 case GDI_LINEDASHDOT_ACTION :
398 sal_Int16 a(0);
399 sal_Int32 b(0);
401 rIStm.ReadInt16( a ); aLineInfo.SetDashCount(a);
402 rIStm.ReadInt32( b ); aLineInfo.SetDashLen(b);
403 rIStm.ReadInt16( a ); aLineInfo.SetDotCount(a);
404 rIStm.ReadInt32( b ); aLineInfo.SetDotLen(b);
405 rIStm.ReadInt32( b ); aLineInfo.SetDistance(b);
407 if(((aLineInfo.GetDashCount() && aLineInfo.GetDashLen())
408 || (aLineInfo.GetDotCount() && aLineInfo.GetDotLen()))
409 && aLineInfo.GetDistance())
411 aLineInfo.SetStyle(LineStyle::Dash);
414 break;
416 case GDI_EXTENDEDPOLYGON_ACTION :
418 // read the tools::PolyPolygon in every case
419 tools::PolyPolygon aInputPolyPolygon;
420 ImplReadExtendedPolyPolygonAction(rIStm, aInputPolyPolygon);
422 // now check if it can be set somewhere
423 if(nLastPolygonAction < rMtf.GetActionSize())
425 MetaPolyLineAction* pPolyLineAction = dynamic_cast< MetaPolyLineAction* >(rMtf.GetAction(nLastPolygonAction));
427 if(pPolyLineAction)
429 // replace MetaPolyLineAction when we have a single polygon. Do not rely on the
430 // same point count; the originally written GDI_POLYLINE_ACTION may have been
431 // Subdivided for better quality for older usages
432 if(1 == aInputPolyPolygon.Count())
434 rMtf.ReplaceAction(
435 new MetaPolyLineAction(
436 aInputPolyPolygon.GetObject(0),
437 pPolyLineAction->GetLineInfo()),
438 nLastPolygonAction);
441 else
443 MetaPolyPolygonAction* pPolyPolygonAction = dynamic_cast< MetaPolyPolygonAction* >(rMtf.GetAction(nLastPolygonAction));
445 if(pPolyPolygonAction)
447 // replace MetaPolyPolygonAction when we have a curved polygon. Do rely on the
448 // same sub-polygon count
449 if(pPolyPolygonAction->GetPolyPolygon().Count() == aInputPolyPolygon.Count())
451 rMtf.ReplaceAction(
452 new MetaPolyPolygonAction(
453 aInputPolyPolygon),
454 nLastPolygonAction);
457 else
459 MetaPolygonAction* pPolygonAction = dynamic_cast< MetaPolygonAction* >(rMtf.GetAction(nLastPolygonAction));
461 if(pPolygonAction)
463 // replace MetaPolygonAction
464 if(1 == aInputPolyPolygon.Count())
466 rMtf.ReplaceAction(
467 new MetaPolygonAction(
468 aInputPolyPolygon.GetObject(0)),
469 nLastPolygonAction);
476 break;
478 case GDI_RECT_ACTION:
480 ImplReadRect( rIStm, aRect );
481 sal_Int32 nTmp(0), nTmp1(0);
482 rIStm.ReadInt32( nTmp ).ReadInt32( nTmp1 );
484 if( nTmp || nTmp1 )
485 rMtf.AddAction( new MetaRoundRectAction( aRect, nTmp, nTmp1 ) );
486 else
488 rMtf.AddAction( new MetaRectAction( aRect ) );
490 if( bFatLine )
491 rMtf.AddAction( new MetaPolyLineAction( aRect, aLineInfo ) );
494 break;
496 case GDI_ELLIPSE_ACTION:
498 ImplReadRect( rIStm, aRect );
500 if( bFatLine )
502 const tools::Polygon aPoly( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 );
504 rMtf.AddAction( new MetaPushAction( PushFlags::LINECOLOR ) );
505 rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) );
506 rMtf.AddAction( new MetaPolygonAction( aPoly ) );
507 rMtf.AddAction( new MetaPopAction() );
508 rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) );
510 else
511 rMtf.AddAction( new MetaEllipseAction( aRect ) );
513 break;
515 case GDI_ARC_ACTION:
517 ImplReadRect( rIStm, aRect );
518 aSerializer.readPoint(aPt);
519 aSerializer.readPoint(aPt1);
521 if( bFatLine )
523 const tools::Polygon aPoly( aRect, aPt, aPt1, PolyStyle::Arc );
525 rMtf.AddAction( new MetaPushAction( PushFlags::LINECOLOR ) );
526 rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) );
527 rMtf.AddAction( new MetaPolygonAction( aPoly ) );
528 rMtf.AddAction( new MetaPopAction() );
529 rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) );
531 else
532 rMtf.AddAction( new MetaArcAction( aRect, aPt, aPt1 ) );
534 break;
536 case GDI_PIE_ACTION:
538 ImplReadRect( rIStm, aRect );
539 aSerializer.readPoint(aPt);
540 aSerializer.readPoint(aPt1);
542 if( bFatLine )
544 const tools::Polygon aPoly( aRect, aPt, aPt1, PolyStyle::Pie );
546 rMtf.AddAction( new MetaPushAction( PushFlags::LINECOLOR ) );
547 rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) );
548 rMtf.AddAction( new MetaPolygonAction( aPoly ) );
549 rMtf.AddAction( new MetaPopAction() );
550 rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) );
552 else
553 rMtf.AddAction( new MetaPieAction( aRect, aPt, aPt1 ) );
555 break;
557 case GDI_INVERTRECT_ACTION:
558 case GDI_HIGHLIGHTRECT_ACTION:
560 ImplReadRect( rIStm, aRect );
561 rMtf.AddAction( new MetaPushAction( PushFlags::RASTEROP ) );
562 rMtf.AddAction( new MetaRasterOpAction( RasterOp::Invert ) );
563 rMtf.AddAction( new MetaRectAction( aRect ) );
564 rMtf.AddAction( new MetaPopAction() );
566 break;
568 case GDI_POLYLINE_ACTION:
570 if (ImplReadPoly(rIStm, aActionPoly))
572 nLastPolygonAction = rMtf.GetActionSize();
574 if( bFatLine )
575 rMtf.AddAction( new MetaPolyLineAction( aActionPoly, aLineInfo ) );
576 else
577 rMtf.AddAction( new MetaPolyLineAction( aActionPoly ) );
580 break;
582 case GDI_POLYGON_ACTION:
584 if (ImplReadPoly(rIStm, aActionPoly))
586 if( bFatLine )
588 rMtf.AddAction( new MetaPushAction( PushFlags::LINECOLOR ) );
589 rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) );
590 rMtf.AddAction( new MetaPolygonAction( aActionPoly ) );
591 rMtf.AddAction( new MetaPopAction() );
592 rMtf.AddAction( new MetaPolyLineAction( aActionPoly, aLineInfo ) );
594 else
596 nLastPolygonAction = rMtf.GetActionSize();
597 rMtf.AddAction( new MetaPolygonAction( aActionPoly ) );
601 break;
603 case GDI_POLYPOLYGON_ACTION:
605 tools::PolyPolygon aPolyPoly;
607 if (ImplReadPolyPoly(rIStm, aPolyPoly))
609 if( bFatLine )
611 rMtf.AddAction( new MetaPushAction( PushFlags::LINECOLOR ) );
612 rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) );
613 rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) );
614 rMtf.AddAction( new MetaPopAction() );
616 for( sal_uInt16 nPoly = 0, nCount = aPolyPoly.Count(); nPoly < nCount; nPoly++ )
617 rMtf.AddAction( new MetaPolyLineAction( aPolyPoly[ nPoly ], aLineInfo ) );
619 else
621 nLastPolygonAction = rMtf.GetActionSize();
622 rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) );
626 break;
628 case GDI_FONT_ACTION:
630 vcl::Font aFont;
631 char aName[LF_FACESIZE+1];
633 ImplReadColor( rIStm, aActionColor ); aFont.SetColor( aActionColor );
634 ImplReadColor( rIStm, aActionColor ); aFont.SetFillColor( aActionColor );
635 size_t nRet = rIStm.ReadBytes(aName, LF_FACESIZE);
636 aName[nRet] = 0;
637 aFont.SetFamilyName( OUString( aName, strlen(aName), rIStm.GetStreamCharSet() ) );
639 sal_Int32 nWidth(0), nHeight(0);
640 rIStm.ReadInt32(nWidth).ReadInt32(nHeight);
641 sal_Int16 nCharOrient(0), nLineOrient(0);
642 rIStm.ReadInt16(nCharOrient).ReadInt16(nLineOrient);
643 sal_Int16 nCharSet(0), nFamily(0), nPitch(0), nAlign(0), nWeight(0), nUnderline(0), nStrikeout(0);
644 rIStm.ReadInt16(nCharSet).ReadInt16(nFamily).ReadInt16(nPitch).ReadInt16(nAlign).ReadInt16(nWeight).ReadInt16(nUnderline).ReadInt16(nStrikeout);
645 bool bItalic(false), bOutline(false), bShadow(false), bTransparent(false);
646 rIStm.ReadCharAsBool(bItalic).ReadCharAsBool(bOutline).ReadCharAsBool(bShadow).ReadCharAsBool(bTransparent);
648 aFont.SetFontSize( Size( nWidth, nHeight ) );
649 aFont.SetCharSet( static_cast<rtl_TextEncoding>(nCharSet) );
650 aFont.SetFamily( static_cast<FontFamily>(nFamily) );
651 aFont.SetPitch( static_cast<FontPitch>(nPitch) );
652 aFont.SetAlignment( static_cast<FontAlign>(nAlign) );
653 aFont.SetWeight( ( nWeight == 1 ) ? WEIGHT_LIGHT : ( nWeight == 2 ) ? WEIGHT_NORMAL :
654 ( nWeight == 3 ) ? WEIGHT_BOLD : WEIGHT_DONTKNOW );
655 aFont.SetUnderline( static_cast<FontLineStyle>(nUnderline) );
656 aFont.SetStrikeout( static_cast<FontStrikeout>(nStrikeout) );
657 aFont.SetItalic( bItalic ? ITALIC_NORMAL : ITALIC_NONE );
658 aFont.SetOutline( bOutline );
659 aFont.SetShadow( bShadow );
660 aFont.SetOrientation( Degree10(nLineOrient) );
661 aFont.SetTransparent( bTransparent );
663 eActualCharSet = aFont.GetCharSet();
664 if ( eActualCharSet == RTL_TEXTENCODING_DONTKNOW )
665 eActualCharSet = osl_getThreadTextEncoding();
667 rMtf.AddAction( new MetaFontAction( aFont ) );
668 rMtf.AddAction( new MetaTextAlignAction( aFont.GetAlignment() ) );
669 rMtf.AddAction( new MetaTextColorAction( aFont.GetColor() ) );
670 rMtf.AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) );
672 // #106172# Track font relevant data in shadow VDev
673 aFontVDev->SetFont( aFont );
675 break;
677 case GDI_TEXT_ACTION:
679 sal_Int32 nIndex(0), nLen(0), nTmp(0);
680 aSerializer.readPoint(aPt);
681 rIStm.ReadInt32( nIndex ).ReadInt32( nLen ).ReadInt32( nTmp );
682 if (nTmp > 0)
684 OString aByteStr = read_uInt8s_ToOString(rIStm, nTmp);
685 sal_uInt8 nTerminator = 0;
686 rIStm.ReadUChar( nTerminator );
687 SAL_WARN_IF( nTerminator != 0, "vcl.gdi", "expected string to be NULL terminated" );
689 OUString aStr(OStringToOUString(aByteStr, eActualCharSet));
690 if ( nUnicodeCommentActionNumber == i )
691 ImplReadUnicodeComment( nUnicodeCommentStreamPos, rIStm, aStr );
692 rMtf.AddAction( new MetaTextAction( aPt, aStr, nIndex, nLen ) );
695 if (nActionSize < 24)
696 rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
697 else
698 rIStm.Seek(nActBegin + nActionSize);
700 break;
702 case GDI_TEXTARRAY_ACTION:
704 sal_Int32 nIndex(0), nLen(0), nAryLen(0), nTmp(0);
705 aSerializer.readPoint(aPt);
706 rIStm.ReadInt32( nIndex ).ReadInt32( nLen ).ReadInt32( nTmp ).ReadInt32( nAryLen );
707 if (nTmp > 0)
709 OString aByteStr = read_uInt8s_ToOString(rIStm, nTmp);
710 sal_uInt8 nTerminator = 0;
711 rIStm.ReadUChar( nTerminator );
712 SAL_WARN_IF( nTerminator != 0, "vcl.gdi", "expected string to be NULL terminated" );
714 OUString aStr(OStringToOUString(aByteStr, eActualCharSet));
716 std::unique_ptr<tools::Long[]> pDXAry;
717 if (nAryLen > 0)
719 const size_t nMinRecordSize = sizeof(sal_Int32);
720 const size_t nMaxRecords = rIStm.remainingSize() / nMinRecordSize;
721 if (o3tl::make_unsigned(nAryLen) > nMaxRecords)
723 SAL_WARN("vcl.gdi", "Parsing error: " << nMaxRecords <<
724 " max possible entries, but " << nAryLen << " claimed, truncating");
725 nAryLen = nMaxRecords;
728 sal_Int32 nStrLen( aStr.getLength() );
730 sal_Int32 nDXAryLen = std::max(nAryLen, nStrLen);
732 if (nDXAryLen < nLen)
734 //MetaTextArrayAction ctor expects pDXAry to be >= nLen if set, so if this can't
735 //be achieved, don't read it, it's utterly broken.
736 SAL_WARN("vcl.gdi", "dxary too short, discarding completely");
737 rIStm.SeekRel(sizeof(sal_Int32) * nDXAryLen);
738 nLen = 0;
739 nIndex = 0;
741 else
743 pDXAry.reset(new tools::Long[nDXAryLen]);
745 for (sal_Int32 j = 0; j < nAryLen; ++j)
747 rIStm.ReadInt32( nTmp );
748 pDXAry[ j ] = nTmp;
751 // #106172# Add last DX array elem, if missing
752 if( nAryLen != nStrLen )
754 if (nAryLen+1 == nStrLen && nIndex >= 0)
756 std::unique_ptr<tools::Long[]> pTmpAry(new tools::Long[nStrLen]);
758 aFontVDev->GetTextArray( aStr, pTmpAry.get(), nIndex, nLen );
760 // now, the difference between the
761 // last and the second last DX array
762 // is the advancement for the last
763 // glyph. Thus, to complete our meta
764 // action's DX array, just add that
765 // difference to last elem and store
766 // in very last.
767 if( nStrLen > 1 )
768 pDXAry[ nStrLen-1 ] = pDXAry[ nStrLen-2 ] + pTmpAry[ nStrLen-1 ] - pTmpAry[ nStrLen-2 ];
769 else
770 pDXAry[ nStrLen-1 ] = pTmpAry[ nStrLen-1 ]; // len=1: 0th position taken to be 0
772 #ifdef DBG_UTIL
773 else
774 OSL_FAIL("More than one DX array element missing on SVM import");
775 #endif
779 if ( nUnicodeCommentActionNumber == i )
780 ImplReadUnicodeComment( nUnicodeCommentStreamPos, rIStm, aStr );
781 rMtf.AddAction( new MetaTextArrayAction( aPt, aStr, pDXAry.get(), nIndex, nLen ) );
784 if (nActionSize < 24)
785 rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
786 else
787 rIStm.Seek(nActBegin + nActionSize);
789 break;
791 case GDI_STRETCHTEXT_ACTION:
793 sal_Int32 nIndex(0), nLen(0), nWidth(0), nTmp(0);
795 aSerializer.readPoint(aPt);
796 rIStm.ReadInt32( nIndex ).ReadInt32( nLen ).ReadInt32( nTmp ).ReadInt32( nWidth );
797 if (nTmp > 0)
799 OString aByteStr = read_uInt8s_ToOString(rIStm, nTmp);
800 sal_uInt8 nTerminator = 0;
801 rIStm.ReadUChar( nTerminator );
802 SAL_WARN_IF( nTerminator != 0, "vcl.gdi", "expected string to be NULL terminated" );
804 OUString aStr(OStringToOUString(aByteStr, eActualCharSet));
805 if ( nUnicodeCommentActionNumber == i )
806 ImplReadUnicodeComment( nUnicodeCommentStreamPos, rIStm, aStr );
807 rMtf.AddAction( new MetaStretchTextAction( aPt, nWidth, aStr, nIndex, nLen ) );
810 if (nActionSize < 28)
811 rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
812 else
813 rIStm.Seek(nActBegin + nActionSize);
815 break;
817 case GDI_BITMAP_ACTION:
819 Bitmap aBmp;
821 aSerializer.readPoint(aPt);
822 ReadDIB(aBmp, rIStm, true);
823 rMtf.AddAction( new MetaBmpAction( aPt, aBmp ) );
825 break;
827 case GDI_BITMAPSCALE_ACTION:
829 Bitmap aBmp;
831 aSerializer.readPoint(aPt);
832 aSerializer.readSize(aSz);
833 ReadDIB(aBmp, rIStm, true);
834 rMtf.AddAction( new MetaBmpScaleAction( aPt, aSz, aBmp ) );
836 break;
838 case GDI_BITMAPSCALEPART_ACTION:
840 Bitmap aBmp;
841 Size aSz2;
843 aSerializer.readPoint(aPt);
844 aSerializer.readSize(aSz);
845 aSerializer.readPoint(aPt1);
846 aSerializer.readSize(aSz2);
847 ReadDIB(aBmp, rIStm, true);
848 rMtf.AddAction( new MetaBmpScalePartAction( aPt, aSz, aPt1, aSz2, aBmp ) );
850 break;
852 case GDI_PEN_ACTION:
854 sal_Int32 nPenWidth;
855 sal_Int16 nPenStyle;
857 ImplReadColor( rIStm, aActionColor );
858 rIStm.ReadInt32( nPenWidth ).ReadInt16( nPenStyle );
860 aLineInfo.SetStyle( nPenStyle ? LineStyle::Solid : LineStyle::NONE );
861 aLineInfo.SetWidth( nPenWidth );
862 bFatLine = nPenStyle && !aLineInfo.IsDefault();
864 rMtf.AddAction( new MetaLineColorAction( aActionColor, nPenStyle != 0 ) );
866 break;
868 case GDI_FILLBRUSH_ACTION:
870 sal_Int16 nBrushStyle;
872 ImplReadColor( rIStm, aActionColor );
873 rIStm.SeekRel( 6 );
874 rIStm.ReadInt16( nBrushStyle );
875 rMtf.AddAction( new MetaFillColorAction( aActionColor, nBrushStyle != 0 ) );
876 rIStm.SeekRel( 2 );
878 break;
880 case GDI_MAPMODE_ACTION:
882 if (ImplReadMapMode(rIStm, aMapMode))
884 rMtf.AddAction(new MetaMapModeAction(aMapMode));
886 // #106172# Track font relevant data in shadow VDev
887 aFontVDev->SetMapMode(aMapMode);
890 break;
892 case GDI_CLIPREGION_ACTION:
894 vcl::Region aRegion;
895 sal_Int16 nRegType;
896 sal_Int16 bIntersect;
897 bool bClip = false;
899 rIStm.ReadInt16( nRegType ).ReadInt16( bIntersect );
900 ImplReadRect( rIStm, aRect );
902 switch( nRegType )
904 case 0:
905 break;
907 case 1:
909 tools::Rectangle aRegRect;
911 ImplReadRect( rIStm, aRegRect );
912 aRegion = vcl::Region( aRegRect );
913 bClip = true;
915 break;
917 case 2:
919 if (ImplReadPoly(rIStm, aActionPoly))
921 aRegion = vcl::Region( aActionPoly );
922 bClip = true;
925 break;
927 case 3:
929 bool bSuccess = true;
930 tools::PolyPolygon aPolyPoly;
931 sal_Int32 nPolyCount32(0);
932 rIStm.ReadInt32(nPolyCount32);
933 sal_uInt16 nPolyCount(nPolyCount32);
935 for (sal_uInt16 j = 0; j < nPolyCount && rIStm.good(); ++j)
937 if (!ImplReadPoly(rIStm, aActionPoly))
939 bSuccess = false;
940 break;
942 aPolyPoly.Insert(aActionPoly);
945 if (bSuccess)
947 aRegion = vcl::Region( aPolyPoly );
948 bClip = true;
951 break;
954 if( bIntersect )
955 aRegion.Intersect( aRect );
957 rMtf.AddAction( new MetaClipRegionAction( aRegion, bClip ) );
959 break;
961 case GDI_MOVECLIPREGION_ACTION:
963 sal_Int32 nTmp(0), nTmp1(0);
964 rIStm.ReadInt32( nTmp ).ReadInt32( nTmp1 );
965 rMtf.AddAction( new MetaMoveClipRegionAction( nTmp, nTmp1 ) );
967 break;
969 case GDI_ISECTCLIPREGION_ACTION:
971 ImplReadRect( rIStm, aRect );
972 rMtf.AddAction( new MetaISectRectClipRegionAction( aRect ) );
974 break;
976 case GDI_RASTEROP_ACTION:
978 RasterOp eRasterOp;
979 sal_Int16 nRasterOp;
981 rIStm.ReadInt16( nRasterOp );
983 switch( nRasterOp )
985 case 1:
986 eRasterOp = RasterOp::Invert;
987 break;
989 case 4:
990 case 5:
991 eRasterOp = RasterOp::Xor;
992 break;
994 default:
995 eRasterOp = RasterOp::OverPaint;
996 break;
999 rMtf.AddAction( new MetaRasterOpAction( eRasterOp ) );
1001 break;
1003 case GDI_PUSH_ACTION:
1005 aLIStack.push(std::make_unique<LineInfo>(aLineInfo));
1006 rMtf.AddAction( new MetaPushAction( PushFlags::ALL ) );
1008 // #106172# Track font relevant data in shadow VDev
1009 aFontVDev->Push();
1011 break;
1013 case GDI_POP_ACTION:
1016 std::unique_ptr<LineInfo> xLineInfo;
1017 if (!aLIStack.empty())
1019 xLineInfo = std::move(aLIStack.top());
1020 aLIStack.pop();
1023 // restore line info
1024 if (xLineInfo)
1026 aLineInfo = *xLineInfo;
1027 xLineInfo.reset();
1028 bFatLine = ( LineStyle::NONE != aLineInfo.GetStyle() ) && !aLineInfo.IsDefault();
1031 rMtf.AddAction( new MetaPopAction() );
1033 // #106172# Track font relevant data in shadow VDev
1034 aFontVDev->Pop();
1036 break;
1038 case GDI_GRADIENT_ACTION:
1040 Color aStartCol;
1041 Color aEndCol;
1042 sal_Int16 nStyle;
1043 sal_Int16 nAngle;
1044 sal_Int16 nBorder;
1045 sal_Int16 nOfsX;
1046 sal_Int16 nOfsY;
1047 sal_Int16 nIntensityStart;
1048 sal_Int16 nIntensityEnd;
1050 ImplReadRect( rIStm, aRect );
1051 rIStm.ReadInt16( nStyle );
1052 ImplReadColor( rIStm, aStartCol );
1053 ImplReadColor( rIStm, aEndCol );
1054 rIStm.ReadInt16( nAngle ).ReadInt16( nBorder ).ReadInt16( nOfsX ).ReadInt16( nOfsY ).ReadInt16( nIntensityStart ).ReadInt16( nIntensityEnd );
1056 Gradient aGrad( static_cast<GradientStyle>(nStyle), aStartCol, aEndCol );
1058 aGrad.SetAngle( Degree10(nAngle) );
1059 aGrad.SetBorder( nBorder );
1060 aGrad.SetOfsX( nOfsX );
1061 aGrad.SetOfsY( nOfsY );
1062 aGrad.SetStartIntensity( nIntensityStart );
1063 aGrad.SetEndIntensity( nIntensityEnd );
1064 rMtf.AddAction( new MetaGradientAction( aRect, aGrad ) );
1066 break;
1068 case GDI_TRANSPARENT_COMMENT:
1070 tools::PolyPolygon aPolyPoly;
1071 sal_Int32 nFollowingActionCount(0);
1072 sal_Int16 nTrans(0);
1074 ReadPolyPolygon( rIStm, aPolyPoly );
1075 rIStm.ReadInt16( nTrans ).ReadInt32( nFollowingActionCount );
1076 ImplSkipActions( rIStm, nFollowingActionCount );
1077 rMtf.AddAction( new MetaTransparentAction( aPolyPoly, nTrans ) );
1079 i = SkipActions(i, nFollowingActionCount, nActions);
1081 break;
1083 case GDI_FLOATTRANSPARENT_COMMENT:
1085 GDIMetaFile aMtf;
1086 Point aPos;
1087 Size aSize;
1088 Gradient aGradient;
1089 sal_Int32 nFollowingActionCount(0);
1091 ReadGDIMetaFile( rIStm, aMtf );
1092 aSerializer.readPoint(aPos);
1093 aSerializer.readSize(aSize);
1094 aSerializer.readGradient(aGradient);
1095 rIStm.ReadInt32( nFollowingActionCount );
1096 ImplSkipActions( rIStm, nFollowingActionCount );
1097 rMtf.AddAction( new MetaFloatTransparentAction( aMtf, aPos, aSize, aGradient ) );
1099 i = SkipActions(i, nFollowingActionCount, nActions);
1101 break;
1103 case GDI_HATCH_COMMENT:
1105 tools::PolyPolygon aPolyPoly;
1106 Hatch aHatch;
1107 sal_Int32 nFollowingActionCount(0);
1109 ReadPolyPolygon( rIStm, aPolyPoly );
1110 ReadHatch( rIStm, aHatch );
1111 rIStm.ReadInt32( nFollowingActionCount );
1112 ImplSkipActions( rIStm, nFollowingActionCount );
1113 rMtf.AddAction( new MetaHatchAction( aPolyPoly, aHatch ) );
1115 i = SkipActions(i, nFollowingActionCount, nActions);
1117 break;
1119 case GDI_REFPOINT_COMMENT:
1121 Point aRefPoint;
1122 bool bSet;
1123 sal_Int32 nFollowingActionCount(0);
1125 aSerializer.readPoint(aRefPoint);
1126 rIStm.ReadCharAsBool( bSet ).ReadInt32( nFollowingActionCount );
1127 ImplSkipActions( rIStm, nFollowingActionCount );
1128 rMtf.AddAction( new MetaRefPointAction( aRefPoint, bSet ) );
1130 i = SkipActions(i, nFollowingActionCount, nActions);
1132 // #106172# Track font relevant data in shadow VDev
1133 if( bSet )
1134 aFontVDev->SetRefPoint( aRefPoint );
1135 else
1136 aFontVDev->SetRefPoint();
1138 break;
1140 case GDI_TEXTLINECOLOR_COMMENT:
1142 Color aColor;
1143 bool bSet;
1144 sal_Int32 nFollowingActionCount(0);
1146 aSerializer.readColor(aColor);
1147 rIStm.ReadCharAsBool( bSet ).ReadInt32( nFollowingActionCount );
1148 ImplSkipActions( rIStm, nFollowingActionCount );
1149 rMtf.AddAction( new MetaTextLineColorAction( aColor, bSet ) );
1151 i = SkipActions(i, nFollowingActionCount, nActions);
1153 break;
1155 case GDI_TEXTLINE_COMMENT:
1157 Point aStartPt;
1158 sal_Int32 nWidth(0);
1159 sal_uInt32 nStrikeout(0);
1160 sal_uInt32 nUnderline(0);
1161 sal_Int32 nFollowingActionCount(0);
1163 aSerializer.readPoint(aStartPt);
1164 rIStm.ReadInt32(nWidth ).ReadUInt32(nStrikeout).ReadUInt32(nUnderline).ReadInt32(nFollowingActionCount);
1165 ImplSkipActions(rIStm, nFollowingActionCount);
1166 rMtf.AddAction( new MetaTextLineAction( aStartPt, nWidth,
1167 static_cast<FontStrikeout>(nStrikeout),
1168 static_cast<FontLineStyle>(nUnderline),
1169 LINESTYLE_NONE ) );
1171 i = SkipActions(i, nFollowingActionCount, nActions);
1173 break;
1175 case GDI_GRADIENTEX_COMMENT:
1177 tools::PolyPolygon aPolyPoly;
1178 Gradient aGradient;
1179 sal_Int32 nFollowingActionCount(0);
1181 ReadPolyPolygon( rIStm, aPolyPoly );
1182 aSerializer.readGradient(aGradient);
1183 rIStm.ReadInt32( nFollowingActionCount );
1184 ImplSkipActions( rIStm, nFollowingActionCount );
1185 rMtf.AddAction( new MetaGradientExAction( aPolyPoly, aGradient ) );
1187 i = SkipActions(i, nFollowingActionCount, nActions);
1189 break;
1191 case GDI_COMMENT_COMMENT:
1193 std::vector<sal_uInt8> aData;
1195 OString aComment = read_uInt16_lenPrefixed_uInt8s_ToOString(rIStm);
1196 sal_Int32 nValue(0);
1197 sal_uInt32 nDataSize(0);
1198 rIStm.ReadInt32(nValue).ReadUInt32(nDataSize);
1200 if (nDataSize)
1202 const size_t nMaxPossibleData = rIStm.remainingSize();
1203 if (nDataSize > nMaxPossibleActions)
1205 SAL_WARN("vcl.gdi", "svm record claims to have: " << nDataSize << " data, but only " << nMaxPossibleData << " possible");
1206 nDataSize = nMaxPossibleActions;
1208 aData.resize(nDataSize);
1209 nDataSize = rIStm.ReadBytes(aData.data(), nDataSize);
1212 sal_Int32 nFollowingActionCount(0);
1213 rIStm.ReadInt32(nFollowingActionCount);
1214 ImplSkipActions( rIStm, nFollowingActionCount );
1215 rMtf.AddAction(new MetaCommentAction(aComment, nValue, aData.data(), nDataSize));
1217 i = SkipActions(i, nFollowingActionCount, nActions);
1219 break;
1221 case GDI_UNICODE_COMMENT:
1223 nUnicodeCommentActionNumber = i + 1;
1224 nUnicodeCommentStreamPos = rIStm.Tell() - 6;
1225 if (nActionSize < 4)
1226 rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
1227 else
1228 rIStm.SeekRel(nActionSize - 4);
1230 break;
1232 default:
1233 if (nActionSize < 4)
1234 rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
1235 else
1236 rIStm.SeekRel(nActionSize - 4);
1237 break;
1241 rIStm.SetEndian( nOldFormat );
1244 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */