Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / vcl / source / gdi / svmconverter.cxx
blob049479961bef84f2fdcd01572666db494a8cda0c
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>
22 #include <osl/thread.h>
23 #include <tools/debug.hxx>
24 #include <tools/fract.hxx>
25 #include <tools/stream.hxx>
26 #include <tools/helpers.hxx>
27 #include <vcl/dibtools.hxx>
28 #include <vcl/virdev.hxx>
29 #include <vcl/graph.hxx>
30 #include <vcl/lineinfo.hxx>
31 #include <rtl/strbuf.hxx>
33 #include "svmconverter.hxx"
35 #include <memory>
36 #include <o3tl/make_unique.hxx>
38 // Inlines
39 void ImplReadRect( SvStream& rIStm, tools::Rectangle& rRect )
41 Point aTL;
42 Point aBR;
44 ReadPair( rIStm, aTL );
45 ReadPair( rIStm, aBR );
47 rRect = tools::Rectangle( aTL, aBR );
50 void ImplWriteRect( SvStream& rOStm, const tools::Rectangle& rRect )
52 WritePair( rOStm, rRect.TopLeft() );
53 WritePair( rOStm, rRect.BottomRight() );
56 bool ImplReadPoly(SvStream& rIStm, tools::Polygon& rPoly)
58 sal_Int32 nSize32(0);
59 rIStm.ReadInt32(nSize32);
60 sal_uInt16 nSize = nSize32;
62 const size_t nMaxPossiblePoints = rIStm.remainingSize() / 2 * sizeof(sal_Int32);
63 if (nSize > nMaxPossiblePoints)
65 SAL_WARN("vcl.gdi", "svm record claims to have: " << nSize << " points, but only " << nMaxPossiblePoints << " possible");
66 return false;
69 rPoly = tools::Polygon(nSize);
71 for (sal_uInt16 i = 0; i < nSize && rIStm.good(); ++i)
72 ReadPair(rIStm, rPoly[i]);
74 return rIStm.good();
77 bool ImplReadPolyPoly(SvStream& rIStm, tools::PolyPolygon& rPolyPoly)
79 bool bSuccess = true;
81 tools::Polygon aPoly;
82 sal_Int32 nPolyCount32(0);
83 rIStm.ReadInt32(nPolyCount32);
84 sal_uInt16 nPolyCount = (sal_uInt16)nPolyCount32;
86 for (sal_uInt16 i = 0; i < nPolyCount && rIStm.good(); ++i)
88 if (!ImplReadPoly(rIStm, aPoly))
90 bSuccess = false;
91 break;
93 rPolyPoly.Insert(aPoly);
96 return bSuccess && rIStm.good();
99 void ImplWritePolyPolyAction( SvStream& rOStm, const tools::PolyPolygon& rPolyPoly )
101 const sal_uInt16 nPoly = rPolyPoly.Count();
102 sal_uInt16 nPoints = 0;
103 sal_uInt16 n;
105 for( n = 0; n < nPoly; n++ )
106 nPoints = sal::static_int_cast<sal_uInt16>(nPoints + rPolyPoly[ n ].GetSize());
108 rOStm.WriteInt16( GDI_POLYPOLYGON_ACTION );
109 rOStm.WriteInt32( 8 + ( nPoly << 2 ) + ( nPoints << 3 ) );
110 rOStm.WriteInt32( nPoly );
112 for( n = 0; n < nPoly; n++ )
114 // #i102224# Here the possible curved nature of Polygon was
115 // ignored (for all those years). Adapted to at least write
116 // a polygon representing the curve as good as possible
117 tools::Polygon aSimplePoly;
118 rPolyPoly[n].AdaptiveSubdivide(aSimplePoly);
119 const sal_uInt16 nSize(aSimplePoly.GetSize());
121 rOStm.WriteInt32( nSize );
123 for( sal_uInt16 j = 0; j < nSize; j++ )
124 WritePair( rOStm, aSimplePoly[ j ] );
128 void ImplReadColor( SvStream& rIStm, Color& rColor )
130 sal_Int16 nVal(0);
132 rIStm.ReadInt16( nVal ); rColor.SetRed( sal::static_int_cast<sal_uInt8>((sal_uInt16)nVal >> 8) );
133 rIStm.ReadInt16( nVal ); rColor.SetGreen( sal::static_int_cast<sal_uInt8>((sal_uInt16)nVal >> 8) );
134 rIStm.ReadInt16( nVal ); rColor.SetBlue( sal::static_int_cast<sal_uInt8>((sal_uInt16)nVal >> 8) );
137 void ImplWriteColor( SvStream& rOStm, const Color& rColor )
139 sal_Int16 nVal;
141 nVal = ( (sal_Int16) rColor.GetRed() << 8 ) | rColor.GetRed();
142 rOStm.WriteInt16( nVal );
144 nVal = ( (sal_Int16) rColor.GetGreen() << 8 ) | rColor.GetGreen();
145 rOStm.WriteInt16( nVal );
147 nVal = ( (sal_Int16) rColor.GetBlue() << 8 ) | rColor.GetBlue();
148 rOStm.WriteInt16( nVal );
151 bool ImplReadMapMode(SvStream& rIStm, MapMode& rMapMode)
153 sal_Int16 nUnit(0);
154 rIStm.ReadInt16(nUnit);
156 Point aOrg;
157 ReadPair(rIStm, aOrg);
159 sal_Int32 nXNum(0), nXDenom(0), nYNum(0), nYDenom(0);
160 rIStm.ReadInt32(nXNum).ReadInt32(nXDenom).ReadInt32(nYNum).ReadInt32(nYDenom);
162 if (!rIStm.good() || nXDenom <= 0 || nYDenom <= 0 || nXNum <= 0 || nYNum <= 0)
164 SAL_WARN("vcl.gdi", "Parsing error: invalid mapmode fraction");
165 return false;
168 if (nUnit < sal_Int16(MapUnit::Map100thMM) || nUnit > sal_Int16(MapUnit::LAST))
170 SAL_WARN("vcl.gdi", "Parsing error: invalid mapmode");
171 return false;
174 rMapMode = MapMode((MapUnit) nUnit, aOrg, Fraction(nXNum, nXDenom), Fraction(nYNum, nYDenom));
176 return true;
179 void ImplWriteMapMode( SvStream& rOStm, const MapMode& rMapMode )
181 rOStm.WriteInt16( (sal_uInt16)rMapMode.GetMapUnit() );
182 WritePair( rOStm, rMapMode.GetOrigin() );
183 rOStm.WriteInt32( rMapMode.GetScaleX().GetNumerator() );
184 rOStm.WriteInt32( rMapMode.GetScaleX().GetDenominator() );
185 rOStm.WriteInt32( rMapMode.GetScaleY().GetNumerator() );
186 rOStm.WriteInt32( rMapMode.GetScaleY().GetDenominator() );
189 void ImplWritePushAction( SvStream& rOStm )
191 rOStm.WriteInt16( GDI_PUSH_ACTION );
192 rOStm.WriteInt32( 4 );
195 void ImplWritePopAction( SvStream& rOStm )
197 rOStm.WriteInt16( GDI_POP_ACTION );
198 rOStm.WriteInt32( 4 );
201 void ImplWriteLineColor( SvStream& rOStm, const Color& rColor, sal_Int16 nStyle, sal_Int32 nWidth = 0 )
203 if( rColor.GetTransparency() > 127 )
204 nStyle = 0;
206 rOStm.WriteInt16( GDI_PEN_ACTION );
207 rOStm.WriteInt32( 16 );
208 ImplWriteColor( rOStm, rColor );
209 rOStm.WriteInt32( nWidth );
210 rOStm.WriteInt16( nStyle );
213 void ImplWriteFillColor( SvStream& rOStm, const Color& rColor, sal_Int16 nStyle )
215 rOStm.WriteInt16( GDI_FILLBRUSH_ACTION );
216 rOStm.WriteInt32( 20 );
217 ImplWriteColor( rOStm, rColor );
219 if( rColor.GetTransparency() > 127 )
220 nStyle = 0;
222 if( nStyle > 1 )
224 ImplWriteColor( rOStm, COL_WHITE );
225 rOStm.WriteInt16( nStyle );
226 rOStm.WriteInt16( 1 );
228 else
230 ImplWriteColor( rOStm, COL_BLACK );
231 rOStm.WriteInt16( nStyle );
232 rOStm.WriteInt16( 0 );
236 void ImplWriteFont( SvStream& rOStm, const vcl::Font& rFont,
237 rtl_TextEncoding& rActualCharSet )
239 char aName[33];
240 short nWeight;
242 OString aByteName(OUStringToOString(rFont.GetFamilyName(),
243 rOStm.GetStreamCharSet()));
244 strncpy( aName, aByteName.getStr(), 32 );
245 aName[32] = 0;
247 switch ( rFont.GetWeight() )
249 case WEIGHT_THIN:
250 case WEIGHT_ULTRALIGHT:
251 case WEIGHT_LIGHT:
252 nWeight = 1;
253 break;
255 case WEIGHT_NORMAL:
256 case WEIGHT_MEDIUM:
257 nWeight = 2;
258 break;
260 case WEIGHT_BOLD:
261 case WEIGHT_ULTRABOLD:
262 case WEIGHT_BLACK:
263 nWeight = 3;
264 break;
266 default:
267 nWeight = 0;
268 break;
271 rOStm.WriteInt16( GDI_FONT_ACTION );
272 rOStm.WriteInt32( 78 );
274 rActualCharSet = GetStoreCharSet( rFont.GetCharSet() );
275 ImplWriteColor( rOStm, rFont.GetColor() );
276 ImplWriteColor( rOStm, rFont.GetFillColor() );
277 rOStm.WriteBytes( aName, 32 );
278 WritePair( rOStm, rFont.GetFontSize() );
279 rOStm.WriteInt16( 0 ); // no character orientation anymore
280 rOStm.WriteInt16( rFont.GetOrientation() );
281 rOStm.WriteInt16( rActualCharSet );
282 rOStm.WriteInt16( rFont.GetFamilyType() );
283 rOStm.WriteInt16( rFont.GetPitch() );
284 rOStm.WriteInt16( rFont.GetAlignment() );
285 rOStm.WriteInt16( nWeight );
286 rOStm.WriteInt16( rFont.GetUnderline() );
287 rOStm.WriteInt16( rFont.GetStrikeout() );
288 rOStm.WriteBool( rFont.GetItalic() != ITALIC_NONE );
289 rOStm.WriteBool( rFont.IsOutline() );
290 rOStm.WriteBool( rFont.IsShadow() );
291 rOStm.WriteBool( rFont.IsTransparent() );
292 if ( rActualCharSet == RTL_TEXTENCODING_DONTKNOW )
293 rActualCharSet = osl_getThreadTextEncoding();
296 void ImplWriteRasterOpAction( SvStream& rOStm, sal_Int16 nRasterOp )
298 rOStm.WriteInt16( GDI_RASTEROP_ACTION ).WriteInt32( 6 ).WriteInt16( nRasterOp );
301 bool ImplWriteUnicodeComment( SvStream& rOStm, const OUString& rString )
303 sal_Int32 nStringLen = rString.getLength();
304 if ( nStringLen )
306 sal_uInt32 nSize = ( nStringLen << 1 ) + 4;
307 sal_uInt16 nType = GDI_UNICODE_COMMENT;
309 rOStm.WriteUInt16( nType ).WriteUInt32( nSize );
310 write_uInt16s_FromOUString(rOStm, rString);
312 return nStringLen != 0;
315 void ImplReadUnicodeComment( sal_uInt32 nStrmPos, SvStream& rIStm, OUString& rString )
317 sal_uInt32 nOld = rIStm.Tell();
318 if ( nStrmPos )
320 sal_uInt16 nType;
321 sal_uInt32 nActionSize;
322 std::size_t nStringLen;
324 rIStm.Seek( nStrmPos );
325 rIStm .ReadUInt16( nType )
326 .ReadUInt32( nActionSize );
328 nStringLen = (nActionSize - 4) >> 1;
330 if ( nStringLen && ( nType == GDI_UNICODE_COMMENT ) )
331 rString = read_uInt16s_ToOUString(rIStm, nStringLen);
333 rIStm.Seek( nOld );
336 void ImplSkipActions(SvStream& rIStm, sal_uLong nSkipCount)
338 sal_Int32 nActionSize;
339 sal_Int16 nType;
340 for (sal_uLong i = 0UL; i < nSkipCount; ++i)
342 rIStm.ReadInt16(nType).ReadInt32(nActionSize);
343 if (!rIStm.good() || nActionSize < 4)
344 break;
345 rIStm.SeekRel(nActionSize - 4);
349 bool ImplWriteExtendedPolyPolygonAction(SvStream& rOStm, const tools::PolyPolygon& rPolyPolygon, bool bOnlyWhenCurve)
351 const sal_uInt16 nPolygonCount(rPolyPolygon.Count());
353 if(nPolygonCount)
355 sal_uInt32 nAllPolygonCount(0);
356 sal_uInt32 nAllPointCount(0);
357 sal_uInt32 nAllFlagCount(0);
358 sal_uInt16 a(0);
360 for(a = 0; a < nPolygonCount; a++)
362 const tools::Polygon& rCandidate = rPolyPolygon.GetObject(a);
363 const sal_uInt16 nPointCount(rCandidate.GetSize());
365 if(nPointCount)
367 nAllPolygonCount++;
368 nAllPointCount += nPointCount;
370 if(rCandidate.HasFlags())
372 nAllFlagCount += nPointCount;
377 if((bOnlyWhenCurve && nAllFlagCount) || (!bOnlyWhenCurve && nAllPointCount))
379 rOStm.WriteInt16( GDI_EXTENDEDPOLYGON_ACTION );
381 const sal_Int32 nActionSize(
382 4 + // Action size
383 2 + // PolygonCount
384 (nAllPolygonCount * 2) + // Points per polygon
385 (nAllPointCount << 3) + // Points themselves
386 nAllPolygonCount + // Bool if (when poly has points) it has flags, too
387 nAllFlagCount); // Flags themselves
389 rOStm.WriteInt32( nActionSize );
390 rOStm.WriteUInt16( nAllPolygonCount );
392 for(a = 0; a < nPolygonCount; a++)
394 const tools::Polygon& rCandidate = rPolyPolygon.GetObject(a);
395 const sal_uInt16 nPointCount(rCandidate.GetSize());
397 if(nPointCount)
399 rOStm.WriteUInt16( nPointCount );
401 for(sal_uInt16 b(0); b < nPointCount; b++)
403 WritePair( rOStm, rCandidate[b] );
406 if(rCandidate.HasFlags())
408 rOStm.WriteBool( true );
410 for(sal_uInt16 c(0); c < nPointCount; c++)
412 rOStm.WriteUChar( (sal_uInt8)rCandidate.GetFlags(c) );
415 else
417 rOStm.WriteBool( false );
422 return true;
426 return false;
429 void ImplReadExtendedPolyPolygonAction(SvStream& rIStm, tools::PolyPolygon& rPolyPoly)
431 rPolyPoly.Clear();
432 sal_uInt16 nPolygonCount(0);
433 rIStm.ReadUInt16( nPolygonCount );
435 if (!nPolygonCount)
436 return;
438 const size_t nMinRecordSize = sizeof(sal_uInt16);
439 const size_t nMaxRecords = rIStm.remainingSize() / nMinRecordSize;
440 if (nPolygonCount > nMaxRecords)
442 SAL_WARN("vcl.gdi", "Parsing error: " << nMaxRecords <<
443 " max possible entries, but " << nPolygonCount << " claimed, truncating");
444 nPolygonCount = nMaxRecords;
447 for(sal_uInt16 a(0); a < nPolygonCount; a++)
449 sal_uInt16 nPointCount(0);
450 rIStm.ReadUInt16(nPointCount);
452 const size_t nMinPolygonSize = sizeof(sal_Int32) * 2;
453 const size_t nMaxPolygons = rIStm.remainingSize() / nMinPolygonSize;
454 if (nPointCount > nMaxPolygons)
456 SAL_WARN("vcl.gdi", "Parsing error: " << nMaxPolygons <<
457 " max possible entries, but " << nPointCount << " claimed, truncating");
458 nPointCount = nMaxPolygons;
461 tools::Polygon aCandidate(nPointCount);
463 if (nPointCount)
465 for(sal_uInt16 b(0); b < nPointCount; b++)
467 ReadPair( rIStm , aCandidate[b] );
470 sal_uInt8 bHasFlags(int(false));
471 rIStm.ReadUChar( bHasFlags );
473 if(bHasFlags)
475 sal_uInt8 aPolyFlags(0);
477 for(sal_uInt16 c(0); c < nPointCount; c++)
479 rIStm.ReadUChar( aPolyFlags );
480 aCandidate.SetFlags(c, (PolyFlags)aPolyFlags);
485 rPolyPoly.Insert(aCandidate);
489 SVMConverter::SVMConverter( SvStream& rStm, GDIMetaFile& rMtf, sal_uLong nConvertMode )
491 if( !rStm.GetError() )
493 if( CONVERT_FROM_SVM1 == nConvertMode )
494 ImplConvertFromSVM1( rStm, rMtf );
495 else if( CONVERT_TO_SVM1 == nConvertMode )
496 ImplConvertToSVM1( rStm, rMtf );
500 namespace
502 sal_Int32 SkipActions(sal_Int32 i, sal_Int32 nFollowingActionCount, sal_Int32 nActions)
504 sal_Int32 remainingActions = nActions - i;
505 if (nFollowingActionCount < 0)
506 nFollowingActionCount = remainingActions;
507 return std::min(remainingActions, nFollowingActionCount);
511 #define LF_FACESIZE 32
513 void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf )
515 const sal_uLong nPos = rIStm.Tell();
516 const SvStreamEndian nOldFormat = rIStm.GetEndian();
518 rIStm.SetEndian( SvStreamEndian::LITTLE );
520 char aCode[ 5 ];
521 Size aPrefSz;
523 // read header
524 rIStm.ReadBytes(aCode, sizeof(aCode)); // Identifier
525 sal_Int16 nSize(0);
526 rIStm.ReadInt16( nSize ); // Size
527 sal_Int16 nVersion(0);
528 rIStm.ReadInt16( nVersion ); // Version
529 sal_Int32 nTmp32(0);
530 rIStm.ReadInt32( nTmp32 );
531 aPrefSz.Width() = nTmp32; // PrefSize.Width()
532 rIStm.ReadInt32( nTmp32 );
533 aPrefSz.Height() = nTmp32; // PrefSize.Height()
535 // check header-magic and version
536 if( rIStm.GetError()
537 || ( memcmp( aCode, "SVGDI", sizeof( aCode ) ) != 0 )
538 || ( nVersion != 200 ) )
540 rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
541 rIStm.SetEndian( nOldFormat );
542 rIStm.Seek( nPos );
543 return;
546 LineInfo aLineInfo( LineStyle::NONE, 0 );
547 std::stack<std::unique_ptr<LineInfo>> aLIStack;
548 ScopedVclPtrInstance< VirtualDevice > aFontVDev;
549 rtl_TextEncoding eActualCharSet = osl_getThreadTextEncoding();
550 bool bFatLine = false;
552 tools::Polygon aActionPoly;
553 tools::Rectangle aRect;
554 Point aPt, aPt1;
555 Size aSz;
556 Color aActionColor;
558 sal_uInt32 nUnicodeCommentStreamPos = 0;
559 sal_Int32 nUnicodeCommentActionNumber = 0;
561 rMtf.SetPrefSize(aPrefSz);
563 MapMode aMapMode;
564 if (ImplReadMapMode(rIStm, aMapMode)) // MapMode
565 rMtf.SetPrefMapMode(aMapMode);
567 sal_Int32 nActions(0);
568 rIStm.ReadInt32(nActions); // Action count
569 if (nActions < 0)
571 SAL_WARN("vcl.gdi", "svm claims negative action count (" << nActions << ")");
572 nActions = 0;
575 const size_t nMinActionSize = sizeof(sal_uInt16) + sizeof(sal_Int32);
576 const size_t nMaxPossibleActions = rIStm.remainingSize() / nMinActionSize;
577 if (static_cast<sal_uInt32>(nActions) > nMaxPossibleActions)
579 SAL_WARN("vcl.gdi", "svm claims more actions (" << nActions << ") than stream could provide, truncating");
580 nActions = nMaxPossibleActions;
583 size_t nLastPolygonAction(0);
585 for (sal_Int32 i = 0; i < nActions && rIStm.good(); ++i)
587 sal_Int16 nType(0);
588 rIStm.ReadInt16(nType);
589 sal_Int32 nActBegin = rIStm.Tell();
590 sal_Int32 nActionSize(0);
591 rIStm.ReadInt32(nActionSize);
593 SAL_WARN_IF( ( nType > 33 ) && ( nType < 1024 ), "vcl.gdi", "Unknown GDIMetaAction while converting!" );
595 switch( nType )
597 case GDI_PIXEL_ACTION:
599 ReadPair( rIStm, aPt );
600 ImplReadColor( rIStm, aActionColor );
601 rMtf.AddAction( new MetaPixelAction( aPt, aActionColor ) );
603 break;
605 case GDI_POINT_ACTION:
607 ReadPair( rIStm, aPt );
608 rMtf.AddAction( new MetaPointAction( aPt ) );
610 break;
612 case GDI_LINE_ACTION:
614 ReadPair( rIStm, aPt );
615 ReadPair( rIStm, aPt1 );
616 rMtf.AddAction( new MetaLineAction( aPt, aPt1, aLineInfo ) );
618 break;
620 case GDI_LINEJOIN_ACTION :
622 sal_Int16 nLineJoin(0);
623 rIStm.ReadInt16( nLineJoin );
624 aLineInfo.SetLineJoin((basegfx::B2DLineJoin)nLineJoin);
626 break;
628 case GDI_LINECAP_ACTION :
630 sal_Int16 nLineCap(0);
631 rIStm.ReadInt16( nLineCap );
632 aLineInfo.SetLineCap((css::drawing::LineCap)nLineCap);
634 break;
636 case GDI_LINEDASHDOT_ACTION :
638 sal_Int16 a(0);
639 sal_Int32 b(0);
641 rIStm.ReadInt16( a ); aLineInfo.SetDashCount(a);
642 rIStm.ReadInt32( b ); aLineInfo.SetDashLen(b);
643 rIStm.ReadInt16( a ); aLineInfo.SetDotCount(a);
644 rIStm.ReadInt32( b ); aLineInfo.SetDotLen(b);
645 rIStm.ReadInt32( b ); aLineInfo.SetDistance(b);
647 if(((aLineInfo.GetDashCount() && aLineInfo.GetDashLen())
648 || (aLineInfo.GetDotCount() && aLineInfo.GetDotLen()))
649 && aLineInfo.GetDistance())
651 aLineInfo.SetStyle(LineStyle::Dash);
654 break;
656 case GDI_EXTENDEDPOLYGON_ACTION :
658 // read the tools::PolyPolygon in every case
659 tools::PolyPolygon aInputPolyPolygon;
660 ImplReadExtendedPolyPolygonAction(rIStm, aInputPolyPolygon);
662 // now check if it can be set somewhere
663 if(nLastPolygonAction < rMtf.GetActionSize())
665 MetaPolyLineAction* pPolyLineAction = dynamic_cast< MetaPolyLineAction* >(rMtf.GetAction(nLastPolygonAction));
667 if(pPolyLineAction)
669 // replace MetaPolyLineAction when we have a single polygon. Do not rely on the
670 // same point count; the originally written GDI_POLYLINE_ACTION may have been
671 // Subdivided for better quality for older usages
672 if(1 == aInputPolyPolygon.Count())
674 MetaAction* pAction = rMtf.ReplaceAction(
675 new MetaPolyLineAction(
676 aInputPolyPolygon.GetObject(0),
677 pPolyLineAction->GetLineInfo()),
678 nLastPolygonAction);
679 if(pAction)
680 pAction->Delete();
683 else
685 MetaPolyPolygonAction* pPolyPolygonAction = dynamic_cast< MetaPolyPolygonAction* >(rMtf.GetAction(nLastPolygonAction));
687 if(pPolyPolygonAction)
689 // replace MetaPolyPolygonAction when we have a curved polygon. Do rely on the
690 // same sub-polygon count
691 if(pPolyPolygonAction->GetPolyPolygon().Count() == aInputPolyPolygon.Count())
693 MetaAction* pAction = rMtf.ReplaceAction(
694 new MetaPolyPolygonAction(
695 aInputPolyPolygon),
696 nLastPolygonAction);
697 if(pAction)
698 pAction->Delete();
701 else
703 MetaPolygonAction* pPolygonAction = dynamic_cast< MetaPolygonAction* >(rMtf.GetAction(nLastPolygonAction));
705 if(pPolygonAction)
707 // replace MetaPolygonAction
708 if(1 == aInputPolyPolygon.Count())
710 MetaAction* pAction = rMtf.ReplaceAction(
711 new MetaPolygonAction(
712 aInputPolyPolygon.GetObject(0)),
713 nLastPolygonAction);
714 if(pAction)
715 pAction->Delete();
722 break;
724 case GDI_RECT_ACTION:
726 ImplReadRect( rIStm, aRect );
727 sal_Int32 nTmp(0), nTmp1(0);
728 rIStm.ReadInt32( nTmp ).ReadInt32( nTmp1 );
730 if( nTmp || nTmp1 )
731 rMtf.AddAction( new MetaRoundRectAction( aRect, nTmp, nTmp1 ) );
732 else
734 rMtf.AddAction( new MetaRectAction( aRect ) );
736 if( bFatLine )
737 rMtf.AddAction( new MetaPolyLineAction( aRect, aLineInfo ) );
740 break;
742 case GDI_ELLIPSE_ACTION:
744 ImplReadRect( rIStm, aRect );
746 if( bFatLine )
748 const tools::Polygon aPoly( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 );
750 rMtf.AddAction( new MetaPushAction( PushFlags::LINECOLOR ) );
751 rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) );
752 rMtf.AddAction( new MetaPolygonAction( aPoly ) );
753 rMtf.AddAction( new MetaPopAction() );
754 rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) );
756 else
757 rMtf.AddAction( new MetaEllipseAction( aRect ) );
759 break;
761 case GDI_ARC_ACTION:
763 ImplReadRect( rIStm, aRect );
764 ReadPair( rIStm, aPt );
765 ReadPair( rIStm, aPt1 );
767 if( bFatLine )
769 const tools::Polygon aPoly( aRect, aPt, aPt1, PolyStyle::Arc );
771 rMtf.AddAction( new MetaPushAction( PushFlags::LINECOLOR ) );
772 rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) );
773 rMtf.AddAction( new MetaPolygonAction( aPoly ) );
774 rMtf.AddAction( new MetaPopAction() );
775 rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) );
777 else
778 rMtf.AddAction( new MetaArcAction( aRect, aPt, aPt1 ) );
780 break;
782 case GDI_PIE_ACTION:
784 ImplReadRect( rIStm, aRect );
785 ReadPair( rIStm, aPt );
786 ReadPair( rIStm, aPt1 );
788 if( bFatLine )
790 const tools::Polygon aPoly( aRect, aPt, aPt1, PolyStyle::Pie );
792 rMtf.AddAction( new MetaPushAction( PushFlags::LINECOLOR ) );
793 rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) );
794 rMtf.AddAction( new MetaPolygonAction( aPoly ) );
795 rMtf.AddAction( new MetaPopAction() );
796 rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) );
798 else
799 rMtf.AddAction( new MetaPieAction( aRect, aPt, aPt1 ) );
801 break;
803 case GDI_INVERTRECT_ACTION:
804 case GDI_HIGHLIGHTRECT_ACTION:
806 ImplReadRect( rIStm, aRect );
807 rMtf.AddAction( new MetaPushAction( PushFlags::RASTEROP ) );
808 rMtf.AddAction( new MetaRasterOpAction( RasterOp::Invert ) );
809 rMtf.AddAction( new MetaRectAction( aRect ) );
810 rMtf.AddAction( new MetaPopAction() );
812 break;
814 case GDI_POLYLINE_ACTION:
816 if (ImplReadPoly(rIStm, aActionPoly))
818 nLastPolygonAction = rMtf.GetActionSize();
820 if( bFatLine )
821 rMtf.AddAction( new MetaPolyLineAction( aActionPoly, aLineInfo ) );
822 else
823 rMtf.AddAction( new MetaPolyLineAction( aActionPoly ) );
826 break;
828 case GDI_POLYGON_ACTION:
830 if (ImplReadPoly(rIStm, aActionPoly))
832 if( bFatLine )
834 rMtf.AddAction( new MetaPushAction( PushFlags::LINECOLOR ) );
835 rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) );
836 rMtf.AddAction( new MetaPolygonAction( aActionPoly ) );
837 rMtf.AddAction( new MetaPopAction() );
838 rMtf.AddAction( new MetaPolyLineAction( aActionPoly, aLineInfo ) );
840 else
842 nLastPolygonAction = rMtf.GetActionSize();
843 rMtf.AddAction( new MetaPolygonAction( aActionPoly ) );
847 break;
849 case GDI_POLYPOLYGON_ACTION:
851 tools::PolyPolygon aPolyPoly;
853 if (ImplReadPolyPoly(rIStm, aPolyPoly))
855 if( bFatLine )
857 rMtf.AddAction( new MetaPushAction( PushFlags::LINECOLOR ) );
858 rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) );
859 rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) );
860 rMtf.AddAction( new MetaPopAction() );
862 for( sal_uInt16 nPoly = 0, nCount = aPolyPoly.Count(); nPoly < nCount; nPoly++ )
863 rMtf.AddAction( new MetaPolyLineAction( aPolyPoly[ nPoly ], aLineInfo ) );
865 else
867 nLastPolygonAction = rMtf.GetActionSize();
868 rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) );
872 break;
874 case GDI_FONT_ACTION:
876 vcl::Font aFont;
877 char aName[LF_FACESIZE+1];
879 ImplReadColor( rIStm, aActionColor ); aFont.SetColor( aActionColor );
880 ImplReadColor( rIStm, aActionColor ); aFont.SetFillColor( aActionColor );
881 size_t nRet = rIStm.ReadBytes(aName, LF_FACESIZE);
882 aName[nRet] = 0;
883 aFont.SetFamilyName( OUString( aName, strlen(aName), rIStm.GetStreamCharSet() ) );
885 sal_Int32 nWidth(0), nHeight(0);
886 rIStm.ReadInt32(nWidth).ReadInt32(nHeight);
887 sal_Int16 nCharOrient(0), nLineOrient(0);
888 rIStm.ReadInt16(nCharOrient).ReadInt16(nLineOrient);
889 sal_Int16 nCharSet(0), nFamily(0), nPitch(0), nAlign(0), nWeight(0), nUnderline(0), nStrikeout(0);
890 rIStm.ReadInt16(nCharSet).ReadInt16(nFamily).ReadInt16(nPitch).ReadInt16(nAlign).ReadInt16(nWeight).ReadInt16(nUnderline).ReadInt16(nStrikeout);
891 bool bItalic(false), bOutline(false), bShadow(false), bTransparent(false);
892 rIStm.ReadCharAsBool(bItalic).ReadCharAsBool(bOutline).ReadCharAsBool(bShadow).ReadCharAsBool(bTransparent);
894 aFont.SetFontSize( Size( nWidth, nHeight ) );
895 aFont.SetCharSet( (rtl_TextEncoding) nCharSet );
896 aFont.SetFamily( (FontFamily) nFamily );
897 aFont.SetPitch( (FontPitch) nPitch );
898 aFont.SetAlignment( (FontAlign) nAlign );
899 aFont.SetWeight( ( nWeight == 1 ) ? WEIGHT_LIGHT : ( nWeight == 2 ) ? WEIGHT_NORMAL :
900 ( nWeight == 3 ) ? WEIGHT_BOLD : WEIGHT_DONTKNOW );
901 aFont.SetUnderline( (FontLineStyle) nUnderline );
902 aFont.SetStrikeout( (FontStrikeout) nStrikeout );
903 aFont.SetItalic( bItalic ? ITALIC_NORMAL : ITALIC_NONE );
904 aFont.SetOutline( bOutline );
905 aFont.SetShadow( bShadow );
906 aFont.SetOrientation( nLineOrient );
907 aFont.SetTransparent( bTransparent );
909 eActualCharSet = aFont.GetCharSet();
910 if ( eActualCharSet == RTL_TEXTENCODING_DONTKNOW )
911 eActualCharSet = osl_getThreadTextEncoding();
913 rMtf.AddAction( new MetaFontAction( aFont ) );
914 rMtf.AddAction( new MetaTextAlignAction( aFont.GetAlignment() ) );
915 rMtf.AddAction( new MetaTextColorAction( aFont.GetColor() ) );
916 rMtf.AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) );
918 // #106172# Track font relevant data in shadow VDev
919 aFontVDev->SetFont( aFont );
921 break;
923 case GDI_TEXT_ACTION:
925 sal_Int32 nIndex(0), nLen(0), nTmp(0);
927 ReadPair( rIStm, aPt ).ReadInt32( nIndex ).ReadInt32( nLen ).ReadInt32( nTmp );
928 if (nTmp > 0)
930 OString aByteStr = read_uInt8s_ToOString(rIStm, nTmp);
931 sal_uInt8 nTerminator = 0;
932 rIStm.ReadUChar( nTerminator );
933 SAL_WARN_IF( nTerminator != 0, "vcl.gdi", "expected string to be NULL terminated" );
935 OUString aStr(OStringToOUString(aByteStr, eActualCharSet));
936 if ( nUnicodeCommentActionNumber == i )
937 ImplReadUnicodeComment( nUnicodeCommentStreamPos, rIStm, aStr );
938 rMtf.AddAction( new MetaTextAction( aPt, aStr, nIndex, nLen ) );
941 if (nActionSize < 24)
942 rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
943 else
944 rIStm.Seek(nActBegin + nActionSize);
946 break;
948 case GDI_TEXTARRAY_ACTION:
950 sal_Int32 nIndex(0), nLen(0), nAryLen(0), nTmp(0);
952 ReadPair( rIStm, aPt ).ReadInt32( nIndex ).ReadInt32( nLen ).ReadInt32( nTmp ).ReadInt32( nAryLen );
953 if (nTmp > 0)
955 OString aByteStr = read_uInt8s_ToOString(rIStm, nTmp);
956 sal_uInt8 nTerminator = 0;
957 rIStm.ReadUChar( nTerminator );
958 SAL_WARN_IF( nTerminator != 0, "vcl.gdi", "expected string to be NULL terminated" );
960 OUString aStr(OStringToOUString(aByteStr, eActualCharSet));
962 std::unique_ptr<long[]> pDXAry;
963 sal_Int32 nDXAryLen = 0;
964 if (nAryLen > 0)
966 const size_t nMinRecordSize = sizeof(sal_Int32);
967 const size_t nMaxRecords = rIStm.remainingSize() / nMinRecordSize;
968 if (static_cast<sal_uInt32>(nAryLen) > nMaxRecords)
970 SAL_WARN("vcl.gdi", "Parsing error: " << nMaxRecords <<
971 " max possible entries, but " << nAryLen << " claimed, truncating");
972 nAryLen = nMaxRecords;
975 sal_Int32 nStrLen( aStr.getLength() );
977 nDXAryLen = std::max(nAryLen, nStrLen);
979 if (nDXAryLen < nLen)
981 //MetaTextArrayAction ctor expects pDXAry to be >= nLen if set, so if this can't
982 //be achieved, don't read it, it's utterly broken.
983 SAL_WARN("vcl.gdi", "dxary too short, discarding completely");
984 rIStm.SeekRel(sizeof(sal_Int32) * nDXAryLen);
985 nLen = 0;
986 nIndex = 0;
988 else
990 pDXAry.reset(new long[nDXAryLen]);
992 for (sal_Int32 j = 0; j < nAryLen; ++j)
993 rIStm.ReadInt32( nTmp ), pDXAry[ j ] = nTmp;
995 // #106172# Add last DX array elem, if missing
996 if( nAryLen != nStrLen )
998 if (nAryLen+1 == nStrLen && nIndex >= 0)
1000 std::unique_ptr<long[]> pTmpAry(new long[nStrLen]);
1002 aFontVDev->GetTextArray( aStr, pTmpAry.get(), nIndex, nLen );
1004 // now, the difference between the
1005 // last and the second last DX array
1006 // is the advancement for the last
1007 // glyph. Thus, to complete our meta
1008 // action's DX array, just add that
1009 // difference to last elem and store
1010 // in very last.
1011 if( nStrLen > 1 )
1012 pDXAry[ nStrLen-1 ] = pDXAry[ nStrLen-2 ] + pTmpAry[ nStrLen-1 ] - pTmpAry[ nStrLen-2 ];
1013 else
1014 pDXAry[ nStrLen-1 ] = pTmpAry[ nStrLen-1 ]; // len=1: 0th position taken to be 0
1016 #ifdef DBG_UTIL
1017 else
1018 OSL_FAIL("More than one DX array element missing on SVM import");
1019 #endif
1023 if ( nUnicodeCommentActionNumber == i )
1024 ImplReadUnicodeComment( nUnicodeCommentStreamPos, rIStm, aStr );
1025 rMtf.AddAction( new MetaTextArrayAction( aPt, aStr, pDXAry.get(), nIndex, nLen ) );
1028 if (nActionSize < 24)
1029 rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
1030 else
1031 rIStm.Seek(nActBegin + nActionSize);
1033 break;
1035 case GDI_STRETCHTEXT_ACTION:
1037 sal_Int32 nIndex(0), nLen(0), nWidth(0), nTmp(0);
1039 ReadPair( rIStm, aPt ).ReadInt32( nIndex ).ReadInt32( nLen ).ReadInt32( nTmp ).ReadInt32( nWidth );
1040 if (nTmp > 0)
1042 OString aByteStr = read_uInt8s_ToOString(rIStm, nTmp);
1043 sal_uInt8 nTerminator = 0;
1044 rIStm.ReadUChar( nTerminator );
1045 SAL_WARN_IF( nTerminator != 0, "vcl.gdi", "expected string to be NULL terminated" );
1047 OUString aStr(OStringToOUString(aByteStr, eActualCharSet));
1048 if ( nUnicodeCommentActionNumber == i )
1049 ImplReadUnicodeComment( nUnicodeCommentStreamPos, rIStm, aStr );
1050 rMtf.AddAction( new MetaStretchTextAction( aPt, nWidth, aStr, nIndex, nLen ) );
1053 if (nActionSize < 28)
1054 rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
1055 else
1056 rIStm.Seek(nActBegin + nActionSize);
1058 break;
1060 case GDI_BITMAP_ACTION:
1062 Bitmap aBmp;
1064 ReadPair( rIStm, aPt );
1065 ReadDIB(aBmp, rIStm, true);
1066 rMtf.AddAction( new MetaBmpAction( aPt, aBmp ) );
1068 break;
1070 case GDI_BITMAPSCALE_ACTION:
1072 Bitmap aBmp;
1074 ReadPair( rIStm, aPt );
1075 ReadPair( rIStm, aSz );
1076 ReadDIB(aBmp, rIStm, true);
1077 rMtf.AddAction( new MetaBmpScaleAction( aPt, aSz, aBmp ) );
1079 break;
1081 case GDI_BITMAPSCALEPART_ACTION:
1083 Bitmap aBmp;
1084 Size aSz2;
1086 ReadPair( rIStm, aPt );
1087 ReadPair( rIStm, aSz );
1088 ReadPair( rIStm, aPt1 );
1089 ReadPair( rIStm, aSz2 );
1090 ReadDIB(aBmp, rIStm, true);
1091 rMtf.AddAction( new MetaBmpScalePartAction( aPt, aSz, aPt1, aSz2, aBmp ) );
1093 break;
1095 case GDI_PEN_ACTION:
1097 sal_Int32 nPenWidth;
1098 sal_Int16 nPenStyle;
1100 ImplReadColor( rIStm, aActionColor );
1101 rIStm.ReadInt32( nPenWidth ).ReadInt16( nPenStyle );
1103 aLineInfo.SetStyle( nPenStyle ? LineStyle::Solid : LineStyle::NONE );
1104 aLineInfo.SetWidth( nPenWidth );
1105 bFatLine = nPenStyle && !aLineInfo.IsDefault();
1107 rMtf.AddAction( new MetaLineColorAction( aActionColor, nPenStyle != 0 ) );
1109 break;
1111 case GDI_FILLBRUSH_ACTION:
1113 sal_Int16 nBrushStyle;
1115 ImplReadColor( rIStm, aActionColor );
1116 rIStm.SeekRel( 6 );
1117 rIStm.ReadInt16( nBrushStyle );
1118 rMtf.AddAction( new MetaFillColorAction( aActionColor, nBrushStyle != 0 ) );
1119 rIStm.SeekRel( 2 );
1121 break;
1123 case GDI_MAPMODE_ACTION:
1125 if (ImplReadMapMode(rIStm, aMapMode))
1127 rMtf.AddAction(new MetaMapModeAction(aMapMode));
1129 // #106172# Track font relevant data in shadow VDev
1130 aFontVDev->SetMapMode(aMapMode);
1133 break;
1135 case GDI_CLIPREGION_ACTION:
1137 vcl::Region aRegion;
1138 sal_Int16 nRegType;
1139 sal_Int16 bIntersect;
1140 bool bClip = false;
1142 rIStm.ReadInt16( nRegType ).ReadInt16( bIntersect );
1143 ImplReadRect( rIStm, aRect );
1145 switch( nRegType )
1147 case 0:
1148 break;
1150 case 1:
1152 tools::Rectangle aRegRect;
1154 ImplReadRect( rIStm, aRegRect );
1155 aRegion = vcl::Region( aRegRect );
1156 bClip = true;
1158 break;
1160 case 2:
1162 if (ImplReadPoly(rIStm, aActionPoly))
1164 aRegion = vcl::Region( aActionPoly );
1165 bClip = true;
1168 break;
1170 case 3:
1172 bool bSuccess = true;
1173 tools::PolyPolygon aPolyPoly;
1174 sal_Int32 nPolyCount32(0);
1175 rIStm.ReadInt32(nPolyCount32);
1176 sal_uInt16 nPolyCount(nPolyCount32);
1178 for (sal_uInt16 j = 0; j < nPolyCount && rIStm.good(); ++j)
1180 if (!ImplReadPoly(rIStm, aActionPoly))
1182 bSuccess = false;
1183 break;
1185 aPolyPoly.Insert(aActionPoly);
1188 if (bSuccess)
1190 aRegion = vcl::Region( aPolyPoly );
1191 bClip = true;
1194 break;
1197 if( bIntersect )
1198 aRegion.Intersect( aRect );
1200 rMtf.AddAction( new MetaClipRegionAction( aRegion, bClip ) );
1202 break;
1204 case GDI_MOVECLIPREGION_ACTION:
1206 sal_Int32 nTmp(0), nTmp1(0);
1207 rIStm.ReadInt32( nTmp ).ReadInt32( nTmp1 );
1208 rMtf.AddAction( new MetaMoveClipRegionAction( nTmp, nTmp1 ) );
1210 break;
1212 case GDI_ISECTCLIPREGION_ACTION:
1214 ImplReadRect( rIStm, aRect );
1215 rMtf.AddAction( new MetaISectRectClipRegionAction( aRect ) );
1217 break;
1219 case GDI_RASTEROP_ACTION:
1221 RasterOp eRasterOp;
1222 sal_Int16 nRasterOp;
1224 rIStm.ReadInt16( nRasterOp );
1226 switch( nRasterOp )
1228 case 1:
1229 eRasterOp = RasterOp::Invert;
1230 break;
1232 case 4:
1233 case 5:
1234 eRasterOp = RasterOp::Xor;
1235 break;
1237 default:
1238 eRasterOp = RasterOp::OverPaint;
1239 break;
1242 rMtf.AddAction( new MetaRasterOpAction( eRasterOp ) );
1244 break;
1246 case GDI_PUSH_ACTION:
1248 aLIStack.push(o3tl::make_unique<LineInfo>(aLineInfo));
1249 rMtf.AddAction( new MetaPushAction( PushFlags::ALL ) );
1251 // #106172# Track font relevant data in shadow VDev
1252 aFontVDev->Push();
1254 break;
1256 case GDI_POP_ACTION:
1259 std::unique_ptr<LineInfo> xLineInfo;
1260 if (!aLIStack.empty())
1262 xLineInfo = std::move(aLIStack.top());
1263 aLIStack.pop();
1266 // restore line info
1267 if (xLineInfo)
1269 aLineInfo = *xLineInfo;
1270 xLineInfo.reset();
1271 bFatLine = ( LineStyle::NONE != aLineInfo.GetStyle() ) && !aLineInfo.IsDefault();
1274 rMtf.AddAction( new MetaPopAction() );
1276 // #106172# Track font relevant data in shadow VDev
1277 aFontVDev->Pop();
1279 break;
1281 case GDI_GRADIENT_ACTION:
1283 Color aStartCol;
1284 Color aEndCol;
1285 sal_Int16 nStyle;
1286 sal_Int16 nAngle;
1287 sal_Int16 nBorder;
1288 sal_Int16 nOfsX;
1289 sal_Int16 nOfsY;
1290 sal_Int16 nIntensityStart;
1291 sal_Int16 nIntensityEnd;
1293 ImplReadRect( rIStm, aRect );
1294 rIStm.ReadInt16( nStyle );
1295 ImplReadColor( rIStm, aStartCol );
1296 ImplReadColor( rIStm, aEndCol );
1297 rIStm.ReadInt16( nAngle ).ReadInt16( nBorder ).ReadInt16( nOfsX ).ReadInt16( nOfsY ).ReadInt16( nIntensityStart ).ReadInt16( nIntensityEnd );
1299 Gradient aGrad( (GradientStyle) nStyle, aStartCol, aEndCol );
1301 aGrad.SetAngle( nAngle );
1302 aGrad.SetBorder( nBorder );
1303 aGrad.SetOfsX( nOfsX );
1304 aGrad.SetOfsY( nOfsY );
1305 aGrad.SetStartIntensity( nIntensityStart );
1306 aGrad.SetEndIntensity( nIntensityEnd );
1307 rMtf.AddAction( new MetaGradientAction( aRect, aGrad ) );
1309 break;
1311 case GDI_TRANSPARENT_COMMENT:
1313 tools::PolyPolygon aPolyPoly;
1314 sal_Int32 nFollowingActionCount(0);
1315 sal_Int16 nTrans(0);
1317 ReadPolyPolygon( rIStm, aPolyPoly );
1318 rIStm.ReadInt16( nTrans ).ReadInt32( nFollowingActionCount );
1319 ImplSkipActions( rIStm, nFollowingActionCount );
1320 rMtf.AddAction( new MetaTransparentAction( aPolyPoly, nTrans ) );
1322 i = SkipActions(i, nFollowingActionCount, nActions);
1324 break;
1326 case GDI_FLOATTRANSPARENT_COMMENT:
1328 GDIMetaFile aMtf;
1329 Point aPos;
1330 Size aSize;
1331 Gradient aGradient;
1332 sal_Int32 nFollowingActionCount(0);
1334 ReadGDIMetaFile( rIStm, aMtf );
1335 ReadPair( rIStm, aPos );
1336 ReadPair( rIStm, aSize );
1337 ReadGradient( rIStm, aGradient );
1338 rIStm.ReadInt32( nFollowingActionCount );
1339 ImplSkipActions( rIStm, nFollowingActionCount );
1340 rMtf.AddAction( new MetaFloatTransparentAction( aMtf, aPos, aSize, aGradient ) );
1342 i = SkipActions(i, nFollowingActionCount, nActions);
1344 break;
1346 case GDI_HATCH_COMMENT:
1348 tools::PolyPolygon aPolyPoly;
1349 Hatch aHatch;
1350 sal_Int32 nFollowingActionCount(0);
1352 ReadPolyPolygon( rIStm, aPolyPoly );
1353 ReadHatch( rIStm, aHatch );
1354 rIStm.ReadInt32( nFollowingActionCount );
1355 ImplSkipActions( rIStm, nFollowingActionCount );
1356 rMtf.AddAction( new MetaHatchAction( aPolyPoly, aHatch ) );
1358 i = SkipActions(i, nFollowingActionCount, nActions);
1360 break;
1362 case GDI_REFPOINT_COMMENT:
1364 Point aRefPoint;
1365 bool bSet;
1366 sal_Int32 nFollowingActionCount(0);
1368 ReadPair( rIStm, aRefPoint );
1369 rIStm.ReadCharAsBool( bSet ).ReadInt32( nFollowingActionCount );
1370 ImplSkipActions( rIStm, nFollowingActionCount );
1371 rMtf.AddAction( new MetaRefPointAction( aRefPoint, bSet ) );
1373 i = SkipActions(i, nFollowingActionCount, nActions);
1375 // #106172# Track font relevant data in shadow VDev
1376 if( bSet )
1377 aFontVDev->SetRefPoint( aRefPoint );
1378 else
1379 aFontVDev->SetRefPoint();
1381 break;
1383 case GDI_TEXTLINECOLOR_COMMENT:
1385 Color aColor;
1386 bool bSet;
1387 sal_Int32 nFollowingActionCount(0);
1389 ReadColor( rIStm, aColor );
1390 rIStm.ReadCharAsBool( bSet ).ReadInt32( nFollowingActionCount );
1391 ImplSkipActions( rIStm, nFollowingActionCount );
1392 rMtf.AddAction( new MetaTextLineColorAction( aColor, bSet ) );
1394 i = SkipActions(i, nFollowingActionCount, nActions);
1396 break;
1398 case GDI_TEXTLINE_COMMENT:
1400 Point aStartPt;
1401 sal_Int32 nWidth(0);
1402 sal_uInt32 nStrikeout(0);
1403 sal_uInt32 nUnderline(0);
1404 sal_Int32 nFollowingActionCount(0);
1406 ReadPair( rIStm, aStartPt );
1407 rIStm.ReadInt32(nWidth ).ReadUInt32(nStrikeout).ReadUInt32(nUnderline).ReadInt32(nFollowingActionCount);
1408 ImplSkipActions(rIStm, nFollowingActionCount);
1409 rMtf.AddAction( new MetaTextLineAction( aStartPt, nWidth,
1410 (FontStrikeout) nStrikeout,
1411 (FontLineStyle) nUnderline,
1412 LINESTYLE_NONE ) );
1414 i = SkipActions(i, nFollowingActionCount, nActions);
1416 break;
1418 case GDI_GRADIENTEX_COMMENT:
1420 tools::PolyPolygon aPolyPoly;
1421 Gradient aGradient;
1422 sal_Int32 nFollowingActionCount(0);
1424 ReadPolyPolygon( rIStm, aPolyPoly );
1425 ReadGradient( rIStm, aGradient );
1426 rIStm.ReadInt32( nFollowingActionCount );
1427 ImplSkipActions( rIStm, nFollowingActionCount );
1428 rMtf.AddAction( new MetaGradientExAction( aPolyPoly, aGradient ) );
1430 i = SkipActions(i, nFollowingActionCount, nActions);
1432 break;
1434 case GDI_COMMENT_COMMENT:
1436 std::vector<sal_uInt8> aData;
1438 OString aComment = read_uInt16_lenPrefixed_uInt8s_ToOString(rIStm);
1439 sal_Int32 nValue(0);
1440 sal_uInt32 nDataSize(0);
1441 rIStm.ReadInt32(nValue).ReadUInt32(nDataSize);
1443 if (nDataSize)
1445 const size_t nMaxPossibleData = rIStm.remainingSize();
1446 if (nDataSize > nMaxPossibleActions)
1448 SAL_WARN("vcl.gdi", "svm record claims to have: " << nDataSize << " data, but only " << nMaxPossibleData << " possible");
1449 nDataSize = nMaxPossibleActions;
1451 aData.resize(nDataSize);
1452 nDataSize = rIStm.ReadBytes(aData.data(), nDataSize);
1455 sal_Int32 nFollowingActionCount(0);
1456 rIStm.ReadInt32(nFollowingActionCount);
1457 ImplSkipActions( rIStm, nFollowingActionCount );
1458 rMtf.AddAction(new MetaCommentAction(aComment, nValue, aData.data(), nDataSize));
1460 i = SkipActions(i, nFollowingActionCount, nActions);
1462 break;
1464 case GDI_UNICODE_COMMENT:
1466 nUnicodeCommentActionNumber = i + 1;
1467 nUnicodeCommentStreamPos = rIStm.Tell() - 6;
1468 if (nActionSize < 4)
1469 rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
1470 else
1471 rIStm.SeekRel(nActionSize - 4);
1473 break;
1475 default:
1476 if (nActionSize < 4)
1477 rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
1478 else
1479 rIStm.SeekRel(nActionSize - 4);
1480 break;
1484 rIStm.SetEndian( nOldFormat );
1487 void SVMConverter::ImplConvertToSVM1( SvStream& rOStm, GDIMetaFile& rMtf )
1489 sal_uLong nCountPos;
1490 vcl::Font aSaveFont;
1491 const SvStreamEndian nOldFormat = rOStm.GetEndian();
1492 rtl_TextEncoding eActualCharSet = osl_getThreadTextEncoding();
1493 const Size aPrefSize( rMtf.GetPrefSize() );
1494 bool bRop_0_1 = false;
1495 ScopedVclPtrInstance< VirtualDevice > aSaveVDev;
1496 Color aLineCol( COL_BLACK );
1497 ::std::stack< Color* > aLineColStack;
1499 rOStm.SetEndian( SvStreamEndian::LITTLE );
1501 // Write MagicCode
1502 rOStm.WriteCharPtr( "SVGDI" ); // Identifier
1503 rOStm.WriteInt16( 42 ); // HeaderSize
1504 rOStm.WriteInt16( 200 ); // VERSION
1505 rOStm.WriteInt32( aPrefSize.Width() );
1506 rOStm.WriteInt32( aPrefSize.Height() );
1507 ImplWriteMapMode( rOStm, rMtf.GetPrefMapMode() );
1509 // ActionCount will be written later
1510 nCountPos = rOStm.Tell();
1511 rOStm.SeekRel( 4 );
1513 const sal_Int32 nActCount = ImplWriteActions( rOStm, rMtf, *aSaveVDev.get(), bRop_0_1, aLineCol, aLineColStack, eActualCharSet );
1514 const sal_uLong nActPos = rOStm.Tell();
1516 rOStm.Seek( nCountPos );
1517 rOStm.WriteInt32( nActCount );
1518 rOStm.Seek( nActPos );
1519 rOStm.SetEndian( nOldFormat );
1521 // cleanup push-pop stack if necessary
1522 while ( !aLineColStack.empty() )
1524 delete aLineColStack.top();
1525 aLineColStack.pop();
1529 sal_uLong SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf,
1530 VirtualDevice& rSaveVDev, bool& rRop_0_1,
1531 Color& rLineCol, ::std::stack< Color* >& rLineColStack,
1532 rtl_TextEncoding& rActualCharSet )
1534 sal_uLong nCount = 0;
1535 for( size_t i = 0, nActionCount = rMtf.GetActionSize(); i < nActionCount; i++ )
1537 const MetaAction* pAction = rMtf.GetAction( i );
1539 switch( pAction->GetType() )
1541 case MetaActionType::PIXEL:
1543 const MetaPixelAction* pAct = static_cast<const MetaPixelAction*>(pAction);
1545 rOStm.WriteInt16( GDI_PIXEL_ACTION );
1546 rOStm.WriteInt32( 18 );
1547 WritePair( rOStm, pAct->GetPoint() );
1548 ImplWriteColor( rOStm, pAct->GetColor() );
1549 nCount++;
1551 break;
1553 case MetaActionType::POINT:
1555 const MetaPointAction* pAct = static_cast<const MetaPointAction*>(pAction);
1557 rOStm.WriteInt16( GDI_POINT_ACTION );
1558 rOStm.WriteInt32( 12 );
1559 WritePair( rOStm, pAct->GetPoint() );
1560 nCount++;
1562 break;
1564 case MetaActionType::LINE:
1566 const MetaLineAction* pAct = static_cast<const MetaLineAction*>(pAction);
1567 const LineInfo& rInfo = pAct->GetLineInfo();
1568 const bool bFatLine(!rInfo.IsDefault() && (LineStyle::NONE != rInfo.GetStyle()));
1569 const bool bLineJoin(bFatLine && basegfx::B2DLineJoin::Round != rInfo.GetLineJoin());
1570 const bool bLineCap(bFatLine && css::drawing::LineCap_BUTT != rInfo.GetLineCap());
1571 const bool bLineDashDot(LineStyle::Dash == rInfo.GetStyle());
1573 if( bFatLine )
1575 ImplWritePushAction( rOStm );
1576 ImplWriteLineColor( rOStm, rLineCol, 1, rInfo.GetWidth() );
1578 if(bLineJoin)
1580 rOStm.WriteInt16( GDI_LINEJOIN_ACTION );
1581 rOStm.WriteInt32( 6 );
1582 rOStm.WriteInt16( static_cast<sal_Int16>(rInfo.GetLineJoin()) );
1585 if(bLineCap)
1587 rOStm.WriteInt16( GDI_LINECAP_ACTION );
1588 rOStm.WriteInt32( 6 );
1589 rOStm.WriteInt16( (sal_Int16)rInfo.GetLineCap() );
1593 if(bLineDashDot)
1595 rOStm.WriteInt16( GDI_LINEDASHDOT_ACTION );
1596 rOStm.WriteInt32( 4 + 16 );
1597 rOStm.WriteInt16( rInfo.GetDashCount() );
1598 rOStm.WriteInt32( rInfo.GetDashLen() );
1599 rOStm.WriteInt16( rInfo.GetDotCount() );
1600 rOStm.WriteInt32( rInfo.GetDotLen() );
1601 rOStm.WriteInt32( rInfo.GetDistance() );
1604 rOStm.WriteInt16( GDI_LINE_ACTION );
1605 rOStm.WriteInt32( 20 );
1606 WritePair( rOStm, pAct->GetStartPoint() );
1607 WritePair( rOStm, pAct->GetEndPoint() );
1608 nCount++;
1610 if( bFatLine )
1612 ImplWritePopAction( rOStm );
1613 nCount += 3;
1615 if(bLineJoin)
1617 nCount += 1;
1620 if(bLineCap)
1622 nCount += 1;
1626 if(bLineDashDot)
1628 nCount += 1;
1631 break;
1633 case MetaActionType::RECT:
1635 const MetaRectAction* pAct = static_cast<const MetaRectAction*>(pAction);
1637 rOStm.WriteInt16( GDI_RECT_ACTION );
1638 rOStm.WriteInt32( 28 );
1639 ImplWriteRect( rOStm, pAct->GetRect() );
1640 rOStm.WriteInt32( 0 );
1641 rOStm.WriteInt32( 0 );
1642 nCount++;
1644 break;
1646 case MetaActionType::ROUNDRECT:
1648 const MetaRoundRectAction* pAct = static_cast<const MetaRoundRectAction*>(pAction);
1650 rOStm.WriteInt16( GDI_RECT_ACTION );
1651 rOStm.WriteInt32( 28 );
1652 ImplWriteRect( rOStm, pAct->GetRect() );
1653 rOStm.WriteInt32( pAct->GetHorzRound() );
1654 rOStm.WriteInt32( pAct->GetVertRound() );
1655 nCount++;
1657 break;
1659 case MetaActionType::ELLIPSE:
1661 const MetaEllipseAction* pAct = static_cast<const MetaEllipseAction*>(pAction);
1663 rOStm.WriteInt16( GDI_ELLIPSE_ACTION );
1664 rOStm.WriteInt32( 20 );
1665 ImplWriteRect( rOStm, pAct->GetRect() );
1666 nCount++;
1668 break;
1670 case MetaActionType::ARC:
1672 const MetaArcAction* pAct = static_cast<const MetaArcAction*>(pAction);
1674 rOStm.WriteInt16( GDI_ARC_ACTION );
1675 rOStm.WriteInt32( 36 );
1676 ImplWriteRect( rOStm, pAct->GetRect() );
1677 WritePair( rOStm, pAct->GetStartPoint() );
1678 WritePair( rOStm, pAct->GetEndPoint() );
1679 nCount++;
1681 break;
1683 case MetaActionType::PIE:
1685 const MetaPieAction* pAct = static_cast<const MetaPieAction*>(pAction);
1687 rOStm.WriteInt16( GDI_PIE_ACTION );
1688 rOStm.WriteInt32( 36 );
1689 ImplWriteRect( rOStm, pAct->GetRect() );
1690 WritePair( rOStm, pAct->GetStartPoint() );
1691 WritePair( rOStm, pAct->GetEndPoint() );
1692 nCount++;
1694 break;
1696 case MetaActionType::CHORD:
1698 const MetaChordAction* pAct = static_cast<const MetaChordAction*>(pAction);
1699 tools::Polygon aChordPoly( pAct->GetRect(), pAct->GetStartPoint(),
1700 pAct->GetEndPoint(), PolyStyle::Chord );
1701 const sal_uInt16 nPoints = aChordPoly.GetSize();
1703 rOStm.WriteInt16( GDI_POLYGON_ACTION );
1704 rOStm.WriteInt32( 8 + ( nPoints << 3 ) );
1705 rOStm.WriteInt32( nPoints );
1707 for( sal_uInt16 n = 0; n < nPoints; n++ )
1708 WritePair( rOStm, aChordPoly[ n ] );
1709 nCount++;
1711 break;
1713 case MetaActionType::POLYLINE:
1715 // #i102224#
1716 const MetaPolyLineAction* pAct = static_cast<const MetaPolyLineAction*>(pAction);
1717 // #i102224# Here the possible curved nature of Polygon was
1718 // ignored (for all those years). Adapted to at least write
1719 // a polygon representing the curve as good as possible
1720 tools::Polygon aSimplePoly;
1721 pAct->GetPolygon().AdaptiveSubdivide(aSimplePoly);
1722 const LineInfo& rInfo = pAct->GetLineInfo();
1723 const sal_uInt16 nPoints(aSimplePoly.GetSize());
1724 const bool bFatLine(!rInfo.IsDefault() && (LineStyle::NONE != rInfo.GetStyle()));
1725 const bool bLineJoin(bFatLine && basegfx::B2DLineJoin::Round != rInfo.GetLineJoin());
1726 const bool bLineCap(bFatLine && css::drawing::LineCap_BUTT != rInfo.GetLineCap());
1727 const bool bLineDashDot(LineStyle::Dash == rInfo.GetStyle());
1729 if( bFatLine )
1731 ImplWritePushAction( rOStm );
1732 ImplWriteLineColor( rOStm, rLineCol, 1, rInfo.GetWidth() );
1734 if(bLineJoin)
1736 rOStm.WriteInt16( GDI_LINEJOIN_ACTION );
1737 rOStm.WriteInt32( 6 );
1738 rOStm.WriteInt16( static_cast<sal_Int16>(rInfo.GetLineJoin()) );
1741 if(bLineCap)
1743 rOStm.WriteInt16( GDI_LINECAP_ACTION );
1744 rOStm.WriteInt32( 6 );
1745 rOStm.WriteInt16( (sal_Int16)rInfo.GetLineCap() );
1749 if(bLineDashDot)
1751 rOStm.WriteInt16( GDI_LINEDASHDOT_ACTION );
1752 rOStm.WriteInt32( 4 + 16 );
1753 rOStm.WriteInt16( rInfo.GetDashCount() );
1754 rOStm.WriteInt32( rInfo.GetDashLen() );
1755 rOStm.WriteInt16( rInfo.GetDotCount() );
1756 rOStm.WriteInt32( rInfo.GetDotLen() );
1757 rOStm.WriteInt32( rInfo.GetDistance() );
1760 rOStm.WriteInt16( GDI_POLYLINE_ACTION );
1761 rOStm.WriteInt32( 8 + ( nPoints << 3 ) );
1762 rOStm.WriteInt32( nPoints );
1764 for( sal_uInt16 n = 0; n < nPoints; n++ )
1766 WritePair( rOStm, aSimplePoly[ n ] );
1769 nCount++;
1771 const tools::PolyPolygon aPolyPolygon(pAct->GetPolygon());
1772 if(ImplWriteExtendedPolyPolygonAction(rOStm, aPolyPolygon, true))
1774 nCount++;
1777 if( bFatLine )
1779 ImplWritePopAction( rOStm );
1780 nCount += 3;
1782 if(bLineJoin)
1784 nCount += 1;
1787 if(bLineCap)
1789 nCount += 1;
1793 if(bLineDashDot)
1795 nCount += 1;
1798 break;
1800 case MetaActionType::POLYGON:
1802 const MetaPolygonAction* pAct = static_cast<const MetaPolygonAction*>(pAction);
1803 // #i102224# Here the possible curved nature of Polygon was
1804 // ignored (for all those years). Adapted to at least write
1805 // a polygon representing the curve as good as possible
1806 tools::Polygon aSimplePoly;
1807 pAct->GetPolygon().AdaptiveSubdivide(aSimplePoly);
1808 const sal_uInt16 nPoints(aSimplePoly.GetSize());
1810 rOStm.WriteInt16( GDI_POLYGON_ACTION );
1811 rOStm.WriteInt32( 8 + ( nPoints << 3 ) );
1812 rOStm.WriteInt32( nPoints );
1814 for( sal_uInt16 n = 0; n < nPoints; n++ )
1815 WritePair( rOStm, aSimplePoly[ n ] );
1817 nCount++;
1819 const tools::PolyPolygon aPolyPolygon(pAct->GetPolygon());
1820 if(ImplWriteExtendedPolyPolygonAction(rOStm, aPolyPolygon, true))
1822 nCount++;
1825 break;
1827 case MetaActionType::POLYPOLYGON:
1829 const MetaPolyPolygonAction* pAct = static_cast<const MetaPolyPolygonAction*>(pAction);
1830 ImplWritePolyPolyAction( rOStm, pAct->GetPolyPolygon() );
1831 nCount++;
1833 if(ImplWriteExtendedPolyPolygonAction(rOStm, pAct->GetPolyPolygon(), true))
1835 nCount++;
1838 break;
1840 case MetaActionType::TEXT:
1842 const MetaTextAction* pAct = static_cast<const MetaTextAction*>(pAction);
1843 OUString aUniText( pAct->GetText() );
1844 OString aText(OUStringToOString(aUniText, rActualCharSet));
1845 const sal_Int32 nStrLen = aText.getLength();
1847 if ( ImplWriteUnicodeComment( rOStm, aUniText ) )
1848 nCount++;
1850 rOStm.WriteInt16( GDI_TEXT_ACTION );
1851 rOStm.WriteInt32( 24 + ( nStrLen + 1 ) );
1852 WritePair( rOStm, pAct->GetPoint() );
1853 rOStm.WriteInt32( pAct->GetIndex() );
1854 rOStm.WriteInt32( pAct->GetLen() );
1855 rOStm.WriteInt32( nStrLen );
1856 rOStm.WriteBytes( aText.getStr(), nStrLen + 1 );
1857 nCount++;
1859 break;
1861 case MetaActionType::TEXTARRAY:
1863 const MetaTextArrayAction* pAct = static_cast<const MetaTextArrayAction*>(pAction);
1864 OString aText(OUStringToOString(pAct->GetText(), rActualCharSet));
1865 OUString aUniText = pAct->GetText().copy(
1866 pAct->GetIndex(),
1867 std::min<sal_Int32>(pAct->GetText().getLength() - pAct->GetIndex(), pAct->GetLen()) );
1868 sal_Int32 nAryLen;
1869 sal_Int32 nLen = pAct->GetLen();
1870 const sal_Int32 nTextLen = aText.getLength();
1871 long* pDXArray = pAct->GetDXArray();
1873 if ( ImplWriteUnicodeComment( rOStm, aUniText ) )
1874 nCount++;
1876 if( ( nLen + pAct->GetIndex() ) > nTextLen )
1878 if( pAct->GetIndex() <= nTextLen )
1879 nLen = nTextLen - pAct->GetIndex();
1880 else
1881 nLen = 0;
1884 if( !pDXArray || !nLen )
1885 nAryLen = 0;
1886 else
1887 nAryLen = nLen; // #105987# Write out all of DX array
1889 rOStm.WriteInt16( GDI_TEXTARRAY_ACTION );
1890 rOStm.WriteInt32( 28 + ( nLen + 1 ) + ( nAryLen * 4 ) );
1891 WritePair( rOStm, pAct->GetPoint() );
1892 rOStm.WriteInt32( 0 );
1893 rOStm.WriteInt32( nLen );
1894 rOStm.WriteInt32( nLen );
1895 rOStm.WriteInt32( nAryLen );
1896 rOStm.WriteBytes( aText.getStr()+pAct->GetIndex(), nLen + 1 );
1898 for (sal_Int32 n = 0; n < nAryLen; ++n)
1899 rOStm.WriteInt32( pDXArray[ n ] );
1901 nCount++;
1903 break;
1905 case MetaActionType::STRETCHTEXT:
1907 const MetaStretchTextAction* pAct = static_cast<const MetaStretchTextAction*>(pAction);
1908 OUString aUniText( pAct->GetText() );
1909 OString aText(OUStringToOString(aUniText, rActualCharSet));
1910 const sal_Int32 nStrLen = aText.getLength();
1912 if ( ImplWriteUnicodeComment( rOStm, aUniText ) )
1913 nCount++;
1915 rOStm.WriteInt16( GDI_STRETCHTEXT_ACTION );
1916 rOStm.WriteInt32( 28 + ( nStrLen + 1 ) );
1917 WritePair( rOStm, pAct->GetPoint() );
1918 rOStm.WriteInt32( pAct->GetIndex() );
1919 rOStm.WriteInt32( pAct->GetLen() );
1920 rOStm.WriteInt32( nStrLen );
1921 rOStm.WriteInt32( pAct->GetWidth() );
1922 rOStm.WriteBytes( aText.getStr(), nStrLen + 1 );
1923 nCount++;
1925 break;
1927 case MetaActionType::BMP:
1929 const MetaBmpAction* pAct = static_cast<const MetaBmpAction*>(pAction);
1931 rOStm.WriteInt16( GDI_BITMAP_ACTION );
1932 rOStm.WriteInt32( 12 );
1933 WritePair( rOStm, pAct->GetPoint() );
1934 WriteDIB(pAct->GetBitmap(), rOStm, false, true);
1935 nCount++;
1937 break;
1939 case MetaActionType::BMPSCALE:
1941 const MetaBmpScaleAction* pAct = static_cast<const MetaBmpScaleAction*>(pAction);
1943 rOStm.WriteInt16( GDI_BITMAPSCALE_ACTION );
1944 rOStm.WriteInt32( 20 );
1945 WritePair( rOStm, pAct->GetPoint() );
1946 WritePair( rOStm, pAct->GetSize() );
1947 WriteDIB(pAct->GetBitmap(), rOStm, false, true);
1948 nCount++;
1950 break;
1952 case MetaActionType::BMPSCALEPART:
1954 const MetaBmpScalePartAction* pAct = static_cast<const MetaBmpScalePartAction*>(pAction);
1956 rOStm.WriteInt16( GDI_BITMAPSCALEPART_ACTION );
1957 rOStm.WriteInt32( 36 );
1958 WritePair( rOStm, pAct->GetDestPoint() );
1959 WritePair( rOStm, pAct->GetDestSize() );
1960 WritePair( rOStm, pAct->GetSrcPoint() );
1961 WritePair( rOStm, pAct->GetSrcSize() );
1962 WriteDIB(pAct->GetBitmap(), rOStm, false, true);
1963 nCount++;
1965 break;
1967 case MetaActionType::BMPEX:
1969 const MetaBmpExAction* pAct = static_cast<const MetaBmpExAction*>(pAction);
1970 const Bitmap aBmp( Graphic( pAct->GetBitmapEx() ).GetBitmap() );
1972 rOStm.WriteInt16( GDI_BITMAP_ACTION );
1973 rOStm.WriteInt32( 12 );
1974 WritePair( rOStm, pAct->GetPoint() );
1975 WriteDIB(aBmp, rOStm, false, true);
1976 nCount++;
1978 break;
1980 case MetaActionType::BMPEXSCALE:
1982 const MetaBmpExScaleAction* pAct = static_cast<const MetaBmpExScaleAction*>(pAction);
1983 const Bitmap aBmp( Graphic( pAct->GetBitmapEx() ).GetBitmap() );
1985 rOStm.WriteInt16( GDI_BITMAPSCALE_ACTION );
1986 rOStm.WriteInt32( 20 );
1987 WritePair( rOStm, pAct->GetPoint() );
1988 WritePair( rOStm, pAct->GetSize() );
1989 WriteDIB(aBmp, rOStm, false, true);
1990 nCount++;
1992 break;
1994 case MetaActionType::BMPEXSCALEPART:
1996 const MetaBmpExScalePartAction* pAct = static_cast<const MetaBmpExScalePartAction*>(pAction);
1997 const Bitmap aBmp( Graphic( pAct->GetBitmapEx() ).GetBitmap() );
1999 rOStm.WriteInt16( GDI_BITMAPSCALEPART_ACTION );
2000 rOStm.WriteInt32( 36 );
2001 WritePair( rOStm, pAct->GetDestPoint() );
2002 WritePair( rOStm, pAct->GetDestSize() );
2003 WritePair( rOStm, pAct->GetSrcPoint() );
2004 WritePair( rOStm, pAct->GetSrcSize() );
2005 WriteDIB(aBmp, rOStm, false, true);
2006 nCount++;
2008 break;
2010 case MetaActionType::GRADIENT:
2012 const MetaGradientAction* pAct = static_cast<const MetaGradientAction*>(pAction);
2013 const Gradient& rGrad = pAct->GetGradient();
2015 rOStm.WriteInt16( GDI_GRADIENT_ACTION );
2016 rOStm.WriteInt32( 46 );
2017 ImplWriteRect( rOStm, pAct->GetRect() );
2018 rOStm.WriteInt16( (sal_Int16)rGrad.GetStyle() );
2019 ImplWriteColor( rOStm, rGrad.GetStartColor() );
2020 ImplWriteColor( rOStm, rGrad.GetEndColor() );
2021 rOStm.WriteInt16( rGrad.GetAngle() );
2022 rOStm.WriteInt16( rGrad.GetBorder() );
2023 rOStm.WriteInt16( rGrad.GetOfsX() );
2024 rOStm.WriteInt16( rGrad.GetOfsY() );
2025 rOStm.WriteInt16( rGrad.GetStartIntensity() );
2026 rOStm.WriteInt16( rGrad.GetEndIntensity() );
2027 nCount++;
2029 break;
2031 case MetaActionType::GRADIENTEX:
2033 const MetaGradientExAction* pA = static_cast<const MetaGradientExAction*>(pAction);
2034 sal_uLong nOldPos, nNewPos;
2036 // write RefPoint comment
2037 rOStm.WriteInt16( GDI_GRADIENTEX_COMMENT );
2039 // we'll write the ActionSize later
2040 nOldPos = rOStm.Tell();
2041 rOStm.SeekRel( 4 );
2043 // write data
2044 WritePolyPolygon( rOStm, pA->GetPolyPolygon() );
2045 WriteGradient( rOStm, pA->GetGradient() );
2046 rOStm.WriteInt32( 0 ); // number of actions that follow this comment
2048 // calculate and write ActionSize of comment
2049 nNewPos = rOStm.Tell();
2050 rOStm.Seek( nOldPos );
2051 rOStm.WriteInt32( nNewPos - nOldPos );
2052 rOStm.Seek( nNewPos );
2054 nCount++;
2056 break;
2058 case MetaActionType::WALLPAPER:
2060 const MetaWallpaperAction* pAct = static_cast<const MetaWallpaperAction*>(pAction);
2061 const Color& rColor = pAct->GetWallpaper().GetColor();
2063 ImplWritePushAction( rOStm );
2064 ImplWriteLineColor( rOStm, rColor, 1 );
2065 ImplWriteFillColor( rOStm, rColor, 1 );
2067 rOStm.WriteInt16( GDI_RECT_ACTION );
2068 rOStm.WriteInt32( 28 );
2069 ImplWriteRect( rOStm, pAct->GetRect() );
2070 rOStm.WriteInt32( 0 );
2071 rOStm.WriteInt32( 0 );
2073 ImplWritePopAction( rOStm );
2074 nCount += 5;
2076 break;
2078 case MetaActionType::CLIPREGION:
2080 const MetaClipRegionAction* pAct = static_cast<const MetaClipRegionAction*>(pAction);
2081 const vcl::Region& rRegion = pAct->GetRegion();
2082 tools::Rectangle aClipRect;
2084 rOStm.WriteInt16( GDI_CLIPREGION_ACTION );
2085 rOStm.WriteInt32( 24 );
2087 if( pAct->IsClipping() )
2089 aClipRect = rRegion.GetBoundRect();
2090 rOStm.WriteInt16( 1 );
2092 else
2093 rOStm.WriteInt16( 0 );
2095 rOStm.WriteInt16( 0 );
2096 ImplWriteRect( rOStm, aClipRect );
2098 if( pAct->IsClipping() )
2099 ImplWriteRect( rOStm, aClipRect );
2101 nCount++;
2103 break;
2105 case MetaActionType::ISECTRECTCLIPREGION:
2107 const MetaISectRectClipRegionAction* pAct = static_cast<const MetaISectRectClipRegionAction*>(pAction);
2109 rOStm.WriteInt16( GDI_ISECTCLIPREGION_ACTION );
2110 rOStm.WriteInt32( 20 );
2111 WriteRectangle( rOStm, pAct->GetRect() );
2112 nCount++;
2114 break;
2116 case MetaActionType::MOVECLIPREGION:
2118 const MetaMoveClipRegionAction* pAct = static_cast<const MetaMoveClipRegionAction*>(pAction);
2120 rOStm.WriteInt16( GDI_MOVECLIPREGION_ACTION );
2121 rOStm.WriteInt32( 12 );
2122 rOStm.WriteInt32( pAct->GetHorzMove() );
2123 rOStm.WriteInt32( pAct->GetVertMove() );
2124 nCount++;
2126 break;
2128 case MetaActionType::LINECOLOR:
2130 const MetaLineColorAction* pAct = static_cast<const MetaLineColorAction*>(pAction);
2131 ImplWriteLineColor( rOStm, rLineCol = pAct->GetColor(), pAct->IsSetting() ? 1 : 0 );
2132 nCount++;
2134 break;
2136 case MetaActionType::FILLCOLOR:
2138 const MetaFillColorAction* pAct = static_cast<const MetaFillColorAction*>(pAction);
2139 ImplWriteFillColor( rOStm, pAct->GetColor(), pAct->IsSetting() ? 1 : 0 );
2140 nCount++;
2142 break;
2144 case MetaActionType::FONT:
2146 rSaveVDev.SetFont( static_cast<const MetaFontAction*>(pAction)->GetFont() );
2147 ImplWriteFont( rOStm, rSaveVDev.GetFont(), rActualCharSet );
2148 nCount++;
2150 break;
2152 case MetaActionType::TEXTCOLOR:
2154 vcl::Font aSaveFont( rSaveVDev.GetFont() );
2156 aSaveFont.SetColor( static_cast<const MetaTextColorAction*>(pAction)->GetColor() );
2157 rSaveVDev.SetFont( aSaveFont );
2158 ImplWriteFont( rOStm, rSaveVDev.GetFont(), rActualCharSet );
2159 nCount++;
2161 break;
2163 case MetaActionType::TEXTFILLCOLOR:
2165 const MetaTextFillColorAction* pAct = static_cast<const MetaTextFillColorAction*>(pAction);
2166 vcl::Font aSaveFont( rSaveVDev.GetFont() );
2168 if( pAct->IsSetting() )
2169 aSaveFont.SetFillColor( pAct->GetColor() );
2170 else
2171 aSaveFont.SetFillColor( Color( COL_TRANSPARENT ) );
2173 rSaveVDev.SetFont( aSaveFont );
2174 ImplWriteFont( rOStm, rSaveVDev.GetFont(), rActualCharSet );
2175 nCount++;
2177 break;
2179 case MetaActionType::TEXTALIGN:
2181 vcl::Font aSaveFont( rSaveVDev.GetFont() );
2183 aSaveFont.SetAlignment( static_cast<const MetaTextAlignAction*>(pAction)->GetTextAlign() );
2184 rSaveVDev.SetFont( aSaveFont );
2185 ImplWriteFont( rOStm, rSaveVDev.GetFont(), rActualCharSet );
2186 nCount++;
2188 break;
2190 case MetaActionType::MAPMODE:
2192 const MetaMapModeAction* pAct = static_cast<const MetaMapModeAction*>(pAction);
2194 rOStm.WriteInt16( GDI_MAPMODE_ACTION );
2195 rOStm.WriteInt32( 30 );
2196 ImplWriteMapMode( rOStm, pAct->GetMapMode() );
2197 nCount++;
2199 break;
2201 case MetaActionType::PUSH:
2203 ImplWritePushAction( rOStm );
2204 rLineColStack.push( new Color( rLineCol ) );
2205 rSaveVDev.Push();
2206 nCount++;
2208 break;
2210 case MetaActionType::POP:
2212 Color* pCol;
2213 if (rLineColStack.empty())
2214 pCol = nullptr;
2215 else
2217 pCol = rLineColStack.top();
2218 rLineColStack.pop();
2221 if( pCol )
2223 rLineCol = *pCol;
2224 delete pCol;
2227 ImplWritePopAction( rOStm );
2228 rSaveVDev.Pop();
2229 nCount++;
2231 break;
2233 case MetaActionType::RASTEROP:
2235 const MetaRasterOpAction* pAct = static_cast<const MetaRasterOpAction*>(pAction);
2237 if( ( pAct->GetRasterOp() != RasterOp::N0 ) && ( pAct->GetRasterOp() != RasterOp::N1 ) )
2239 sal_Int16 nRasterOp;
2241 // If RasterOp::N0/1 was set earlier, restore old state
2242 // via a Pop first
2243 if( rRop_0_1 )
2245 ImplWritePopAction( rOStm );
2246 rSaveVDev.Pop();
2247 rRop_0_1 = false;
2248 nCount++;
2251 switch( pAct->GetRasterOp() )
2253 case RasterOp::OverPaint : nRasterOp = 0; break;
2254 case RasterOp::Xor : nRasterOp = 4; break;
2255 case RasterOp::Invert: nRasterOp = 1; break;
2256 default: nRasterOp = 0; break;
2259 ImplWriteRasterOpAction( rOStm, nRasterOp );
2260 nCount++;
2262 else
2264 ImplWritePushAction( rOStm );
2265 rSaveVDev.Push();
2267 if( pAct->GetRasterOp() == RasterOp::N0 )
2269 ImplWriteLineColor( rOStm, COL_BLACK, 1 );
2270 ImplWriteFillColor( rOStm, COL_BLACK, 1 );
2272 else
2274 ImplWriteLineColor( rOStm, COL_WHITE, 1 );
2275 ImplWriteFillColor( rOStm, COL_WHITE, 1 );
2278 ImplWriteRasterOpAction( rOStm, 0 );
2279 rRop_0_1 = true;
2280 nCount += 4;
2283 break;
2285 case MetaActionType::Transparent:
2287 const tools::PolyPolygon& rPolyPoly = static_cast<const MetaTransparentAction*>(pAction)->GetPolyPolygon();
2288 const sal_Int16 nTrans = static_cast<const MetaTransparentAction*>(pAction)->GetTransparence();
2289 const sal_Int16 nBrushStyle = ( nTrans < 38 ) ? 8 : ( nTrans < 63 ) ? 9 : 10;
2290 sal_uLong nOldPos, nNewPos;
2292 // write transparence comment
2293 rOStm.WriteInt16( GDI_TRANSPARENT_COMMENT );
2295 // we'll write the ActionSize later
2296 nOldPos = rOStm.Tell();
2297 rOStm.SeekRel( 4 );
2299 // write comment data
2300 WritePolyPolygon( rOStm, rPolyPoly );
2301 rOStm.WriteInt16( nTrans );
2302 rOStm.WriteInt32( 15 ); // number of actions that follow this comment
2304 // calculate and write ActionSize of comment
2305 nNewPos = rOStm.Tell();
2306 rOStm.Seek( nOldPos );
2307 rOStm.WriteInt32( nNewPos - nOldPos );
2308 rOStm.Seek( nNewPos );
2311 // write actions for transparence
2312 ImplWritePushAction( rOStm );
2314 ImplWriteRasterOpAction( rOStm, 4 );
2315 ImplWritePolyPolyAction( rOStm, rPolyPoly );
2317 ImplWritePushAction( rOStm );
2319 ImplWriteRasterOpAction( rOStm, 2 );
2320 ImplWriteFillColor( rOStm, COL_BLACK, nBrushStyle );
2321 ImplWritePolyPolyAction( rOStm, rPolyPoly );
2323 ImplWritePopAction( rOStm );
2325 ImplWriteRasterOpAction( rOStm, 4 );
2326 ImplWritePolyPolyAction( rOStm, rPolyPoly );
2328 ImplWritePopAction( rOStm );
2330 ImplWritePushAction( rOStm );
2332 ImplWriteFillColor( rOStm, Color(), 0 );
2333 ImplWritePolyPolyAction( rOStm, rPolyPoly );
2335 ImplWritePopAction( rOStm );
2337 nCount += 15;
2340 nCount++;
2342 break;
2344 case MetaActionType::FLOATTRANSPARENT:
2346 const MetaFloatTransparentAction* pA = static_cast<const MetaFloatTransparentAction*>(pAction);
2347 const GDIMetaFile& rTransMtf = pA->GetGDIMetaFile();
2348 const Point& rPos = pA->GetPoint();
2349 const Size& rSize = pA->GetSize();
2350 const Gradient& rGradient = pA->GetGradient();
2351 sal_uLong nOldPos, nNewPos;
2353 // write RefPoint comment
2354 rOStm.WriteInt16( GDI_FLOATTRANSPARENT_COMMENT );
2356 // we'll write the ActionSize later
2357 nOldPos = rOStm.Tell();
2358 rOStm.SeekRel( 4 );
2360 // write comment data
2361 WriteGDIMetaFile( rOStm, rTransMtf );
2362 WritePair( rOStm, rPos );
2363 WritePair( rOStm, rSize );
2364 WriteGradient( rOStm, rGradient );
2366 // calculate and write ActionSize of comment
2367 nNewPos = rOStm.Tell();
2368 rOStm.Seek( nOldPos );
2369 rOStm.WriteInt32( nNewPos - nOldPos + 4 );
2370 rOStm.Seek( ( nOldPos = nNewPos ) + 4 );
2373 // write actions for float transparence
2374 sal_uLong nAddCount;
2375 GDIMetaFile aMtf( rTransMtf );
2376 const Size aSrcSize( rTransMtf.GetPrefSize() );
2377 Point aSrcPt( rTransMtf.GetPrefMapMode().GetOrigin() );
2378 const double fScaleX = aSrcSize.Width() ? (double) rSize.Width() / aSrcSize.Width() : 1.0;
2379 const double fScaleY = aSrcSize.Height() ? (double) rSize.Height() / aSrcSize.Height() : 1.0;
2380 long nMoveX, nMoveY;
2382 if( fScaleX != 1.0 || fScaleY != 1.0 )
2384 aMtf.Scale( fScaleX, fScaleY );
2385 aSrcPt.X() = FRound( aSrcPt.X() * fScaleX );
2386 aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
2389 nMoveX = rPos.X() - aSrcPt.X();
2390 nMoveY = rPos.Y() - aSrcPt.Y();
2392 if( nMoveX || nMoveY )
2393 aMtf.Move( nMoveX, nMoveY );
2395 nAddCount = ImplWriteActions( rOStm, aMtf, rSaveVDev, rRop_0_1, rLineCol, rLineColStack, rActualCharSet );
2396 nNewPos = rOStm.Tell();
2397 rOStm.Seek( nOldPos );
2398 rOStm.WriteInt32( nAddCount );
2399 rOStm.Seek( nNewPos );
2401 nCount += nAddCount;
2404 nCount++;
2406 break;
2408 case MetaActionType::HATCH:
2410 const MetaHatchAction* pA = static_cast<const MetaHatchAction*>(pAction);
2411 const tools::PolyPolygon& rPolyPoly = pA->GetPolyPolygon();
2412 const Hatch& rHatch = pA->GetHatch();
2413 sal_uLong nOldPos, nNewPos, nAddCount;
2415 // write hatch comment
2416 rOStm.WriteInt16( GDI_HATCH_COMMENT );
2418 // we'll write the ActionSize later
2419 nOldPos = rOStm.Tell();
2420 rOStm.SeekRel( 4 );
2422 // write comment data
2423 WritePolyPolygon( rOStm, rPolyPoly );
2424 WriteHatch( rOStm, rHatch );
2426 // calculate and write ActionSize of comment
2427 nNewPos = rOStm.Tell();
2428 rOStm.Seek( nOldPos );
2429 rOStm.WriteInt32( nNewPos - nOldPos + 4 );
2430 rOStm.Seek( ( nOldPos = nNewPos ) + 4 );
2433 // write actions for hatch
2434 ScopedVclPtrInstance< VirtualDevice > aVDev;
2435 GDIMetaFile aTmpMtf;
2437 aVDev->AddHatchActions( rPolyPoly, rHatch, aTmpMtf );
2438 nAddCount = ImplWriteActions( rOStm, aTmpMtf, rSaveVDev, rRop_0_1, rLineCol, rLineColStack, rActualCharSet );
2439 nNewPos = rOStm.Tell();
2440 rOStm.Seek( nOldPos );
2441 rOStm.WriteInt32( nAddCount );
2442 rOStm.Seek( nNewPos );
2444 nCount += nAddCount;
2447 nCount++;
2449 break;
2451 case MetaActionType::REFPOINT:
2453 const MetaRefPointAction* pA = static_cast<const MetaRefPointAction*>(pAction);
2454 const Point& rRefPoint = pA->GetRefPoint();
2455 const bool bSet = pA->IsSetting();
2456 sal_uLong nOldPos, nNewPos;
2458 // write RefPoint comment
2459 rOStm.WriteInt16( GDI_REFPOINT_COMMENT );
2461 // we'll write the ActionSize later
2462 nOldPos = rOStm.Tell();
2463 rOStm.SeekRel( 4 );
2465 // write data
2466 WritePair( rOStm, rRefPoint );
2467 rOStm.WriteBool( bSet );
2468 rOStm.WriteInt32( 0 ); // number of actions that follow this comment
2470 // calculate and write ActionSize of comment
2471 nNewPos = rOStm.Tell();
2472 rOStm.Seek( nOldPos );
2473 rOStm.WriteInt32( nNewPos - nOldPos );
2474 rOStm.Seek( nNewPos );
2476 nCount++;
2478 break;
2480 case MetaActionType::TEXTLINECOLOR:
2482 const MetaTextLineColorAction* pA = static_cast<const MetaTextLineColorAction*>(pAction);
2483 const Color& rColor = pA->GetColor();
2484 const bool bSet = pA->IsSetting();
2485 sal_uLong nOldPos, nNewPos;
2487 // write RefPoint comment
2488 rOStm.WriteInt16( GDI_TEXTLINECOLOR_COMMENT );
2490 // we'll write the ActionSize later
2491 nOldPos = rOStm.Tell();
2492 rOStm.SeekRel( 4 );
2494 // write data
2495 WriteColor( rOStm, rColor );
2496 rOStm.WriteBool( bSet );
2497 rOStm.WriteInt32( 0 ); // number of actions that follow this comment
2499 // calculate and write ActionSize of comment
2500 nNewPos = rOStm.Tell();
2501 rOStm.Seek( nOldPos );
2502 rOStm.WriteInt32( nNewPos - nOldPos );
2503 rOStm.Seek( nNewPos );
2505 nCount++;
2507 break;
2509 case MetaActionType::TEXTLINE:
2511 const MetaTextLineAction* pA = static_cast<const MetaTextLineAction*>(pAction);
2512 const Point& rStartPt = pA->GetStartPoint();
2513 const sal_Int32 nWidth = (sal_Int32) pA->GetWidth();
2514 const FontStrikeout eStrikeout = pA->GetStrikeout();
2515 const FontLineStyle eUnderline = pA->GetUnderline();
2516 sal_uLong nOldPos, nNewPos;
2518 // write RefPoint comment
2519 rOStm.WriteInt16( GDI_TEXTLINE_COMMENT );
2521 // we'll write the ActionSize later
2522 nOldPos = rOStm.Tell();
2523 rOStm.SeekRel( 4 );
2525 // write data
2526 WritePair( rOStm, rStartPt );
2527 rOStm.WriteInt32( nWidth ).WriteUInt32( eStrikeout ).WriteUInt32( eUnderline );
2528 rOStm.WriteInt32( 0 ); // number of actions that follow this comment
2530 // calculate and write ActionSize of comment
2531 nNewPos = rOStm.Tell();
2532 rOStm.Seek( nOldPos );
2533 rOStm.WriteInt32( nNewPos - nOldPos );
2534 rOStm.Seek( nNewPos );
2536 nCount++;
2538 break;
2540 case MetaActionType::EPS:
2541 break;
2543 case MetaActionType::COMMENT:
2545 const MetaCommentAction* pA = static_cast<const MetaCommentAction*>(pAction);
2546 const sal_uInt32 nDataSize = pA->GetDataSize();
2547 sal_uLong nOldPos, nNewPos;
2549 // write RefPoint comment
2550 rOStm.WriteInt16( GDI_COMMENT_COMMENT );
2552 // we'll write the ActionSize later
2553 nOldPos = rOStm.Tell();
2554 rOStm.SeekRel( 4 );
2556 // write data
2557 write_uInt16_lenPrefixed_uInt8s_FromOString(rOStm, pA->GetComment());
2558 rOStm.WriteInt32( pA->GetValue() ).WriteUInt32( nDataSize );
2560 if( nDataSize )
2561 rOStm.WriteBytes( pA->GetData(), nDataSize );
2563 rOStm.WriteInt32( 0 ); // number of actions that follow this comment
2565 // calculate and write ActionSize of comment
2566 nNewPos = rOStm.Tell();
2567 rOStm.Seek( nOldPos );
2568 rOStm.WriteInt32( nNewPos - nOldPos );
2569 rOStm.Seek( nNewPos );
2571 nCount++;
2573 break;
2575 default:
2576 #ifdef DBG_UTIL
2578 OStringBuffer aStr("Missing implementation for Action#: ");
2579 aStr.append(static_cast<sal_Int32>(pAction->GetType()));
2580 aStr.append('!');
2581 OSL_FAIL(aStr.getStr());
2583 #endif
2584 break;
2588 return nCount;
2591 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */