1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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>
40 static void ImplReadRect( SvStream
& rIStm
, tools::Rectangle
& rRect
)
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
);
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");
67 rPoly
= tools::Polygon(nSize
);
69 for (sal_uInt16 i
= 0; i
< nSize
&& rIStm
.good(); ++i
)
71 aSerializer
.readPoint(rPoly
[i
]);
76 static bool ImplReadPolyPoly(SvStream
& rIStm
, tools::PolyPolygon
& rPolyPoly
)
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
))
92 rPolyPoly
.Insert(aPoly
);
95 return bSuccess
&& rIStm
.good();
98 static void ImplReadColor( SvStream
& rIStm
, Color
& rColor
)
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
)
110 rIStm
.ReadInt16(nUnit
);
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");
125 if (nUnit
< sal_Int16(MapUnit::Map100thMM
) || nUnit
> sal_Int16(MapUnit::LAST
))
127 SAL_WARN("vcl.gdi", "Parsing error: invalid mapmode");
131 rMapMode
= MapMode(static_cast<MapUnit
>(nUnit
), aOrg
, Fraction(nXNum
, nXDenom
), Fraction(nYNum
, nYDenom
));
136 static void ImplReadUnicodeComment( sal_uInt32 nStrmPos
, SvStream
& rIStm
, OUString
& rString
)
138 sal_uInt32 nOld
= rIStm
.Tell();
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
);
157 static void ImplSkipActions(SvStream
& rIStm
, sal_uLong nSkipCount
)
159 sal_Int32 nActionSize
;
161 for (sal_uLong i
= 0; i
< nSkipCount
; ++i
)
163 rIStm
.ReadInt16(nType
).ReadInt32(nActionSize
);
164 if (!rIStm
.good() || nActionSize
< 4)
166 rIStm
.SeekRel(nActionSize
- 4);
170 static void ImplReadExtendedPolyPolygonAction(SvStream
& rIStm
, tools::PolyPolygon
& rPolyPoly
)
172 TypeSerializer
aSerializer(rIStm
);
175 sal_uInt16
nPolygonCount(0);
176 rIStm
.ReadUInt16( nPolygonCount
);
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
);
208 for(sal_uInt16
b(0); b
< nPointCount
; b
++)
210 aSerializer
.readPoint(aCandidate
[b
]);
213 sal_uInt8
bHasFlags(int(false));
214 rIStm
.ReadUChar( 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
);
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
);
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
);
271 rIStm
.ReadBytes(aCode
, sizeof(aCode
)); // Identifier
273 rIStm
.ReadInt16( nSize
); // Size
274 sal_Int16
nVersion(0);
275 rIStm
.ReadInt16( nVersion
); // Version
277 rIStm
.ReadInt32( nTmp32
);
280 SAL_WARN("vcl.gdi", "svm: value for width should be positive");
281 lcl_error(rIStm
, nOldFormat
, nPos
);
284 aPrefSz
.setWidth( nTmp32
); // PrefSize.Width()
285 rIStm
.ReadInt32( nTmp32
);
288 SAL_WARN("vcl.gdi", "svm: value for height should be positive");
289 lcl_error(rIStm
, nOldFormat
, nPos
);
292 aPrefSz
.setHeight( nTmp32
); // PrefSize.Height()
294 // check header-magic and version
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
);
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
;
316 sal_uInt32 nUnicodeCommentStreamPos
= 0;
317 sal_Int32 nUnicodeCommentActionNumber
= 0;
319 rMtf
.SetPrefSize(aPrefSz
);
322 if (ImplReadMapMode(rIStm
, aMapMode
)) // MapMode
323 rMtf
.SetPrefMapMode(aMapMode
);
325 sal_Int32
nActions(0);
326 rIStm
.ReadInt32(nActions
); // Action count
329 SAL_WARN("vcl.gdi", "svm claims negative action count (" << nActions
<< ")");
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
)
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!" );
357 case GDI_PIXEL_ACTION
:
359 aSerializer
.readPoint(aPt
);
360 ImplReadColor( rIStm
, aActionColor
);
361 rMtf
.AddAction( new MetaPixelAction( aPt
, aActionColor
) );
365 case GDI_POINT_ACTION
:
367 aSerializer
.readPoint(aPt
);
368 rMtf
.AddAction( new MetaPointAction( aPt
) );
372 case GDI_LINE_ACTION
:
374 aSerializer
.readPoint(aPt
);
375 aSerializer
.readPoint(aPt1
);
376 rMtf
.AddAction( new MetaLineAction( aPt
, aPt1
, aLineInfo
) );
380 case GDI_LINEJOIN_ACTION
:
382 sal_Int16
nLineJoin(0);
383 rIStm
.ReadInt16( nLineJoin
);
384 aLineInfo
.SetLineJoin(static_cast<basegfx::B2DLineJoin
>(nLineJoin
));
388 case GDI_LINECAP_ACTION
:
390 sal_Int16
nLineCap(0);
391 rIStm
.ReadInt16( nLineCap
);
392 aLineInfo
.SetLineCap(static_cast<css::drawing::LineCap
>(nLineCap
));
396 case GDI_LINEDASHDOT_ACTION
:
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
);
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
));
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())
435 new MetaPolyLineAction(
436 aInputPolyPolygon
.GetObject(0),
437 pPolyLineAction
->GetLineInfo()),
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())
452 new MetaPolyPolygonAction(
459 MetaPolygonAction
* pPolygonAction
= dynamic_cast< MetaPolygonAction
* >(rMtf
.GetAction(nLastPolygonAction
));
463 // replace MetaPolygonAction
464 if(1 == aInputPolyPolygon
.Count())
467 new MetaPolygonAction(
468 aInputPolyPolygon
.GetObject(0)),
478 case GDI_RECT_ACTION
:
480 ImplReadRect( rIStm
, aRect
);
481 sal_Int32
nTmp(0), nTmp1(0);
482 rIStm
.ReadInt32( nTmp
).ReadInt32( nTmp1
);
485 rMtf
.AddAction( new MetaRoundRectAction( aRect
, nTmp
, nTmp1
) );
488 rMtf
.AddAction( new MetaRectAction( aRect
) );
491 rMtf
.AddAction( new MetaPolyLineAction( aRect
, aLineInfo
) );
496 case GDI_ELLIPSE_ACTION
:
498 ImplReadRect( rIStm
, aRect
);
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
) );
511 rMtf
.AddAction( new MetaEllipseAction( aRect
) );
517 ImplReadRect( rIStm
, aRect
);
518 aSerializer
.readPoint(aPt
);
519 aSerializer
.readPoint(aPt1
);
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
) );
532 rMtf
.AddAction( new MetaArcAction( aRect
, aPt
, aPt1
) );
538 ImplReadRect( rIStm
, aRect
);
539 aSerializer
.readPoint(aPt
);
540 aSerializer
.readPoint(aPt1
);
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
) );
553 rMtf
.AddAction( new MetaPieAction( aRect
, aPt
, aPt1
) );
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() );
568 case GDI_POLYLINE_ACTION
:
570 if (ImplReadPoly(rIStm
, aActionPoly
))
572 nLastPolygonAction
= rMtf
.GetActionSize();
575 rMtf
.AddAction( new MetaPolyLineAction( aActionPoly
, aLineInfo
) );
577 rMtf
.AddAction( new MetaPolyLineAction( aActionPoly
) );
582 case GDI_POLYGON_ACTION
:
584 if (ImplReadPoly(rIStm
, aActionPoly
))
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
) );
596 nLastPolygonAction
= rMtf
.GetActionSize();
597 rMtf
.AddAction( new MetaPolygonAction( aActionPoly
) );
603 case GDI_POLYPOLYGON_ACTION
:
605 tools::PolyPolygon aPolyPoly
;
607 if (ImplReadPolyPoly(rIStm
, aPolyPoly
))
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
) );
621 nLastPolygonAction
= rMtf
.GetActionSize();
622 rMtf
.AddAction( new MetaPolyPolygonAction( aPolyPoly
) );
628 case GDI_FONT_ACTION
:
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
);
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
);
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
);
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
);
698 rIStm
.Seek(nActBegin
+ nActionSize
);
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
);
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
;
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
);
743 pDXAry
.reset(new tools::Long
[nDXAryLen
]);
745 for (sal_Int32 j
= 0; j
< nAryLen
; ++j
)
747 rIStm
.ReadInt32( 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
768 pDXAry
[ nStrLen
-1 ] = pDXAry
[ nStrLen
-2 ] + pTmpAry
[ nStrLen
-1 ] - pTmpAry
[ nStrLen
-2 ];
770 pDXAry
[ nStrLen
-1 ] = pTmpAry
[ nStrLen
-1 ]; // len=1: 0th position taken to be 0
774 OSL_FAIL("More than one DX array element missing on SVM import");
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
);
787 rIStm
.Seek(nActBegin
+ nActionSize
);
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
);
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
);
813 rIStm
.Seek(nActBegin
+ nActionSize
);
817 case GDI_BITMAP_ACTION
:
821 aSerializer
.readPoint(aPt
);
822 ReadDIB(aBmp
, rIStm
, true);
823 rMtf
.AddAction( new MetaBmpAction( aPt
, aBmp
) );
827 case GDI_BITMAPSCALE_ACTION
:
831 aSerializer
.readPoint(aPt
);
832 aSerializer
.readSize(aSz
);
833 ReadDIB(aBmp
, rIStm
, true);
834 rMtf
.AddAction( new MetaBmpScaleAction( aPt
, aSz
, aBmp
) );
838 case GDI_BITMAPSCALEPART_ACTION
:
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
) );
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 ) );
868 case GDI_FILLBRUSH_ACTION
:
870 sal_Int16 nBrushStyle
;
872 ImplReadColor( rIStm
, aActionColor
);
874 rIStm
.ReadInt16( nBrushStyle
);
875 rMtf
.AddAction( new MetaFillColorAction( aActionColor
, nBrushStyle
!= 0 ) );
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
);
892 case GDI_CLIPREGION_ACTION
:
896 sal_Int16 bIntersect
;
899 rIStm
.ReadInt16( nRegType
).ReadInt16( bIntersect
);
900 ImplReadRect( rIStm
, aRect
);
909 tools::Rectangle aRegRect
;
911 ImplReadRect( rIStm
, aRegRect
);
912 aRegion
= vcl::Region( aRegRect
);
919 if (ImplReadPoly(rIStm
, aActionPoly
))
921 aRegion
= vcl::Region( aActionPoly
);
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
))
942 aPolyPoly
.Insert(aActionPoly
);
947 aRegion
= vcl::Region( aPolyPoly
);
955 aRegion
.Intersect( aRect
);
957 rMtf
.AddAction( new MetaClipRegionAction( aRegion
, bClip
) );
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
) );
969 case GDI_ISECTCLIPREGION_ACTION
:
971 ImplReadRect( rIStm
, aRect
);
972 rMtf
.AddAction( new MetaISectRectClipRegionAction( aRect
) );
976 case GDI_RASTEROP_ACTION
:
981 rIStm
.ReadInt16( nRasterOp
);
986 eRasterOp
= RasterOp::Invert
;
991 eRasterOp
= RasterOp::Xor
;
995 eRasterOp
= RasterOp::OverPaint
;
999 rMtf
.AddAction( new MetaRasterOpAction( eRasterOp
) );
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
1013 case GDI_POP_ACTION
:
1016 std::unique_ptr
<LineInfo
> xLineInfo
;
1017 if (!aLIStack
.empty())
1019 xLineInfo
= std::move(aLIStack
.top());
1023 // restore line info
1026 aLineInfo
= *xLineInfo
;
1028 bFatLine
= ( LineStyle::NONE
!= aLineInfo
.GetStyle() ) && !aLineInfo
.IsDefault();
1031 rMtf
.AddAction( new MetaPopAction() );
1033 // #106172# Track font relevant data in shadow VDev
1038 case GDI_GRADIENT_ACTION
:
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
) );
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
);
1083 case GDI_FLOATTRANSPARENT_COMMENT
:
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
);
1103 case GDI_HATCH_COMMENT
:
1105 tools::PolyPolygon aPolyPoly
;
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
);
1119 case GDI_REFPOINT_COMMENT
:
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
1134 aFontVDev
->SetRefPoint( aRefPoint
);
1136 aFontVDev
->SetRefPoint();
1140 case GDI_TEXTLINECOLOR_COMMENT
:
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
);
1155 case GDI_TEXTLINE_COMMENT
:
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
),
1171 i
= SkipActions(i
, nFollowingActionCount
, nActions
);
1175 case GDI_GRADIENTEX_COMMENT
:
1177 tools::PolyPolygon aPolyPoly
;
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
);
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
);
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
);
1221 case GDI_UNICODE_COMMENT
:
1223 nUnicodeCommentActionNumber
= i
+ 1;
1224 nUnicodeCommentStreamPos
= rIStm
.Tell() - 6;
1225 if (nActionSize
< 4)
1226 rIStm
.SetError(SVSTREAM_FILEFORMAT_ERROR
);
1228 rIStm
.SeekRel(nActionSize
- 4);
1233 if (nActionSize
< 4)
1234 rIStm
.SetError(SVSTREAM_FILEFORMAT_ERROR
);
1236 rIStm
.SeekRel(nActionSize
- 4);
1241 rIStm
.SetEndian( nOldFormat
);
1244 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */