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 .
20 #include <mtftools.hxx>
24 #include <basegfx/matrix/b2dhommatrix.hxx>
25 #include <basegfx/polygon/b2dpolypolygontools.hxx>
26 #include <vcl/graphictools.hxx>
27 #include <vcl/BitmapTools.hxx>
28 #include <vcl/metaact.hxx>
29 #include <vcl/canvastools.hxx>
30 #include <vcl/svapp.hxx>
31 #include <tools/fract.hxx>
32 #include <rtl/strbuf.hxx>
33 #include <rtl/tencinfo.h>
34 #include <vcl/virdev.hxx>
35 #include <o3tl/make_unique.hxx>
36 #include <o3tl/safeint.hxx>
37 #include <officecfg/Setup.hxx>
38 #include <officecfg/Office/Linguistic.hxx>
39 #include <unotools/configmgr.hxx>
40 #include <unotools/wincodepage.hxx>
41 #include <tools/helpers.hxx>
42 #include <vcl/bitmapaccess.hxx>
44 #if OSL_DEBUG_LEVEL > 1
45 #define EMFP_DEBUG(x) x
52 SvStream
& operator >> (SvStream
& rInStream
, XForm
& rXForm
)
54 if (sizeof(float) != 4)
56 OSL_FAIL("EmfReader::sizeof( float ) != 4");
61 rInStream
.ReadFloat(rXForm
.eM11
);
62 rInStream
.ReadFloat(rXForm
.eM12
);
63 rInStream
.ReadFloat(rXForm
.eM21
);
64 rInStream
.ReadFloat(rXForm
.eM22
);
65 rInStream
.ReadFloat(rXForm
.eDx
);
66 rInStream
.ReadFloat(rXForm
.eDy
);
71 void WinMtfClipPath::intersectClipRect( const tools::Rectangle
& rRect
)
73 maClip
.intersectRange(
74 vcl::unotools::b2DRectangleFromRectangle(rRect
));
77 void WinMtfClipPath::excludeClipRect( const tools::Rectangle
& rRect
)
80 vcl::unotools::b2DRectangleFromRectangle(rRect
));
83 void WinMtfClipPath::setClipPath( const tools::PolyPolygon
& rPolyPolygon
, sal_Int32 nClippingMode
)
85 const basegfx::B2DPolyPolygon
& rB2DPoly
=rPolyPolygon
.getB2DPolyPolygon();
86 switch ( nClippingMode
)
89 maClip
.unionPolyPolygon(rB2DPoly
);
92 maClip
.xorPolyPolygon(rB2DPoly
);
95 maClip
.subtractPolyPolygon(rB2DPoly
);
98 maClip
.intersectPolyPolygon(rB2DPoly
);
101 maClip
= basegfx::utils::B2DClipState(rB2DPoly
);
106 void WinMtfClipPath::moveClipRegion( const Size
& rSize
)
108 basegfx::B2DHomMatrix aTranslate
;
109 aTranslate
.translate(rSize
.Width(), rSize
.Height());
110 maClip
.transform(aTranslate
);
113 void WinMtfClipPath::setDefaultClipPath()
115 // Empty clip region - everything visible
116 maClip
= basegfx::utils::B2DClipState();
119 basegfx::B2DPolyPolygon
const & WinMtfClipPath::getClipPath() const
121 return maClip
.getClipPoly();
124 void WinMtfPathObj::AddPoint( const Point
& rPoint
)
127 Insert( tools::Polygon() );
128 tools::Polygon
& rPoly
= static_cast<tools::PolyPolygon
&>(*this)[ Count() - 1 ];
129 rPoly
.Insert( rPoly
.GetSize(), rPoint
);
133 void WinMtfPathObj::AddPolyLine( const tools::Polygon
& rPolyLine
)
136 Insert( tools::Polygon() );
137 tools::Polygon
& rPoly
= static_cast<tools::PolyPolygon
&>(*this)[ Count() - 1 ];
138 rPoly
.Insert( rPoly
.GetSize(), rPolyLine
);
142 void WinMtfPathObj::AddPolygon( const tools::Polygon
& rPoly
)
148 void WinMtfPathObj::AddPolyPolygon( const tools::PolyPolygon
& rPolyPoly
)
150 sal_uInt16 i
, nCount
= rPolyPoly
.Count();
151 for ( i
= 0; i
< nCount
; i
++ )
152 Insert( rPolyPoly
[ i
] );
156 void WinMtfPathObj::ClosePath()
160 tools::Polygon
& rPoly
= static_cast<tools::PolyPolygon
&>(*this)[ Count() - 1 ];
161 if ( rPoly
.GetSize() > 2 )
163 Point
aFirst( rPoly
[ 0 ] );
164 if ( aFirst
!= rPoly
[ rPoly
.GetSize() - 1 ] )
165 rPoly
.Insert( rPoly
.GetSize(), aFirst
);
173 OUString
getLODefaultLanguage()
175 if (utl::ConfigManager::IsFuzzing())
176 return OUString("en-US");
177 OUString
result(officecfg::Office::Linguistic::General::DefaultLocale::get());
178 if (result
.isEmpty())
179 result
= officecfg::Setup::L10N::ooSetupSystemLocale::get();
185 WinMtfFontStyle::WinMtfFontStyle( LOGFONTW
const & rFont
)
187 rtl_TextEncoding eCharSet
;
188 if ((rFont
.alfFaceName
== "Symbol")
189 || (rFont
.alfFaceName
== "MT Extra"))
190 eCharSet
= RTL_TEXTENCODING_SYMBOL
;
191 else if ((rFont
.lfCharSet
== DEFAULT_CHARSET
) || (rFont
.lfCharSet
== OEM_CHARSET
))
192 eCharSet
= utl_getWinTextEncodingFromLangStr(getLODefaultLanguage().toUtf8().getStr(),
193 rFont
.lfCharSet
== OEM_CHARSET
);
195 eCharSet
= rtl_getTextEncodingFromWindowsCharset( rFont
.lfCharSet
);
196 if ( eCharSet
== RTL_TEXTENCODING_DONTKNOW
)
197 eCharSet
= RTL_TEXTENCODING_MS_1252
;
198 aFont
.SetCharSet( eCharSet
);
199 aFont
.SetFamilyName( rFont
.alfFaceName
);
201 switch ( rFont
.lfPitchAndFamily
& 0xf0 )
204 eFamily
= FAMILY_ROMAN
;
208 eFamily
= FAMILY_SWISS
;
212 eFamily
= FAMILY_MODERN
;
216 eFamily
= FAMILY_SCRIPT
;
220 eFamily
= FAMILY_DECORATIVE
;
224 eFamily
= FAMILY_DONTKNOW
;
227 aFont
.SetFamily( eFamily
);
230 switch ( rFont
.lfPitchAndFamily
& 0x0f )
233 ePitch
= PITCH_FIXED
;
239 ePitch
= PITCH_VARIABLE
;
242 aFont
.SetPitch( ePitch
);
245 if (rFont
.lfWeight
== 0) // default weight SHOULD be used
246 eWeight
= WEIGHT_DONTKNOW
;
247 else if (rFont
.lfWeight
<= FW_THIN
)
248 eWeight
= WEIGHT_THIN
;
249 else if( rFont
.lfWeight
<= FW_ULTRALIGHT
)
250 eWeight
= WEIGHT_ULTRALIGHT
;
251 else if( rFont
.lfWeight
<= FW_LIGHT
)
252 eWeight
= WEIGHT_LIGHT
;
253 else if( rFont
.lfWeight
< FW_MEDIUM
)
254 eWeight
= WEIGHT_NORMAL
;
255 else if( rFont
.lfWeight
== FW_MEDIUM
)
256 eWeight
= WEIGHT_MEDIUM
;
257 else if( rFont
.lfWeight
<= FW_SEMIBOLD
)
258 eWeight
= WEIGHT_SEMIBOLD
;
259 else if( rFont
.lfWeight
<= FW_BOLD
)
260 eWeight
= WEIGHT_BOLD
;
261 else if( rFont
.lfWeight
<= FW_ULTRABOLD
)
262 eWeight
= WEIGHT_ULTRABOLD
;
264 eWeight
= WEIGHT_BLACK
;
265 aFont
.SetWeight( eWeight
);
268 aFont
.SetItalic( ITALIC_NORMAL
);
270 if( rFont
.lfUnderline
)
271 aFont
.SetUnderline( LINESTYLE_SINGLE
);
273 if( rFont
.lfStrikeOut
)
274 aFont
.SetStrikeout( STRIKEOUT_SINGLE
);
276 aFont
.SetOrientation( static_cast<short>(rFont
.lfEscapement
) );
278 Size
aFontSize( Size( rFont
.lfWidth
, rFont
.lfHeight
) );
279 if ( rFont
.lfHeight
> 0 )
281 // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
282 SolarMutexGuard aGuard
;
283 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
284 // converting the cell height into a font height
285 aFont
.SetFontSize( aFontSize
);
286 pVDev
->SetFont( aFont
);
287 FontMetric
aMetric( pVDev
->GetFontMetric() );
288 long nHeight
= aMetric
.GetAscent() + aMetric
.GetDescent();
291 double fHeight
= (static_cast<double>(aFontSize
.Height()) * rFont
.lfHeight
) / nHeight
;
292 aFontSize
.setHeight( static_cast<sal_Int32
>( fHeight
+ 0.5 ) );
296 // Convert height to positive
297 aFontSize
.setHeight( std::abs(aFontSize
.Height()) );
299 aFont
.SetFontSize(aFontSize
);
302 Color
MtfTools::ReadColor()
306 mpInputStream
->ReadUInt32( nColor
);
307 return Color( static_cast<sal_uInt8
>(nColor
), static_cast<sal_uInt8
>( nColor
>> 8 ), static_cast<sal_uInt8
>( nColor
>> 16 ) );
310 Point
MtfTools::ImplScale(const Point
& rPoint
) // Hack to set varying defaults for incompletely defined files.
313 return Point(rPoint
.X() * UNDOCUMENTED_WIN_RCL_RELATION
- mrclFrame
.Left(),
314 rPoint
.Y() * UNDOCUMENTED_WIN_RCL_RELATION
- mrclFrame
.Top());
319 Point
MtfTools::ImplMap( const Point
& rPt
)
321 if ( mnWinExtX
&& mnWinExtY
)
326 double fX2
= fX
* maXForm
.eM11
+ fY
* maXForm
.eM21
+ maXForm
.eDx
;
327 double fY2
= fX
* maXForm
.eM12
+ fY
* maXForm
.eM22
+ maXForm
.eDy
;
329 if ( mnGfxMode
== GM_COMPATIBLE
)
337 fX2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
*10;
338 fY2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
*10;
347 fX2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
;
348 fY2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
;
357 fX2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
/MILLIINCH_PER_TWIPS
;
358 fY2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
/MILLIINCH_PER_TWIPS
;
373 case MM_HIMETRIC
: // in hundredth of a millimeter
383 if (mnPixX
== 0 || mnPixY
== 0)
385 SAL_WARN("emfio", "invalid scaling factor");
397 fY2
+= mnDevOrgY
; // fX2, fY2 now in device units
398 fX2
*= static_cast<double>(mnMillX
) * 100.0 / static_cast<double>(mnPixX
);
399 fY2
*= static_cast<double>(mnMillY
) * 100.0 / static_cast<double>(mnPixY
);
404 fX2
-= mrclFrame
.Left();
405 fY2
-= mrclFrame
.Top();
407 return Point(basegfx::fround(fX2
), basegfx::fround(fY2
));
413 Size
MtfTools::ImplMap(const Size
& rSz
, bool bDoWorldTransform
)
415 if ( mnWinExtX
&& mnWinExtY
)
417 // #i121382# apply the whole WorldTransform, else a rotation will be misinterpreted
418 double fWidth
, fHeight
;
419 if (bDoWorldTransform
)
421 fWidth
= rSz
.Width() * maXForm
.eM11
+ rSz
.Height() * maXForm
.eM21
;
422 fHeight
= rSz
.Width() * maXForm
.eM12
+ rSz
.Height() * maXForm
.eM22
;
426 //take the scale, but not the rotation
427 basegfx::B2DHomMatrix
aMatrix(maXForm
.eM11
, maXForm
.eM12
, 0,
428 maXForm
.eM21
, maXForm
.eM22
, 0);
429 basegfx::B2DTuple aScale
, aTranslate
;
430 double fRotate
, fShearX
;
431 if (!aMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
))
436 fWidth
= rSz
.Width() * aScale
.getX();
437 fHeight
= rSz
.Height() * aScale
.getY();
440 if ( mnGfxMode
== GM_COMPATIBLE
)
446 fWidth
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
*10;
447 fHeight
*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH
*10;
452 fWidth
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
;
453 fHeight
*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH
;
462 case MM_HIMETRIC
: // in hundredth of millimeters
469 fWidth
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
/MILLIINCH_PER_TWIPS
;
470 fHeight
*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH
/MILLIINCH_PER_TWIPS
;
475 if (mnPixX
== 0 || mnPixY
== 0)
477 SAL_WARN("emfio", "invalid scaling factor");
483 fHeight
/= mnWinExtY
;
484 fWidth
*= mnDevWidth
;
485 fHeight
*= mnDevHeight
;
486 fWidth
*= static_cast<double>(mnMillX
) * 100.0 / static_cast<double>(mnPixX
);
487 fHeight
*= static_cast<double>(mnMillY
) * 100.0 / static_cast<double>(mnPixY
);
493 return Size(basegfx::fround(fWidth
), basegfx::fround(fHeight
));
499 tools::Rectangle
MtfTools::ImplMap( const tools::Rectangle
& rRect
)
501 tools::Rectangle aRect
;
502 aRect
.SetPos(ImplMap(rRect
.TopLeft()));
503 aRect
.SaturatingSetSize(ImplMap(rRect
.GetSize()));
507 void MtfTools::ImplMap( vcl::Font
& rFont
)
509 // !!! HACK: we now always set the width to zero because the OS width is interpreted differently;
510 // must later be made portable in SV (KA 1996-02-08)
511 Size aFontSize
= ImplMap (rFont
.GetFontSize(), false);
513 const auto nHeight
= aFontSize
.Height();
515 aFontSize
.setHeight( o3tl::saturating_toggle_sign(nHeight
) );
517 rFont
.SetFontSize( aFontSize
);
520 const bool bFail
= o3tl::checked_multiply(mnWinExtX
, mnWinExtY
, nResult
);
521 if (!bFail
&& nResult
< 0)
522 rFont
.SetOrientation( 3600 - rFont
.GetOrientation() );
525 tools::Polygon
& MtfTools::ImplMap( tools::Polygon
& rPolygon
)
527 sal_uInt16 nPoints
= rPolygon
.GetSize();
528 for ( sal_uInt16 i
= 0; i
< nPoints
; i
++ )
530 rPolygon
[ i
] = ImplMap( rPolygon
[ i
] );
535 void MtfTools::ImplScale( tools::Polygon
& rPolygon
)
537 sal_uInt16 nPoints
= rPolygon
.GetSize();
538 for ( sal_uInt16 i
= 0; i
< nPoints
; i
++ )
540 rPolygon
[ i
] = ImplScale( rPolygon
[ i
] );
544 tools::PolyPolygon
& MtfTools::ImplScale( tools::PolyPolygon
& rPolyPolygon
)
546 sal_uInt16 nPolys
= rPolyPolygon
.Count();
547 for (sal_uInt16 i
= 0; i
< nPolys
; ++i
)
549 ImplScale(rPolyPolygon
[i
]);
554 tools::PolyPolygon
& MtfTools::ImplMap( tools::PolyPolygon
& rPolyPolygon
)
556 sal_uInt16 nPolys
= rPolyPolygon
.Count();
557 for ( sal_uInt16 i
= 0; i
< nPolys
; ImplMap( rPolyPolygon
[ i
++ ] ) ) ;
561 void MtfTools::SelectObject( sal_Int32 nIndex
)
563 if ( nIndex
& ENHMETA_STOCK_OBJECT
)
565 sal_uInt16 nStockId
= static_cast<sal_uInt8
>(nIndex
);
570 maFillStyle
= WinMtfFillStyle( COL_WHITE
);
571 mbFillStyleSelected
= true;
576 maFillStyle
= WinMtfFillStyle( COL_LIGHTGRAY
);
577 mbFillStyleSelected
= true;
583 maFillStyle
= WinMtfFillStyle( COL_GRAY
);
584 mbFillStyleSelected
= true;
589 maFillStyle
= WinMtfFillStyle( COL_BLACK
);
590 mbFillStyleSelected
= true;
595 maFillStyle
= WinMtfFillStyle( COL_TRANSPARENT
, true );
596 mbFillStyleSelected
= true;
601 maLineStyle
= WinMtfLineStyle( COL_WHITE
);
606 maLineStyle
= WinMtfLineStyle( COL_BLACK
);
611 maLineStyle
= WinMtfLineStyle( COL_TRANSPARENT
, true );
620 nIndex
&= 0xffff; // safety check: don't allow index to be > 65535
622 GDIObj
*pGDIObj
= nullptr;
624 if ( static_cast<sal_uInt32
>(nIndex
) < mvGDIObj
.size() )
625 pGDIObj
= mvGDIObj
[ nIndex
].get();
629 if (const auto pen
= dynamic_cast<WinMtfLineStyle
*>(pGDIObj
))
631 else if (const auto brush
= dynamic_cast<WinMtfFillStyle
*>(
634 maFillStyle
= *brush
;
635 mbFillStyleSelected
= true;
637 else if (const auto font
= dynamic_cast<WinMtfFontStyle
*>(
640 maFont
= font
->aFont
;
646 void MtfTools::SetTextLayoutMode( ComplexTextLayoutFlags nTextLayoutMode
)
648 mnTextLayoutMode
= nTextLayoutMode
;
651 void MtfTools::SetBkMode( BkMode nMode
)
656 void MtfTools::SetBkColor( const Color
& rColor
)
661 void MtfTools::SetTextColor( const Color
& rColor
)
663 maTextColor
= rColor
;
666 void MtfTools::SetTextAlign( sal_uInt32 nAlign
)
668 mnTextAlign
= nAlign
;
671 void MtfTools::ImplResizeObjectArry( sal_uInt32 nNewEntrys
)
673 mvGDIObj
.resize(nNewEntrys
);
676 void MtfTools::ImplDrawClippedPolyPolygon( const tools::PolyPolygon
& rPolyPoly
)
678 if ( rPolyPoly
.Count() )
680 ImplSetNonPersistentLineColorTransparenz();
681 if ( rPolyPoly
.Count() == 1 )
683 if ( rPolyPoly
.IsRect() )
684 mpGDIMetaFile
->AddAction( new MetaRectAction( rPolyPoly
.GetBoundRect() ) );
687 tools::Polygon
aPoly( rPolyPoly
[ 0 ] );
688 sal_uInt16 nCount
= aPoly
.GetSize();
691 if ( aPoly
[ nCount
- 1 ] != aPoly
[ 0 ] )
693 Point
aPoint( aPoly
[ 0 ] );
694 aPoly
.Insert( nCount
, aPoint
);
696 mpGDIMetaFile
->AddAction( new MetaPolygonAction( aPoly
) );
701 mpGDIMetaFile
->AddAction( new MetaPolyPolygonAction( rPolyPoly
) );
705 void MtfTools::CreateObject( std::unique_ptr
<GDIObj
> pObject
)
709 const auto pLineStyle
= dynamic_cast<WinMtfLineStyle
*>(pObject
.get());
710 const auto pFontStyle
= dynamic_cast<WinMtfFontStyle
*>(pObject
.get());
714 if (pFontStyle
->aFont
.GetFontHeight() == 0)
715 pFontStyle
->aFont
.SetFontHeight(423);
716 ImplMap(pFontStyle
->aFont
); // defaulting to 12pt
718 else if ( pLineStyle
)
720 Size
aSize(pLineStyle
->aLineInfo
.GetWidth(), 0);
721 aSize
= ImplMap(aSize
);
722 pLineStyle
->aLineInfo
.SetWidth(aSize
.Width());
725 std::vector
<std::unique_ptr
<GDIObj
>>::size_type nIndex
;
726 for ( nIndex
= 0; nIndex
< mvGDIObj
.size(); nIndex
++ )
728 if ( !mvGDIObj
[ nIndex
] )
731 if ( nIndex
== mvGDIObj
.size() )
732 ImplResizeObjectArry( mvGDIObj
.size() + 16 );
734 mvGDIObj
[ nIndex
] = std::move(pObject
);
737 void MtfTools::CreateObjectIndexed( sal_Int32 nIndex
, std::unique_ptr
<GDIObj
> pObject
)
739 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
741 nIndex
&= 0xffff; // safety check: do not allow index to be > 65535
744 const auto pLineStyle
= dynamic_cast<WinMtfLineStyle
*>(pObject
.get());
745 const auto pFontStyle
= dynamic_cast<WinMtfFontStyle
*>(pObject
.get());
748 if (pFontStyle
->aFont
.GetFontHeight() == 0)
749 pFontStyle
->aFont
.SetFontHeight(423);
750 ImplMap(pFontStyle
->aFont
);
752 else if ( pLineStyle
)
754 Size
aSize(pLineStyle
->aLineInfo
.GetWidth(), 0);
755 pLineStyle
->aLineInfo
.SetWidth( ImplMap(aSize
).Width() );
757 if ( pLineStyle
->aLineInfo
.GetStyle() == LineStyle::Dash
)
759 aSize
.AdjustWidth(1 );
760 long nDotLen
= ImplMap( aSize
).Width();
761 pLineStyle
->aLineInfo
.SetDistance( nDotLen
);
762 pLineStyle
->aLineInfo
.SetDotLen( nDotLen
);
763 pLineStyle
->aLineInfo
.SetDashLen( nDotLen
* 3 );
767 if ( static_cast<sal_uInt32
>(nIndex
) >= mvGDIObj
.size() )
768 ImplResizeObjectArry( nIndex
+ 16 );
770 mvGDIObj
[ nIndex
] = std::move(pObject
);
774 void MtfTools::CreateObject()
776 CreateObject(o3tl::make_unique
<GDIObj
>());
779 void MtfTools::DeleteObject( sal_Int32 nIndex
)
781 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
783 if ( static_cast<sal_uInt32
>(nIndex
) < mvGDIObj
.size() )
785 mvGDIObj
[ nIndex
].reset();
790 void MtfTools::IntersectClipRect( const tools::Rectangle
& rRect
)
792 if (utl::ConfigManager::IsFuzzing())
794 mbClipNeedsUpdate
=true;
795 if ((rRect
.Left()-rRect
.Right()==0) && (rRect
.Top()-rRect
.Bottom()==0))
797 return; // empty rectangles cause trouble
799 maClipPath
.intersectClipRect( ImplMap( rRect
) );
802 void MtfTools::ExcludeClipRect( const tools::Rectangle
& rRect
)
804 if (utl::ConfigManager::IsFuzzing())
806 mbClipNeedsUpdate
=true;
807 maClipPath
.excludeClipRect( ImplMap( rRect
) );
810 void MtfTools::MoveClipRegion( const Size
& rSize
)
812 if (utl::ConfigManager::IsFuzzing())
814 mbClipNeedsUpdate
=true;
815 maClipPath
.moveClipRegion( ImplMap( rSize
) );
818 void MtfTools::SetClipPath( const tools::PolyPolygon
& rPolyPolygon
, sal_Int32 nClippingMode
, bool bIsMapped
)
820 if (utl::ConfigManager::IsFuzzing())
822 mbClipNeedsUpdate
= true;
823 tools::PolyPolygon
aPolyPolygon(rPolyPolygon
);
827 if (!mbIsMapDevSet
&& (mnMapMode
== MM_ISOTROPIC
|| mnMapMode
== MM_ANISOTROPIC
))
828 aPolyPolygon
= ImplScale(aPolyPolygon
);
830 aPolyPolygon
= ImplMap(aPolyPolygon
);
832 maClipPath
.setClipPath(aPolyPolygon
, nClippingMode
);
835 void MtfTools::SetDefaultClipPath()
837 mbClipNeedsUpdate
= true;
838 maClipPath
.setDefaultClipPath();
841 MtfTools::MtfTools( GDIMetaFile
& rGDIMetaFile
, SvStream
& rStreamWMF
)
852 mnLatestTextAlign(90),
853 mnTextAlign(TA_LEFT
| TA_TOP
| TA_NOUPDATECP
),
856 maLatestBkColor(0x12345678),
857 maBkColor(COL_WHITE
),
858 mnLatestTextLayoutMode(ComplexTextLayoutFlags::Default
),
859 mnTextLayoutMode(ComplexTextLayoutFlags::Default
),
860 mnLatestBkMode(BkMode::NONE
),
861 mnBkMode(BkMode::OPAQUE
),
862 meLatestRasterOp(RasterOp::Invert
),
863 meRasterOp(RasterOp::OverPaint
),
868 mnGfxMode(GM_COMPATIBLE
),
885 mpGDIMetaFile(&rGDIMetaFile
),
886 mpInputStream(&rStreamWMF
),
891 mbFillStyleSelected(false),
892 mbClipNeedsUpdate(true),
893 mbComplexClip(false),
894 mbIsMapWinSet(false),
897 SvLockBytes
*pLB
= mpInputStream
->GetLockBytes();
901 pLB
->SetSynchronMode();
904 mnStartPos
= mpInputStream
->Tell();
907 mpGDIMetaFile
->AddAction( new MetaPushAction( PushFlags::CLIPREGION
) ); // The original clipregion has to be on top
908 // of the stack so it can always be restored
909 // this is necessary to be able to support
910 // SetClipRgn( NULL ) and similar ClipRgn actions (SJ)
912 maFont
.SetFamilyName( "Arial" ); // sj: #i57205#, we do have some scaling problems if using
913 maFont
.SetCharSet( RTL_TEXTENCODING_MS_1252
); // the default font then most times a x11 font is used, we
914 maFont
.SetFontHeight( 423 ); // will prevent this defining a font
916 maLatestLineStyle
.aLineColor
= Color( 0x12, 0x34, 0x56 );
917 maLatestFillStyle
.aFillColor
= Color( 0x12, 0x34, 0x56 );
919 mnRop
= WMFRasterOp::Black
;
920 meRasterOp
= RasterOp::OverPaint
;
921 mpGDIMetaFile
->AddAction( new MetaRasterOpAction( RasterOp::OverPaint
) );
924 MtfTools::~MtfTools() COVERITY_NOEXCEPT_FALSE
926 mpGDIMetaFile
->AddAction( new MetaPopAction() );
927 mpGDIMetaFile
->SetPrefMapMode(MapMode(MapUnit::Map100thMM
));
928 if ( mrclFrame
.IsEmpty() )
929 mpGDIMetaFile
->SetPrefSize( Size( mnDevWidth
, mnDevHeight
) );
931 mpGDIMetaFile
->SetPrefSize( mrclFrame
.GetSize() );
934 void MtfTools::UpdateClipRegion()
936 if (mbClipNeedsUpdate
)
938 mbClipNeedsUpdate
= false;
939 mbComplexClip
= false;
941 mpGDIMetaFile
->AddAction( new MetaPopAction() ); // taking the original clipregion
942 mpGDIMetaFile
->AddAction( new MetaPushAction( PushFlags::CLIPREGION
) );
944 // skip for 'no clipping at all' case
945 if( !maClipPath
.isEmpty() )
947 const basegfx::B2DPolyPolygon
& rClipPoly( maClipPath
.getClipPath() );
949 mbComplexClip
= rClipPoly
.count() > 1
950 || !basegfx::utils::isRectangle(rClipPoly
);
952 static bool bEnableComplexClipViaRegion
= getenv("SAL_WMF_COMPLEXCLIP_VIA_REGION") != nullptr;
954 if (bEnableComplexClipViaRegion
)
956 //this makes cases like tdf#45820 work in reasonable time, and I feel in theory should
957 //be just fine. In practice I see the output is different so needs work before its the
958 //default, but for file fuzzing it should be good enough
961 mpGDIMetaFile
->AddAction(
962 new MetaISectRegionClipRegionAction(
963 vcl::Region(rClipPoly
)));
964 mbComplexClip
= false;
968 mpGDIMetaFile
->AddAction(
969 new MetaISectRectClipRegionAction(
970 vcl::unotools::rectangleFromB2DRectangle(
971 rClipPoly
.getB2DRange())));
977 mpGDIMetaFile
->AddAction(
978 new MetaISectRectClipRegionAction(
979 vcl::unotools::rectangleFromB2DRectangle(
980 rClipPoly
.getB2DRange())));
986 void MtfTools::ImplSetNonPersistentLineColorTransparenz()
988 WinMtfLineStyle
aTransparentLine( COL_TRANSPARENT
, true );
989 if ( ! ( maLatestLineStyle
== aTransparentLine
) )
991 maLatestLineStyle
= aTransparentLine
;
992 mpGDIMetaFile
->AddAction( new MetaLineColorAction( aTransparentLine
.aLineColor
, !aTransparentLine
.bTransparent
) );
996 void MtfTools::UpdateLineStyle()
998 if (!( maLatestLineStyle
== maLineStyle
) )
1000 maLatestLineStyle
= maLineStyle
;
1001 mpGDIMetaFile
->AddAction( new MetaLineColorAction( maLineStyle
.aLineColor
, !maLineStyle
.bTransparent
) );
1005 void MtfTools::UpdateFillStyle()
1007 if ( !mbFillStyleSelected
) // SJ: #i57205# taking care of bkcolor if no brush is selected
1008 maFillStyle
= WinMtfFillStyle( maBkColor
, mnBkMode
== BkMode::Transparent
);
1009 if (!( maLatestFillStyle
== maFillStyle
) )
1011 maLatestFillStyle
= maFillStyle
;
1012 if (maFillStyle
.aType
== WinMtfFillStyleType::Solid
)
1013 mpGDIMetaFile
->AddAction( new MetaFillColorAction( maFillStyle
.aFillColor
, !maFillStyle
.bTransparent
) );
1017 WMFRasterOp
MtfTools::SetRasterOp( WMFRasterOp nRasterOp
)
1019 WMFRasterOp nRetROP
= mnRop
;
1020 if ( nRasterOp
!= mnRop
)
1024 if ( mbNopMode
&& ( nRasterOp
!= WMFRasterOp::Nop
) )
1025 { // changing modes from WMFRasterOp::Nop so set pen and brush
1026 maFillStyle
= maNopFillStyle
;
1027 maLineStyle
= maNopLineStyle
;
1032 case WMFRasterOp::Not
:
1033 meRasterOp
= RasterOp::Invert
;
1036 case WMFRasterOp::XorPen
:
1037 meRasterOp
= RasterOp::Xor
;
1040 case WMFRasterOp::Nop
:
1042 meRasterOp
= RasterOp::OverPaint
;
1045 maNopFillStyle
= maFillStyle
;
1046 maNopLineStyle
= maLineStyle
;
1047 maFillStyle
= WinMtfFillStyle( COL_TRANSPARENT
, true );
1048 maLineStyle
= WinMtfLineStyle( COL_TRANSPARENT
, true );
1055 meRasterOp
= RasterOp::OverPaint
;
1059 if ( nRetROP
!= nRasterOp
)
1060 mpGDIMetaFile
->AddAction( new MetaRasterOpAction( meRasterOp
) );
1064 void MtfTools::StrokeAndFillPath( bool bStroke
, bool bFill
)
1066 if ( maPathObj
.Count() )
1075 mpGDIMetaFile
->AddAction( new MetaPushAction( PushFlags::LINECOLOR
) );
1076 mpGDIMetaFile
->AddAction( new MetaLineColorAction( Color(), false ) );
1078 if ( maPathObj
.Count() == 1 )
1079 mpGDIMetaFile
->AddAction( new MetaPolygonAction( maPathObj
.GetObject( 0 ) ) );
1081 mpGDIMetaFile
->AddAction( new MetaPolyPolygonAction( maPathObj
) );
1084 mpGDIMetaFile
->AddAction( new MetaPopAction() );
1088 sal_uInt16 i
, nCount
= maPathObj
.Count();
1089 for ( i
= 0; i
< nCount
; i
++ )
1090 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( maPathObj
[ i
], maLineStyle
.aLineInfo
) );
1096 void MtfTools::DrawPixel( const Point
& rSource
, const Color
& rColor
)
1098 mpGDIMetaFile
->AddAction( new MetaPixelAction( ImplMap( rSource
), rColor
) );
1101 void MtfTools::MoveTo( const Point
& rPoint
, bool bRecordPath
)
1103 Point
aDest( ImplMap( rPoint
) );
1106 // fdo#57353 create new subpath for subsequent moves
1107 if ( maPathObj
.Count() )
1108 if ( maPathObj
[ maPathObj
.Count() - 1 ].GetSize() )
1109 maPathObj
.Insert( tools::Polygon() );
1110 maPathObj
.AddPoint( aDest
);
1115 void MtfTools::LineTo( const Point
& rPoint
, bool bRecordPath
)
1118 Point
aDest( ImplMap( rPoint
) );
1120 maPathObj
.AddPoint( aDest
);
1124 mpGDIMetaFile
->AddAction( new MetaLineAction( maActPos
, aDest
, maLineStyle
.aLineInfo
) );
1129 void MtfTools::DrawRect( const tools::Rectangle
& rRect
, bool bEdge
)
1134 if ( mbComplexClip
)
1136 tools::Polygon
aPoly( ImplMap( rRect
) );
1137 tools::PolyPolygon
aPolyPolyRect( aPoly
);
1138 tools::PolyPolygon aDest
;
1139 tools::PolyPolygon(maClipPath
.getClipPath()).GetIntersection( aPolyPolyRect
, aDest
);
1140 ImplDrawClippedPolyPolygon( aDest
);
1146 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1148 ImplSetNonPersistentLineColorTransparenz();
1149 mpGDIMetaFile
->AddAction( new MetaRectAction( ImplMap( rRect
) ) );
1151 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( ImplMap( rRect
) ),maLineStyle
.aLineInfo
) );
1156 mpGDIMetaFile
->AddAction( new MetaRectAction( ImplMap( rRect
) ) );
1161 ImplSetNonPersistentLineColorTransparenz();
1162 mpGDIMetaFile
->AddAction( new MetaRectAction( ImplMap( rRect
) ) );
1167 void MtfTools::DrawRoundRect( const tools::Rectangle
& rRect
, const Size
& rSize
)
1172 mpGDIMetaFile
->AddAction( new MetaRoundRectAction( ImplMap( rRect
), labs( ImplMap( rSize
).Width() ), labs( ImplMap( rSize
).Height() ) ) );
1175 void MtfTools::DrawEllipse( const tools::Rectangle
& rRect
)
1180 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1182 Point
aCenter( ImplMap( rRect
.Center() ) );
1183 Size
aRad( ImplMap( Size( rRect
.GetWidth() / 2, rRect
.GetHeight() / 2 ) ) );
1185 ImplSetNonPersistentLineColorTransparenz();
1186 mpGDIMetaFile
->AddAction( new MetaEllipseAction( ImplMap( rRect
) ) );
1188 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( aCenter
, aRad
.Width(), aRad
.Height() ), maLineStyle
.aLineInfo
) );
1193 mpGDIMetaFile
->AddAction( new MetaEllipseAction( ImplMap( rRect
) ) );
1197 void MtfTools::DrawArc( const tools::Rectangle
& rRect
, const Point
& rStart
, const Point
& rEnd
, bool bTo
)
1203 tools::Rectangle
aRect( ImplMap( rRect
) );
1204 Point
aStart( ImplMap( rStart
) );
1205 Point
aEnd( ImplMap( rEnd
) );
1207 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1209 if ( aStart
== aEnd
)
1210 { // SJ: #i53768# if start & end is identical, then we have to draw a full ellipse
1211 Point
aCenter( aRect
.Center() );
1212 Size
aRad( aRect
.GetWidth() / 2, aRect
.GetHeight() / 2 );
1214 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( aCenter
, aRad
.Width(), aRad
.Height() ), maLineStyle
.aLineInfo
) );
1217 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( aRect
, aStart
, aEnd
, PolyStyle::Arc
), maLineStyle
.aLineInfo
) );
1220 mpGDIMetaFile
->AddAction( new MetaArcAction( aRect
, aStart
, aEnd
) );
1226 void MtfTools::DrawPie( const tools::Rectangle
& rRect
, const Point
& rStart
, const Point
& rEnd
)
1231 tools::Rectangle
aRect( ImplMap( rRect
) );
1232 Point
aStart( ImplMap( rStart
) );
1233 Point
aEnd( ImplMap( rEnd
) );
1235 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1237 ImplSetNonPersistentLineColorTransparenz();
1238 mpGDIMetaFile
->AddAction( new MetaPieAction( aRect
, aStart
, aEnd
) );
1240 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( aRect
, aStart
, aEnd
, PolyStyle::Pie
), maLineStyle
.aLineInfo
) );
1245 mpGDIMetaFile
->AddAction( new MetaPieAction( aRect
, aStart
, aEnd
) );
1249 void MtfTools::DrawChord( const tools::Rectangle
& rRect
, const Point
& rStart
, const Point
& rEnd
)
1254 tools::Rectangle
aRect( ImplMap( rRect
) );
1255 Point
aStart( ImplMap( rStart
) );
1256 Point
aEnd( ImplMap( rEnd
) );
1258 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1260 ImplSetNonPersistentLineColorTransparenz();
1261 mpGDIMetaFile
->AddAction( new MetaChordAction( aRect
, aStart
, aEnd
) );
1263 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( aRect
, aStart
, aEnd
, PolyStyle::Chord
), maLineStyle
.aLineInfo
) );
1268 mpGDIMetaFile
->AddAction( new MetaChordAction( aRect
, aStart
, aEnd
) );
1272 void MtfTools::DrawPolygon( tools::Polygon rPolygon
, bool bRecordPath
)
1275 ImplMap( rPolygon
);
1277 maPathObj
.AddPolygon( rPolygon
);
1282 if ( mbComplexClip
)
1284 tools::PolyPolygon
aPolyPoly( rPolygon
);
1285 tools::PolyPolygon aDest
;
1286 tools::PolyPolygon(maClipPath
.getClipPath()).GetIntersection( aPolyPoly
, aDest
);
1287 ImplDrawClippedPolyPolygon( aDest
);
1291 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1293 sal_uInt16 nCount
= rPolygon
.GetSize();
1296 if ( rPolygon
[ nCount
- 1 ] != rPolygon
[ 0 ] )
1298 Point
aPoint( rPolygon
[ 0 ] );
1299 rPolygon
.Insert( nCount
, aPoint
);
1302 ImplSetNonPersistentLineColorTransparenz();
1303 mpGDIMetaFile
->AddAction( new MetaPolygonAction( rPolygon
) );
1305 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( rPolygon
, maLineStyle
.aLineInfo
) );
1311 if (maLatestFillStyle
.aType
!= WinMtfFillStyleType::Pattern
)
1312 mpGDIMetaFile
->AddAction( new MetaPolygonAction( rPolygon
) );
1314 SvtGraphicFill aFill
= SvtGraphicFill( tools::PolyPolygon( rPolygon
),
1317 SvtGraphicFill::fillNonZero
,
1318 SvtGraphicFill::fillTexture
,
1319 SvtGraphicFill::Transform(),
1321 SvtGraphicFill::hatchSingle
,
1323 SvtGraphicFill::GradientType::Linear
,
1327 Graphic (maLatestFillStyle
.aBmp
) );
1329 SvMemoryStream aMemStm
;
1331 WriteSvtGraphicFill( aMemStm
, aFill
);
1333 mpGDIMetaFile
->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_BEGIN", 0,
1334 static_cast<const sal_uInt8
*>(aMemStm
.GetData()),
1335 aMemStm
.Seek( STREAM_SEEK_TO_END
) ) );
1336 mpGDIMetaFile
->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_END" ) );
1344 void MtfTools::DrawPolyPolygon( tools::PolyPolygon
& rPolyPolygon
, bool bRecordPath
)
1348 ImplMap( rPolyPolygon
);
1351 maPathObj
.AddPolyPolygon( rPolyPolygon
);
1356 if ( mbComplexClip
)
1358 tools::PolyPolygon aDest
;
1359 tools::PolyPolygon(maClipPath
.getClipPath()).GetIntersection( rPolyPolygon
, aDest
);
1360 ImplDrawClippedPolyPolygon( aDest
);
1365 mpGDIMetaFile
->AddAction( new MetaPolyPolygonAction( rPolyPolygon
) );
1366 if (maLineStyle
.aLineInfo
.GetWidth() > 0 || maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
)
1368 for (sal_uInt16 nPoly
= 0; nPoly
< rPolyPolygon
.Count(); ++nPoly
)
1370 mpGDIMetaFile
->AddAction(new MetaPolyLineAction(rPolyPolygon
[nPoly
], maLineStyle
.aLineInfo
));
1377 void MtfTools::DrawPolyLine( tools::Polygon rPolygon
, bool bTo
, bool bRecordPath
)
1381 sal_uInt16 nPoints
= rPolygon
.GetSize();
1384 ImplMap( rPolygon
);
1387 rPolygon
[ 0 ] = maActPos
;
1388 maActPos
= rPolygon
[ rPolygon
.GetSize() - 1 ];
1391 maPathObj
.AddPolyLine( rPolygon
);
1395 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( rPolygon
, maLineStyle
.aLineInfo
) );
1400 void MtfTools::DrawPolyBezier( tools::Polygon rPolygon
, bool bTo
, bool bRecordPath
)
1402 sal_uInt16 nPoints
= rPolygon
.GetSize();
1403 if ( ( nPoints
>= 4 ) && ( ( ( nPoints
- 4 ) % 3 ) == 0 ) )
1407 ImplMap( rPolygon
);
1410 rPolygon
[ 0 ] = maActPos
;
1411 maActPos
= rPolygon
[ nPoints
- 1 ];
1414 for ( i
= 0; ( i
+ 2 ) < nPoints
; )
1416 rPolygon
.SetFlags( i
++, PolyFlags::Normal
);
1417 rPolygon
.SetFlags( i
++, PolyFlags::Control
);
1418 rPolygon
.SetFlags( i
++, PolyFlags::Control
);
1421 maPathObj
.AddPolyLine( rPolygon
);
1425 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( rPolygon
, maLineStyle
.aLineInfo
) );
1430 void MtfTools::DrawText( Point
& rPosition
, OUString
const & rText
, long* pDXArry
, long* pDYArry
, bool bRecordPath
, sal_Int32 nGfxMode
)
1433 rPosition
= ImplMap( rPosition
);
1434 sal_Int32 nOldGfxMode
= GetGfxMode();
1435 SetGfxMode( GM_COMPATIBLE
);
1439 sal_Int32 nSumX
= 0, nSumY
= 0;
1440 for (sal_Int32 i
= 0; i
< rText
.getLength(); i
++ )
1442 nSumX
+= pDXArry
[i
];
1444 // #i121382# Map DXArray using WorldTransform
1445 const Size
aSizeX(ImplMap(Size(nSumX
, 0)));
1446 const basegfx::B2DVector
aVectorX(aSizeX
.Width(), aSizeX
.Height());
1447 pDXArry
[i
] = basegfx::fround(aVectorX
.getLength());
1448 pDXArry
[i
] *= (nSumX
>= 0 ? 1 : -1);
1452 nSumY
+= pDYArry
[i
];
1454 const Size
aSizeY(ImplMap(Size(0, nSumY
)));
1455 const basegfx::B2DVector
aVectorY(aSizeY
.Width(), aSizeY
.Height());
1457 pDYArry
[i
] = basegfx::fround(aVectorY
.getLength());
1458 pDYArry
[i
] *= (nSumY
>= 0 ? -1 : 1);
1462 if ( mnLatestTextLayoutMode
!= mnTextLayoutMode
)
1464 mnLatestTextLayoutMode
= mnTextLayoutMode
;
1465 mpGDIMetaFile
->AddAction( new MetaLayoutModeAction( mnTextLayoutMode
) );
1467 SetGfxMode( nGfxMode
);
1468 TextAlign eTextAlign
;
1469 if ( ( mnTextAlign
& TA_BASELINE
) == TA_BASELINE
)
1470 eTextAlign
= ALIGN_BASELINE
;
1471 else if( ( mnTextAlign
& TA_BOTTOM
) == TA_BOTTOM
)
1472 eTextAlign
= ALIGN_BOTTOM
;
1474 eTextAlign
= ALIGN_TOP
;
1475 bool bChangeFont
= false;
1476 if ( mnLatestTextAlign
!= mnTextAlign
)
1479 mnLatestTextAlign
= mnTextAlign
;
1480 mpGDIMetaFile
->AddAction( new MetaTextAlignAction( eTextAlign
) );
1482 if ( maLatestTextColor
!= maTextColor
)
1485 maLatestTextColor
= maTextColor
;
1486 mpGDIMetaFile
->AddAction( new MetaTextColorAction( maTextColor
) );
1488 bool bChangeFillColor
= false;
1489 if ( maLatestBkColor
!= maBkColor
)
1491 bChangeFillColor
= true;
1492 maLatestBkColor
= maBkColor
;
1494 if ( mnLatestBkMode
!= mnBkMode
)
1496 bChangeFillColor
= true;
1497 mnLatestBkMode
= mnBkMode
;
1499 if ( bChangeFillColor
)
1502 mpGDIMetaFile
->AddAction( new MetaTextFillColorAction( maFont
.GetFillColor(), !maFont
.IsTransparent() ) );
1504 vcl::Font
aTmp( maFont
);
1505 aTmp
.SetColor( maTextColor
);
1506 aTmp
.SetFillColor( maBkColor
);
1508 if( mnBkMode
== BkMode::Transparent
)
1509 aTmp
.SetTransparent( true );
1511 aTmp
.SetTransparent( false );
1513 aTmp
.SetAlignment( eTextAlign
);
1515 if ( nGfxMode
== GM_ADVANCED
)
1517 // check whether there is a font rotation applied via transformation
1518 Point
aP1( ImplMap( Point() ) );
1519 Point
aP2( ImplMap( Point( 0, 100 ) ) );
1520 aP2
.AdjustX( -(aP1
.X()) );
1521 aP2
.AdjustY( -(aP1
.Y()) );
1522 double fX
= aP2
.X();
1523 double fY
= aP2
.Y();
1526 double fOrientation
= acos( fX
/ sqrt( fX
* fX
+ fY
* fY
) ) * 57.29577951308;
1528 fOrientation
= 360 - fOrientation
;
1531 fOrientation
+= aTmp
.GetOrientation();
1532 aTmp
.SetOrientation( sal_Int16( fOrientation
) );
1536 if( mnTextAlign
& ( TA_UPDATECP
| TA_RIGHT_CENTER
) )
1538 // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
1539 SolarMutexGuard aGuard
;
1540 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
1541 sal_Int32 nTextWidth
;
1543 pVDev
->SetMapMode( MapMode( MapUnit::Map100thMM
) );
1544 pVDev
->SetFont( maFont
);
1545 const sal_uInt32 nLen
= pDXArry
? rText
.getLength() : 0;
1548 nTextWidth
= pVDev
->GetTextWidth( OUString(rText
[ nLen
- 1 ]) );
1550 nTextWidth
+= pDXArry
[ nLen
- 2 ];
1551 // tdf#39894: We should consider the distance to next character cell origin
1552 aActPosDelta
.setX( pDXArry
[ nLen
- 1 ] );
1555 aActPosDelta
.setY( pDYArry
[ nLen
- 1 ] );
1560 nTextWidth
= pVDev
->GetTextWidth( rText
);
1561 aActPosDelta
.setX( nTextWidth
);
1564 if( mnTextAlign
& TA_UPDATECP
)
1565 rPosition
= maActPos
;
1567 if ( mnTextAlign
& TA_RIGHT_CENTER
)
1569 Point
aDisplacement( ( ( mnTextAlign
& TA_RIGHT_CENTER
) == TA_RIGHT
) ? nTextWidth
: nTextWidth
>> 1, 0 );
1570 Point().RotateAround(aDisplacement
, maFont
.GetOrientation());
1571 rPosition
-= aDisplacement
;
1574 if( mnTextAlign
& TA_UPDATECP
)
1576 Point().RotateAround(aActPosDelta
, maFont
.GetOrientation());
1577 maActPos
= rPosition
+ aActPosDelta
;
1580 if ( bChangeFont
|| ( maLatestFont
!= aTmp
) )
1582 maLatestFont
= aTmp
;
1583 mpGDIMetaFile
->AddAction( new MetaFontAction( aTmp
) );
1584 mpGDIMetaFile
->AddAction( new MetaTextAlignAction( aTmp
.GetAlignment() ) );
1585 mpGDIMetaFile
->AddAction( new MetaTextColorAction( aTmp
.GetColor() ) );
1586 mpGDIMetaFile
->AddAction( new MetaTextFillColorAction( aTmp
.GetFillColor(), !aTmp
.IsTransparent() ) );
1594 if ( pDXArry
&& pDYArry
)
1596 for (sal_Int32 i
= 0; i
< rText
.getLength(); ++i
)
1598 Point
aCharDisplacement( i
? pDXArry
[i
-1] : 0, i
? pDYArry
[i
-1] : 0 );
1599 Point().RotateAround(aCharDisplacement
, maFont
.GetOrientation());
1600 mpGDIMetaFile
->AddAction( new MetaTextArrayAction( rPosition
+ aCharDisplacement
, OUString( rText
[i
] ), nullptr, 0, 1 ) );
1605 /* because text without dx array is badly scaled, we
1606 will create such an array if necessary */
1607 long* pDX
= pDXArry
;
1610 // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
1611 SolarMutexGuard aGuard
;
1612 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
1613 pDX
= new long[ rText
.getLength() ];
1614 pVDev
->SetMapMode(MapMode(MapUnit::Map100thMM
));
1615 pVDev
->SetFont( maLatestFont
);
1616 pVDev
->GetTextArray( rText
, pDX
, 0, rText
.getLength());
1618 mpGDIMetaFile
->AddAction( new MetaTextArrayAction( rPosition
, rText
, pDX
, 0, rText
.getLength() ) );
1619 if ( !pDXArry
) // this means we have created our own array
1620 delete[] pDX
; // which must be deleted
1623 SetGfxMode( nOldGfxMode
);
1626 void MtfTools::ImplDrawBitmap( const Point
& rPos
, const Size
& rSize
, const BitmapEx
& rBitmap
)
1628 BitmapEx
aBmpEx( rBitmap
);
1629 if ( mbComplexClip
)
1631 vcl::bitmap::DrawAndClipBitmap(rPos
, rSize
, rBitmap
, aBmpEx
, maClipPath
.getClipPath());
1634 if ( aBmpEx
.IsTransparent() )
1635 mpGDIMetaFile
->AddAction( new MetaBmpExScaleAction( rPos
, rSize
, aBmpEx
) );
1637 mpGDIMetaFile
->AddAction( new MetaBmpScaleAction( rPos
, rSize
, aBmpEx
.GetBitmap() ) );
1640 void MtfTools::ResolveBitmapActions( std::vector
<std::unique_ptr
<BSaveStruct
>>& rSaveList
)
1644 size_t nObjects
= rSaveList
.size();
1645 size_t nObjectsLeft
= nObjects
;
1647 while ( nObjectsLeft
)
1650 size_t nObjectsOfSameSize
= 0;
1651 size_t nObjectStartIndex
= nObjects
- nObjectsLeft
;
1653 BSaveStruct
* pSave
= rSaveList
[nObjectStartIndex
].get();
1654 tools::Rectangle
aRect( pSave
->aOutRect
);
1656 for ( i
= nObjectStartIndex
; i
< nObjects
; )
1658 nObjectsOfSameSize
++;
1659 if ( ++i
< nObjects
)
1661 pSave
= rSaveList
[i
].get();
1662 if ( pSave
->aOutRect
!= aRect
)
1666 Point
aPos( ImplMap( aRect
.TopLeft() ) );
1667 Size
aSize( ImplMap( aRect
.GetSize() ) );
1669 for ( i
= nObjectStartIndex
; i
< ( nObjectStartIndex
+ nObjectsOfSameSize
); i
++ )
1671 pSave
= rSaveList
[i
].get();
1673 sal_uInt32 nWinRop
= pSave
->nWinRop
;
1674 sal_uInt8 nRasterOperation
= static_cast<sal_uInt8
>( nWinRop
>> 16 );
1676 sal_uInt32 nUsed
= 0;
1677 if ( ( nRasterOperation
& 0xf ) != ( nRasterOperation
>> 4 ) )
1678 nUsed
|= 1; // pattern is used
1679 if ( ( nRasterOperation
& 0x33 ) != ( ( nRasterOperation
& 0xcc ) >> 2 ) )
1680 nUsed
|= 2; // source is used
1681 if ( ( nRasterOperation
& 0xaa ) != ( ( nRasterOperation
& 0x55 ) << 1 ) )
1682 nUsed
|= 4; // destination is used
1684 if ( (nUsed
& 1) && (( nUsed
& 2 ) == 0) && nWinRop
!= PATINVERT
)
1685 { // patterns aren't well supported yet
1686 WMFRasterOp nOldRop
= SetRasterOp( WMFRasterOp::NONE
); // in this case nRasterOperation is either 0 or 0xff
1688 DrawRect( aRect
, false );
1689 SetRasterOp( nOldRop
);
1693 bool bDrawn
= false;
1695 if ( i
== nObjectStartIndex
) // optimizing, sometimes it is possible to create just one transparent bitmap
1697 if ( nObjectsOfSameSize
== 2 )
1699 BSaveStruct
* pSave2
= rSaveList
[i
+ 1].get();
1700 if ( ( pSave
->aBmpEx
.GetPrefSize() == pSave2
->aBmpEx
.GetPrefSize() ) &&
1701 ( pSave
->aBmpEx
.GetPrefMapMode() == pSave2
->aBmpEx
.GetPrefMapMode() ) )
1703 // TODO: Strictly speaking, we should
1704 // check whether mask is monochrome, and
1705 // whether image is black (upper branch)
1706 // or white (lower branch). Otherwise, the
1707 // effect is not the same as a masked
1709 if ( ( nWinRop
== SRCPAINT
) && ( pSave2
->nWinRop
== SRCAND
) )
1711 Bitmap
aMask( pSave
->aBmpEx
.GetBitmap() ); aMask
.Invert();
1712 BitmapEx
aBmpEx( pSave2
->aBmpEx
.GetBitmap(), aMask
);
1713 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1717 // #i20085# This is just the other way
1718 // around as above. Only difference: mask
1720 else if ( ( nWinRop
== SRCAND
) && ( pSave2
->nWinRop
== SRCPAINT
) )
1722 Bitmap
aMask( pSave
->aBmpEx
.GetBitmap() );
1723 BitmapEx
aBmpEx( pSave2
->aBmpEx
.GetBitmap(), aMask
);
1724 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1729 else if ( ( nWinRop
== SRCAND
) && ( pSave2
->nWinRop
== SRCINVERT
) )
1731 Bitmap
aMask( pSave
->aBmpEx
.GetBitmap() );
1732 BitmapEx
aBmpEx( pSave2
->aBmpEx
.GetBitmap(), aMask
);
1733 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1744 WMFRasterOp nOldRop
= SetRasterOp( WMFRasterOp::CopyPen
);
1745 Bitmap
aBitmap( pSave
->aBmpEx
.GetBitmap() );
1746 sal_uInt32 nOperation
= ( nRasterOperation
& 0xf );
1747 switch( nOperation
)
1752 if(pSave
->aBmpEx
.IsAlpha())
1754 ImplDrawBitmap( aPos
, aSize
, pSave
->aBmpEx
);
1758 SetRasterOp( WMFRasterOp::XorPen
);
1759 ImplDrawBitmap( aPos
, aSize
, BitmapEx(aBitmap
) );
1760 SetRasterOp( WMFRasterOp::CopyPen
);
1761 Bitmap
aMask( aBitmap
);
1763 BitmapEx
aBmpEx( aBitmap
, aMask
);
1764 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1765 if ( nOperation
== 0x1 )
1767 SetRasterOp( WMFRasterOp::Not
);
1768 DrawRect( aRect
, false );
1776 Bitmap
aMask( aBitmap
);
1777 if ( ( nUsed
& 1 ) && ( nRasterOperation
& 0xb0 ) == 0xb0 ) // pattern used
1779 aBitmap
.Convert( BmpConversion::N24Bit
);
1780 aBitmap
.Erase( maFillStyle
.aFillColor
);
1782 BitmapEx
aBmpEx( aBitmap
, aMask
);
1783 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1784 if ( nOperation
== 0x7 )
1786 SetRasterOp( WMFRasterOp::Not
);
1787 DrawRect( aRect
, false );
1795 SetRasterOp( WMFRasterOp::Not
);
1796 DrawRect( aRect
, false );
1797 SetRasterOp( WMFRasterOp::CopyPen
);
1798 Bitmap
aMask( aBitmap
);
1800 BitmapEx
aBmpEx( aBitmap
, aMask
);
1801 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1802 SetRasterOp( WMFRasterOp::XorPen
);
1803 ImplDrawBitmap( aPos
, aSize
, BitmapEx(aBitmap
) );
1804 if ( nOperation
== 0xb )
1806 SetRasterOp( WMFRasterOp::Not
);
1807 DrawRect( aRect
, false );
1815 Bitmap
aMask( aBitmap
);
1817 BitmapEx
aBmpEx( aBitmap
, aMask
);
1818 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1819 SetRasterOp( WMFRasterOp::XorPen
);
1820 ImplDrawBitmap( aPos
, aSize
, BitmapEx(aBitmap
) );
1821 if ( nOperation
== 0xd )
1823 SetRasterOp( WMFRasterOp::Not
);
1824 DrawRect( aRect
, false );
1831 SetRasterOp( WMFRasterOp::XorPen
);
1832 ImplDrawBitmap( aPos
, aSize
, BitmapEx(aBitmap
) );
1833 if ( nOperation
== 0x9 )
1835 SetRasterOp( WMFRasterOp::Not
);
1836 DrawRect( aRect
, false );
1841 case 0x0 : // WHITENESS
1842 case 0xf : // BLACKNESS
1843 { // in this case nRasterOperation is either 0 or 0xff
1844 maFillStyle
= WinMtfFillStyle( Color( nRasterOperation
, nRasterOperation
, nRasterOperation
) );
1846 DrawRect( aRect
, false );
1850 case 0x3 : // only source is used
1853 if ( nRasterOperation
== 0x33 )
1855 ImplDrawBitmap( aPos
, aSize
, BitmapEx(aBitmap
) );
1859 case 0x5 : // only destination is used
1861 SetRasterOp( WMFRasterOp::Not
);
1862 DrawRect( aRect
, false );
1866 case 0xa : // no operation
1869 SetRasterOp( nOldRop
);
1874 nObjectsLeft
-= nObjectsOfSameSize
;
1880 void MtfTools::SetDevOrg( const Point
& rPoint
)
1882 mnDevOrgX
= rPoint
.X();
1883 mnDevOrgY
= rPoint
.Y();
1886 void MtfTools::SetDevOrgOffset( sal_Int32 nXAdd
, sal_Int32 nYAdd
)
1892 void MtfTools::SetDevExt( const Size
& rSize
,bool regular
)
1894 if ( rSize
.Width() && rSize
.Height() )
1899 case MM_ANISOTROPIC
:
1901 mnDevWidth
= rSize
.Width();
1902 mnDevHeight
= rSize
.Height();
1912 void MtfTools::ScaleDevExt(double fX
, double fY
)
1914 mnDevWidth
= basegfx::fround(mnDevWidth
* fX
);
1915 mnDevHeight
= basegfx::fround(mnDevHeight
* fY
);
1918 void MtfTools::SetWinOrg( const Point
& rPoint
, bool bIsEMF
)
1920 mnWinOrgX
= rPoint
.X();
1921 mnWinOrgY
= rPoint
.Y();
1929 void MtfTools::SetWinOrgOffset( sal_Int32 nXAdd
, sal_Int32 nYAdd
)
1935 void MtfTools::SetDevByWin() //mnWinExt...-stuff has to be assigned before.
1939 if ( mnMapMode
== MM_ISOTROPIC
) //TODO: WHAT ABOUT ANISOTROPIC???
1942 if (o3tl::checked_add(mnWinExtX
, mnWinOrgX
, nX
) || o3tl::checked_sub(mnWinExtY
, mnWinOrgY
, nY
))
1944 Size
aSize(nX
>> MS_FIXPOINT_BITCOUNT_28_4
, -(nY
>> MS_FIXPOINT_BITCOUNT_28_4
));
1945 SetDevExt(aSize
, false);
1950 void MtfTools::SetWinExt(const Size
& rSize
, bool bIsEMF
)
1952 if (rSize
.Width() && rSize
.Height())
1957 case MM_ANISOTROPIC
:
1959 mnWinExtX
= rSize
.Width();
1960 mnWinExtY
= rSize
.Height();
1965 mbIsMapWinSet
= true;
1971 void MtfTools::ScaleWinExt(double fX
, double fY
)
1973 mnWinExtX
= basegfx::fround(mnWinExtX
* fX
);
1974 mnWinExtY
= basegfx::fround(mnWinExtY
* fY
);
1977 void MtfTools::SetrclBounds( const tools::Rectangle
& rRect
)
1982 void MtfTools::SetrclFrame( const tools::Rectangle
& rRect
)
1987 void MtfTools::SetRefPix( const Size
& rSize
)
1989 mnPixX
= rSize
.Width();
1990 mnPixY
= rSize
.Height();
1993 void MtfTools::SetRefMill( const Size
& rSize
)
1995 mnMillX
= rSize
.Width();
1996 mnMillY
= rSize
.Height();
1999 void MtfTools::SetMapMode( sal_uInt32 nMapMode
)
2001 mnMapMode
= nMapMode
;
2002 if ( nMapMode
== MM_TEXT
&& !mbIsMapWinSet
)
2004 mnWinExtX
= mnDevWidth
;
2005 mnWinExtY
= mnDevHeight
;
2007 else if ( mnMapMode
== MM_HIMETRIC
)
2009 sal_Int32 nWinExtX
, nWinExtY
;
2010 if (o3tl::checked_multiply
<sal_Int32
>(mnMillX
, 100, nWinExtX
) ||
2011 o3tl::checked_multiply
<sal_Int32
>(mnMillY
, 100, nWinExtY
))
2015 mnWinExtX
= nWinExtX
;
2016 mnWinExtY
= nWinExtY
;
2020 void MtfTools::SetWorldTransform( const XForm
& rXForm
)
2022 maXForm
.eM11
= rXForm
.eM11
;
2023 maXForm
.eM12
= rXForm
.eM12
;
2024 maXForm
.eM21
= rXForm
.eM21
;
2025 maXForm
.eM22
= rXForm
.eM22
;
2026 maXForm
.eDx
= rXForm
.eDx
;
2027 maXForm
.eDy
= rXForm
.eDy
;
2030 void MtfTools::ModifyWorldTransform( const XForm
& rXForm
, sal_uInt32 nMode
)
2036 maXForm
.eM11
= maXForm
.eM22
= 1.0f
;
2037 maXForm
.eM12
= maXForm
.eM21
= maXForm
.eDx
= maXForm
.eDy
= 0.0f
;
2041 case MWT_RIGHTMULTIPLY
:
2042 case MWT_LEFTMULTIPLY
:
2045 const XForm
* pRight
;
2047 if ( nMode
== MWT_LEFTMULTIPLY
)
2062 aF
[0][0] = pLeft
->eM11
;
2063 aF
[0][1] = pLeft
->eM12
;
2065 aF
[1][0] = pLeft
->eM21
;
2066 aF
[1][1] = pLeft
->eM22
;
2068 aF
[2][0] = pLeft
->eDx
;
2069 aF
[2][1] = pLeft
->eDy
;
2072 bF
[0][0] = pRight
->eM11
;
2073 bF
[0][1] = pRight
->eM12
;
2075 bF
[1][0] = pRight
->eM21
;
2076 bF
[1][1] = pRight
->eM22
;
2078 bF
[2][0] = pRight
->eDx
;
2079 bF
[2][1] = pRight
->eDy
;
2083 for ( i
= 0; i
< 3; i
++ )
2085 for ( j
= 0; j
< 3; j
++ )
2088 for ( k
= 0; k
< 3; k
++ )
2089 cF
[i
][j
] += aF
[i
][k
] * bF
[k
][j
];
2092 maXForm
.eM11
= cF
[0][0];
2093 maXForm
.eM12
= cF
[0][1];
2094 maXForm
.eM21
= cF
[1][0];
2095 maXForm
.eM22
= cF
[1][1];
2096 maXForm
.eDx
= cF
[2][0];
2097 maXForm
.eDy
= cF
[2][1];
2102 SetWorldTransform(rXForm
);
2108 void MtfTools::Push() // !! to be able to access the original ClipRegion it
2109 { // is not allowed to use the MetaPushAction()
2110 UpdateClipRegion(); // (the original clip region is on top of the stack) (SJ)
2111 std::shared_ptr
<SaveStruct
> pSave( new SaveStruct
);
2113 pSave
->aLineStyle
= maLineStyle
;
2114 pSave
->aFillStyle
= maFillStyle
;
2116 pSave
->aFont
= maFont
;
2117 pSave
->aTextColor
= maTextColor
;
2118 pSave
->nTextAlign
= mnTextAlign
;
2119 pSave
->nTextLayoutMode
= mnTextLayoutMode
;
2120 pSave
->nMapMode
= mnMapMode
;
2121 pSave
->nGfxMode
= mnGfxMode
;
2122 pSave
->nBkMode
= mnBkMode
;
2123 pSave
->aBkColor
= maBkColor
;
2124 pSave
->bFillStyleSelected
= mbFillStyleSelected
;
2126 pSave
->aActPos
= maActPos
;
2127 pSave
->aXForm
= maXForm
;
2128 pSave
->eRasterOp
= meRasterOp
;
2130 pSave
->nWinOrgX
= mnWinOrgX
;
2131 pSave
->nWinOrgY
= mnWinOrgY
;
2132 pSave
->nWinExtX
= mnWinExtX
;
2133 pSave
->nWinExtY
= mnWinExtY
;
2134 pSave
->nDevOrgX
= mnDevOrgX
;
2135 pSave
->nDevOrgY
= mnDevOrgY
;
2136 pSave
->nDevWidth
= mnDevWidth
;
2137 pSave
->nDevHeight
= mnDevHeight
;
2139 pSave
->maPathObj
= maPathObj
;
2140 pSave
->maClipPath
= maClipPath
;
2142 mvSaveStack
.push_back( pSave
);
2145 void MtfTools::Pop()
2147 // Get the latest data from the stack
2148 if( !mvSaveStack
.empty() )
2150 // Backup the current data on the stack
2151 std::shared_ptr
<SaveStruct
> pSave( mvSaveStack
.back() );
2153 maLineStyle
= pSave
->aLineStyle
;
2154 maFillStyle
= pSave
->aFillStyle
;
2156 maFont
= pSave
->aFont
;
2157 maTextColor
= pSave
->aTextColor
;
2158 mnTextAlign
= pSave
->nTextAlign
;
2159 mnTextLayoutMode
= pSave
->nTextLayoutMode
;
2160 mnBkMode
= pSave
->nBkMode
;
2161 mnGfxMode
= pSave
->nGfxMode
;
2162 mnMapMode
= pSave
->nMapMode
;
2163 maBkColor
= pSave
->aBkColor
;
2164 mbFillStyleSelected
= pSave
->bFillStyleSelected
;
2166 maActPos
= pSave
->aActPos
;
2167 maXForm
= pSave
->aXForm
;
2168 meRasterOp
= pSave
->eRasterOp
;
2170 mnWinOrgX
= pSave
->nWinOrgX
;
2171 mnWinOrgY
= pSave
->nWinOrgY
;
2172 mnWinExtX
= pSave
->nWinExtX
;
2173 mnWinExtY
= pSave
->nWinExtY
;
2174 mnDevOrgX
= pSave
->nDevOrgX
;
2175 mnDevOrgY
= pSave
->nDevOrgY
;
2176 mnDevWidth
= pSave
->nDevWidth
;
2177 mnDevHeight
= pSave
->nDevHeight
;
2179 maPathObj
= pSave
->maPathObj
;
2180 if ( ! ( maClipPath
== pSave
->maClipPath
) )
2182 maClipPath
= pSave
->maClipPath
;
2183 mbClipNeedsUpdate
= true;
2185 if ( meLatestRasterOp
!= meRasterOp
)
2186 mpGDIMetaFile
->AddAction( new MetaRasterOpAction( meRasterOp
) );
2187 mvSaveStack
.pop_back();
2191 void MtfTools::AddFromGDIMetaFile( GDIMetaFile
& rGDIMetaFile
)
2193 rGDIMetaFile
.Play( *mpGDIMetaFile
);
2196 void MtfTools::PassEMFPlusHeaderInfo()
2198 EMFP_DEBUG(printf ("\t\t\tadd EMF_PLUS header info\n"));
2201 sal_Int32 nLeft
, nRight
, nTop
, nBottom
;
2203 nLeft
= mrclFrame
.Left();
2204 nTop
= mrclFrame
.Top();
2205 nRight
= mrclFrame
.Right();
2206 nBottom
= mrclFrame
.Bottom();
2209 mem
.WriteInt32( nLeft
).WriteInt32( nTop
).WriteInt32( nRight
).WriteInt32( nBottom
);
2210 mem
.WriteInt32( mnPixX
).WriteInt32( mnPixY
).WriteInt32( mnMillX
).WriteInt32( mnMillY
);
2217 // add transformation matrix to be used in vcl's metaact.cxx for
2218 // rotate and scale operations
2219 mem
.WriteFloat( one
).WriteFloat( zero
).WriteFloat( zero
).WriteFloat( one
).WriteFloat( zero
).WriteFloat( zero
);
2221 // need to flush the stream, otherwise GetEndOfData will return 0
2222 // on windows where the function parameters are probably resolved in reverse order
2225 mpGDIMetaFile
->AddAction( new MetaCommentAction( "EMF_PLUS_HEADER_INFO", 0, static_cast<const sal_uInt8
*>(mem
.GetData()), mem
.GetEndOfData() ) );
2226 mpGDIMetaFile
->UseCanvas( true );
2229 void MtfTools::PassEMFPlus( void const * pBuffer
, sal_uInt32 nLength
)
2231 EMFP_DEBUG(printf ("\t\t\tadd EMF_PLUS comment length %04x\n",(unsigned int) nLength
));
2232 mpGDIMetaFile
->AddAction( new MetaCommentAction( "EMF_PLUS", 0, static_cast<const sal_uInt8
*>(pBuffer
), nLength
) );
2236 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */