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/metric.hxx>
27 #include <vcl/graphictools.hxx>
28 #include <vcl/BitmapTools.hxx>
29 #include <vcl/metaact.hxx>
30 #include <vcl/canvastools.hxx>
31 #include <vcl/svapp.hxx>
32 #include <tools/fract.hxx>
33 #include <tools/stream.hxx>
34 #include <rtl/strbuf.hxx>
35 #include <rtl/tencinfo.h>
36 #include <sal/log.hxx>
37 #include <osl/diagnose.h>
38 #include <vcl/virdev.hxx>
39 #include <o3tl/safeint.hxx>
40 #include <officecfg/Setup.hxx>
41 #include <officecfg/Office/Linguistic.hxx>
42 #include <unotools/configmgr.hxx>
43 #include <unotools/wincodepage.hxx>
44 #include <tools/helpers.hxx>
45 #include <vcl/bitmapaccess.hxx>
47 #if OSL_DEBUG_LEVEL > 1
48 #define EMFP_DEBUG(x) x
55 SvStream
& operator >> (SvStream
& rInStream
, XForm
& rXForm
)
57 if (sizeof(float) != 4)
59 OSL_FAIL("EmfReader::sizeof( float ) != 4");
64 rInStream
.ReadFloat(rXForm
.eM11
);
65 rInStream
.ReadFloat(rXForm
.eM12
);
66 rInStream
.ReadFloat(rXForm
.eM21
);
67 rInStream
.ReadFloat(rXForm
.eM22
);
68 rInStream
.ReadFloat(rXForm
.eDx
);
69 rInStream
.ReadFloat(rXForm
.eDy
);
74 void WinMtfClipPath::intersectClipRect( const tools::Rectangle
& rRect
)
76 maClip
.intersectRange(vcl::unotools::b2DRectangleFromRectangle(rRect
));
79 void WinMtfClipPath::excludeClipRect( const tools::Rectangle
& rRect
)
81 maClip
.subtractRange(vcl::unotools::b2DRectangleFromRectangle(rRect
));
84 void WinMtfClipPath::setClipPath( const tools::PolyPolygon
& rPolyPolygon
, sal_Int32 nClippingMode
)
86 const basegfx::B2DPolyPolygon
& rB2DPoly
=rPolyPolygon
.getB2DPolyPolygon();
87 switch ( nClippingMode
)
90 maClip
.unionPolyPolygon(rB2DPoly
);
93 maClip
.xorPolyPolygon(rB2DPoly
);
96 maClip
.subtractPolyPolygon(rB2DPoly
);
99 maClip
.intersectPolyPolygon(rB2DPoly
);
102 maClip
= basegfx::utils::B2DClipState(rB2DPoly
);
107 void WinMtfClipPath::moveClipRegion( const Size
& rSize
)
109 basegfx::B2DHomMatrix aTranslate
;
110 aTranslate
.translate(rSize
.Width(), rSize
.Height());
111 maClip
.transform(aTranslate
);
114 void WinMtfClipPath::setDefaultClipPath()
116 // Empty clip region - everything visible
117 maClip
= basegfx::utils::B2DClipState();
120 basegfx::B2DPolyPolygon
const & WinMtfClipPath::getClipPath() const
122 return maClip
.getClipPoly();
125 void WinMtfPathObj::AddPoint( const Point
& rPoint
)
128 Insert( tools::Polygon() );
129 tools::Polygon
& rPoly
= static_cast<tools::PolyPolygon
&>(*this)[ Count() - 1 ];
130 rPoly
.Insert( rPoly
.GetSize(), rPoint
);
134 void WinMtfPathObj::AddPolyLine( const tools::Polygon
& rPolyLine
)
137 Insert( tools::Polygon() );
138 tools::Polygon
& rPoly
= static_cast<tools::PolyPolygon
&>(*this)[ Count() - 1 ];
139 rPoly
.Insert( rPoly
.GetSize(), rPolyLine
);
143 void WinMtfPathObj::AddPolygon( const tools::Polygon
& rPoly
)
149 void WinMtfPathObj::AddPolyPolygon( const tools::PolyPolygon
& rPolyPoly
)
151 sal_uInt16 i
, nCount
= rPolyPoly
.Count();
152 for ( i
= 0; i
< nCount
; i
++ )
153 Insert( rPolyPoly
[ i
] );
157 void WinMtfPathObj::ClosePath()
161 tools::Polygon
& rPoly
= static_cast<tools::PolyPolygon
&>(*this)[ Count() - 1 ];
162 if ( rPoly
.GetSize() > 2 )
164 Point
aFirst( rPoly
[ 0 ] );
165 if ( aFirst
!= rPoly
[ rPoly
.GetSize() - 1 ] )
166 rPoly
.Insert( rPoly
.GetSize(), aFirst
);
174 OUString
getLODefaultLanguage()
176 if (utl::ConfigManager::IsFuzzing())
177 return OUString("en-US");
178 OUString
result(officecfg::Office::Linguistic::General::DefaultLocale::get());
179 if (result
.isEmpty())
180 result
= officecfg::Setup::L10N::ooSetupSystemLocale::get();
186 WinMtfFontStyle::WinMtfFontStyle( LOGFONTW
const & rFont
)
188 rtl_TextEncoding eCharSet
;
189 if ((rFont
.alfFaceName
== "Symbol")
190 || (rFont
.alfFaceName
== "MT Extra"))
191 eCharSet
= RTL_TEXTENCODING_SYMBOL
;
192 else if ((rFont
.lfCharSet
== DEFAULT_CHARSET
) || (rFont
.lfCharSet
== OEM_CHARSET
))
193 eCharSet
= utl_getWinTextEncodingFromLangStr(getLODefaultLanguage().toUtf8().getStr(),
194 rFont
.lfCharSet
== OEM_CHARSET
);
196 eCharSet
= rtl_getTextEncodingFromWindowsCharset( rFont
.lfCharSet
);
197 if ( eCharSet
== RTL_TEXTENCODING_DONTKNOW
)
198 eCharSet
= RTL_TEXTENCODING_MS_1252
;
199 aFont
.SetCharSet( eCharSet
);
200 aFont
.SetFamilyName( rFont
.alfFaceName
);
202 switch ( rFont
.lfPitchAndFamily
& 0xf0 )
205 eFamily
= FAMILY_ROMAN
;
209 eFamily
= FAMILY_SWISS
;
213 eFamily
= FAMILY_MODERN
;
217 eFamily
= FAMILY_SCRIPT
;
221 eFamily
= FAMILY_DECORATIVE
;
225 eFamily
= FAMILY_DONTKNOW
;
228 aFont
.SetFamily( eFamily
);
231 switch ( rFont
.lfPitchAndFamily
& 0x0f )
234 ePitch
= PITCH_FIXED
;
240 ePitch
= PITCH_VARIABLE
;
243 aFont
.SetPitch( ePitch
);
246 if (rFont
.lfWeight
== 0) // default weight SHOULD be used
247 eWeight
= WEIGHT_DONTKNOW
;
248 else if (rFont
.lfWeight
<= FW_THIN
)
249 eWeight
= WEIGHT_THIN
;
250 else if( rFont
.lfWeight
<= FW_ULTRALIGHT
)
251 eWeight
= WEIGHT_ULTRALIGHT
;
252 else if( rFont
.lfWeight
<= FW_LIGHT
)
253 eWeight
= WEIGHT_LIGHT
;
254 else if( rFont
.lfWeight
< FW_MEDIUM
)
255 eWeight
= WEIGHT_NORMAL
;
256 else if( rFont
.lfWeight
== FW_MEDIUM
)
257 eWeight
= WEIGHT_MEDIUM
;
258 else if( rFont
.lfWeight
<= FW_SEMIBOLD
)
259 eWeight
= WEIGHT_SEMIBOLD
;
260 else if( rFont
.lfWeight
<= FW_BOLD
)
261 eWeight
= WEIGHT_BOLD
;
262 else if( rFont
.lfWeight
<= FW_ULTRABOLD
)
263 eWeight
= WEIGHT_ULTRABOLD
;
265 eWeight
= WEIGHT_BLACK
;
266 aFont
.SetWeight( eWeight
);
269 aFont
.SetItalic( ITALIC_NORMAL
);
271 if( rFont
.lfUnderline
)
272 aFont
.SetUnderline( LINESTYLE_SINGLE
);
274 if( rFont
.lfStrikeOut
)
275 aFont
.SetStrikeout( STRIKEOUT_SINGLE
);
277 aFont
.SetOrientation( static_cast<short>(rFont
.lfEscapement
) );
279 Size
aFontSize( Size( rFont
.lfWidth
, rFont
.lfHeight
) );
280 if ( rFont
.lfHeight
> 0 )
282 // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
283 SolarMutexGuard aGuard
;
284 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
285 // converting the cell height into a font height
286 aFont
.SetFontSize( aFontSize
);
287 pVDev
->SetFont( aFont
);
288 FontMetric
aMetric( pVDev
->GetFontMetric() );
289 long nHeight
= aMetric
.GetAscent() + aMetric
.GetDescent();
292 double fHeight
= (static_cast<double>(aFontSize
.Height()) * rFont
.lfHeight
) / nHeight
;
293 aFontSize
.setHeight( static_cast<sal_Int32
>( fHeight
+ 0.5 ) );
297 // Convert height to positive
298 aFontSize
.setHeight( std::abs(aFontSize
.Height()) );
300 aFont
.SetFontSize(aFontSize
);
303 Color
MtfTools::ReadColor()
307 mpInputStream
->ReadUInt32( nColor
);
308 return Color( static_cast<sal_uInt8
>(nColor
), static_cast<sal_uInt8
>( nColor
>> 8 ), static_cast<sal_uInt8
>( nColor
>> 16 ) );
311 Point
MtfTools::ImplScale(const Point
& rPoint
) // Hack to set varying defaults for incompletely defined files.
314 return Point(rPoint
.X() * UNDOCUMENTED_WIN_RCL_RELATION
- mrclFrame
.Left(),
315 rPoint
.Y() * UNDOCUMENTED_WIN_RCL_RELATION
- mrclFrame
.Top());
320 Point
MtfTools::ImplMap( const Point
& rPt
)
322 if ( mnWinExtX
&& mnWinExtY
)
327 double fX2
= fX
* maXForm
.eM11
+ fY
* maXForm
.eM21
+ maXForm
.eDx
;
328 double fY2
= fX
* maXForm
.eM12
+ fY
* maXForm
.eM22
+ maXForm
.eDy
;
330 if ( mnGfxMode
== GM_COMPATIBLE
)
338 fX2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
*10;
339 fY2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
*10;
348 fX2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
;
349 fY2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
;
358 fX2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
/MILLIINCH_PER_TWIPS
;
359 fY2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
/MILLIINCH_PER_TWIPS
;
374 case MM_HIMETRIC
: // in hundredth of a millimeter
384 if (mnPixX
== 0 || mnPixY
== 0)
386 SAL_WARN("emfio", "invalid scaling factor");
398 fY2
+= mnDevOrgY
; // fX2, fY2 now in device units
399 fX2
*= static_cast<double>(mnMillX
) * 100.0 / static_cast<double>(mnPixX
);
400 fY2
*= static_cast<double>(mnMillY
) * 100.0 / static_cast<double>(mnPixY
);
405 fX2
-= mrclFrame
.Left();
406 fY2
-= mrclFrame
.Top();
408 return Point(basegfx::fround(fX2
), basegfx::fround(fY2
));
414 Size
MtfTools::ImplMap(const Size
& rSz
, bool bDoWorldTransform
)
416 if ( mnWinExtX
&& mnWinExtY
)
418 // #i121382# apply the whole WorldTransform, else a rotation will be misinterpreted
419 double fWidth
, fHeight
;
420 if (bDoWorldTransform
)
422 fWidth
= rSz
.Width() * maXForm
.eM11
+ rSz
.Height() * maXForm
.eM21
;
423 fHeight
= rSz
.Width() * maXForm
.eM12
+ rSz
.Height() * maXForm
.eM22
;
427 //take the scale, but not the rotation
428 basegfx::B2DHomMatrix
aMatrix(maXForm
.eM11
, maXForm
.eM12
, 0,
429 maXForm
.eM21
, maXForm
.eM22
, 0);
430 basegfx::B2DTuple aScale
, aTranslate
;
431 double fRotate
, fShearX
;
432 if (!aMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
))
437 fWidth
= rSz
.Width() * aScale
.getX();
438 fHeight
= rSz
.Height() * aScale
.getY();
441 if ( mnGfxMode
== GM_COMPATIBLE
)
447 fWidth
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
*10;
448 fHeight
*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH
*10;
453 fWidth
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
;
454 fHeight
*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH
;
463 case MM_HIMETRIC
: // in hundredth of millimeters
470 fWidth
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
/MILLIINCH_PER_TWIPS
;
471 fHeight
*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH
/MILLIINCH_PER_TWIPS
;
476 if (mnPixX
== 0 || mnPixY
== 0)
478 SAL_WARN("emfio", "invalid scaling factor");
484 fHeight
/= mnWinExtY
;
485 fWidth
*= mnDevWidth
;
486 fHeight
*= mnDevHeight
;
487 fWidth
*= static_cast<double>(mnMillX
) * 100.0 / static_cast<double>(mnPixX
);
488 fHeight
*= static_cast<double>(mnMillY
) * 100.0 / static_cast<double>(mnPixY
);
494 return Size(basegfx::fround(fWidth
), basegfx::fround(fHeight
));
500 tools::Rectangle
MtfTools::ImplMap( const tools::Rectangle
& rRect
)
502 tools::Rectangle aRect
;
503 aRect
.SetPos(ImplMap(rRect
.TopLeft()));
504 aRect
.SaturatingSetSize(ImplMap(rRect
.GetSize()));
508 void MtfTools::ImplMap( vcl::Font
& rFont
)
510 // !!! HACK: we now always set the width to zero because the OS width is interpreted differently;
511 // must later be made portable in SV (KA 1996-02-08)
512 Size aFontSize
= ImplMap (rFont
.GetFontSize(), false);
514 const auto nHeight
= aFontSize
.Height();
516 aFontSize
.setHeight( o3tl::saturating_toggle_sign(nHeight
) );
518 rFont
.SetFontSize( aFontSize
);
521 const bool bFail
= o3tl::checked_multiply(mnWinExtX
, mnWinExtY
, nResult
);
522 if (!bFail
&& nResult
< 0)
523 rFont
.SetOrientation( 3600 - rFont
.GetOrientation() );
526 tools::Polygon
& MtfTools::ImplMap( tools::Polygon
& rPolygon
)
528 sal_uInt16 nPoints
= rPolygon
.GetSize();
529 for ( sal_uInt16 i
= 0; i
< nPoints
; i
++ )
531 rPolygon
[ i
] = ImplMap( rPolygon
[ i
] );
536 void MtfTools::ImplScale( tools::Polygon
& rPolygon
)
538 sal_uInt16 nPoints
= rPolygon
.GetSize();
539 for ( sal_uInt16 i
= 0; i
< nPoints
; i
++ )
541 rPolygon
[ i
] = ImplScale( rPolygon
[ i
] );
545 tools::PolyPolygon
& MtfTools::ImplScale( tools::PolyPolygon
& rPolyPolygon
)
547 sal_uInt16 nPolys
= rPolyPolygon
.Count();
548 for (sal_uInt16 i
= 0; i
< nPolys
; ++i
)
550 ImplScale(rPolyPolygon
[i
]);
555 tools::PolyPolygon
& MtfTools::ImplMap( tools::PolyPolygon
& rPolyPolygon
)
557 sal_uInt16 nPolys
= rPolyPolygon
.Count();
558 for ( sal_uInt16 i
= 0; i
< nPolys
; ImplMap( rPolyPolygon
[ i
++ ] ) ) ;
562 void MtfTools::SelectObject( sal_Int32 nIndex
)
564 if ( nIndex
& ENHMETA_STOCK_OBJECT
)
566 sal_uInt16 nStockId
= static_cast<sal_uInt8
>(nIndex
);
571 maFillStyle
= WinMtfFillStyle( COL_WHITE
);
572 mbFillStyleSelected
= true;
577 maFillStyle
= WinMtfFillStyle( COL_LIGHTGRAY
);
578 mbFillStyleSelected
= true;
584 maFillStyle
= WinMtfFillStyle( COL_GRAY
);
585 mbFillStyleSelected
= true;
590 maFillStyle
= WinMtfFillStyle( COL_BLACK
);
591 mbFillStyleSelected
= true;
596 maFillStyle
= WinMtfFillStyle( COL_TRANSPARENT
, true );
597 mbFillStyleSelected
= true;
602 maLineStyle
= WinMtfLineStyle( COL_WHITE
);
607 maLineStyle
= WinMtfLineStyle( COL_BLACK
);
612 maLineStyle
= WinMtfLineStyle( COL_TRANSPARENT
, true );
621 nIndex
&= 0xffff; // safety check: don't allow index to be > 65535
623 GDIObj
*pGDIObj
= nullptr;
625 if ( static_cast<sal_uInt32
>(nIndex
) < mvGDIObj
.size() )
626 pGDIObj
= mvGDIObj
[ nIndex
].get();
630 if (const auto pen
= dynamic_cast<WinMtfLineStyle
*>(pGDIObj
))
632 else if (const auto brush
= dynamic_cast<WinMtfFillStyle
*>(
635 maFillStyle
= *brush
;
636 mbFillStyleSelected
= true;
638 else if (const auto font
= dynamic_cast<WinMtfFontStyle
*>(
641 maFont
= font
->aFont
;
647 void MtfTools::SetTextLayoutMode( ComplexTextLayoutFlags nTextLayoutMode
)
649 mnTextLayoutMode
= nTextLayoutMode
;
652 void MtfTools::SetBkMode( BkMode nMode
)
657 void MtfTools::SetBkColor( const Color
& rColor
)
662 void MtfTools::SetTextColor( const Color
& rColor
)
664 maTextColor
= rColor
;
667 void MtfTools::SetTextAlign( sal_uInt32 nAlign
)
669 mnTextAlign
= nAlign
;
672 void MtfTools::ImplResizeObjectArry( sal_uInt32 nNewEntrys
)
674 mvGDIObj
.resize(nNewEntrys
);
677 void MtfTools::ImplDrawClippedPolyPolygon( const tools::PolyPolygon
& rPolyPoly
)
679 if ( rPolyPoly
.Count() )
681 ImplSetNonPersistentLineColorTransparenz();
682 if ( rPolyPoly
.Count() == 1 )
684 if ( rPolyPoly
.IsRect() )
685 mpGDIMetaFile
->AddAction( new MetaRectAction( rPolyPoly
.GetBoundRect() ) );
688 tools::Polygon
aPoly( rPolyPoly
[ 0 ] );
689 sal_uInt16 nCount
= aPoly
.GetSize();
692 if ( aPoly
[ nCount
- 1 ] != aPoly
[ 0 ] )
694 Point
aPoint( aPoly
[ 0 ] );
695 aPoly
.Insert( nCount
, aPoint
);
697 mpGDIMetaFile
->AddAction( new MetaPolygonAction( aPoly
) );
702 mpGDIMetaFile
->AddAction( new MetaPolyPolygonAction( rPolyPoly
) );
706 void MtfTools::CreateObject( std::unique_ptr
<GDIObj
> pObject
)
710 const auto pLineStyle
= dynamic_cast<WinMtfLineStyle
*>(pObject
.get());
711 const auto pFontStyle
= dynamic_cast<WinMtfFontStyle
*>(pObject
.get());
715 if (pFontStyle
->aFont
.GetFontHeight() == 0)
716 pFontStyle
->aFont
.SetFontHeight(423);
717 ImplMap(pFontStyle
->aFont
); // defaulting to 12pt
719 else if ( pLineStyle
)
721 Size
aSize(pLineStyle
->aLineInfo
.GetWidth(), 0);
722 aSize
= ImplMap(aSize
);
723 pLineStyle
->aLineInfo
.SetWidth(aSize
.Width());
726 std::vector
<std::unique_ptr
<GDIObj
>>::size_type nIndex
;
727 for ( nIndex
= 0; nIndex
< mvGDIObj
.size(); nIndex
++ )
729 if ( !mvGDIObj
[ nIndex
] )
732 if ( nIndex
== mvGDIObj
.size() )
733 ImplResizeObjectArry( mvGDIObj
.size() + 16 );
735 mvGDIObj
[ nIndex
] = std::move(pObject
);
738 void MtfTools::CreateObjectIndexed( sal_Int32 nIndex
, std::unique_ptr
<GDIObj
> pObject
)
740 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
742 nIndex
&= 0xffff; // safety check: do not allow index to be > 65535
745 const auto pLineStyle
= dynamic_cast<WinMtfLineStyle
*>(pObject
.get());
746 const auto pFontStyle
= dynamic_cast<WinMtfFontStyle
*>(pObject
.get());
749 if (pFontStyle
->aFont
.GetFontHeight() == 0)
750 pFontStyle
->aFont
.SetFontHeight(423);
751 ImplMap(pFontStyle
->aFont
);
753 else if ( pLineStyle
)
755 Size
aSize(pLineStyle
->aLineInfo
.GetWidth(), 0);
756 pLineStyle
->aLineInfo
.SetWidth( ImplMap(aSize
).Width() );
758 if ( pLineStyle
->aLineInfo
.GetStyle() == LineStyle::Dash
)
760 aSize
.AdjustWidth(1 );
761 long nDotLen
= ImplMap( aSize
).Width();
762 pLineStyle
->aLineInfo
.SetDistance( nDotLen
);
763 pLineStyle
->aLineInfo
.SetDotLen( nDotLen
);
764 pLineStyle
->aLineInfo
.SetDashLen( nDotLen
* 3 );
768 if ( static_cast<sal_uInt32
>(nIndex
) >= mvGDIObj
.size() )
769 ImplResizeObjectArry( nIndex
+ 16 );
771 mvGDIObj
[ nIndex
] = std::move(pObject
);
775 void MtfTools::CreateObject()
777 CreateObject(std::make_unique
<GDIObj
>());
780 void MtfTools::DeleteObject( sal_Int32 nIndex
)
782 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
784 if ( static_cast<sal_uInt32
>(nIndex
) < mvGDIObj
.size() )
786 mvGDIObj
[ nIndex
].reset();
791 void MtfTools::IntersectClipRect( const tools::Rectangle
& rRect
)
793 if (utl::ConfigManager::IsFuzzing())
795 mbClipNeedsUpdate
=true;
796 if ((rRect
.Left()-rRect
.Right()==0) && (rRect
.Top()-rRect
.Bottom()==0))
798 return; // empty rectangles cause trouble
800 maClipPath
.intersectClipRect( ImplMap( rRect
) );
803 void MtfTools::ExcludeClipRect( const tools::Rectangle
& rRect
)
805 if (utl::ConfigManager::IsFuzzing())
807 mbClipNeedsUpdate
=true;
808 maClipPath
.excludeClipRect( ImplMap( rRect
) );
811 void MtfTools::MoveClipRegion( const Size
& rSize
)
813 if (utl::ConfigManager::IsFuzzing())
815 mbClipNeedsUpdate
=true;
816 maClipPath
.moveClipRegion( ImplMap( rSize
) );
819 void MtfTools::SetClipPath( const tools::PolyPolygon
& rPolyPolygon
, sal_Int32 nClippingMode
, bool bIsMapped
)
821 if (utl::ConfigManager::IsFuzzing())
823 mbClipNeedsUpdate
= true;
824 tools::PolyPolygon
aPolyPolygon(rPolyPolygon
);
828 if (!mbIsMapDevSet
&& (mnMapMode
== MM_ISOTROPIC
|| mnMapMode
== MM_ANISOTROPIC
))
829 aPolyPolygon
= ImplScale(aPolyPolygon
);
831 aPolyPolygon
= ImplMap(aPolyPolygon
);
833 maClipPath
.setClipPath(aPolyPolygon
, nClippingMode
);
836 void MtfTools::SetDefaultClipPath()
838 mbClipNeedsUpdate
= true;
839 maClipPath
.setDefaultClipPath();
842 MtfTools::MtfTools( GDIMetaFile
& rGDIMetaFile
, SvStream
& rStreamWMF
)
853 mnLatestTextAlign(90),
854 mnTextAlign(TA_LEFT
| TA_TOP
| TA_NOUPDATECP
),
857 maLatestBkColor(0x12345678),
858 maBkColor(COL_WHITE
),
859 mnLatestTextLayoutMode(ComplexTextLayoutFlags::Default
),
860 mnTextLayoutMode(ComplexTextLayoutFlags::Default
),
861 mnLatestBkMode(BkMode::NONE
),
862 mnBkMode(BkMode::OPAQUE
),
863 meLatestRasterOp(RasterOp::Invert
),
864 meRasterOp(RasterOp::OverPaint
),
869 mnGfxMode(GM_COMPATIBLE
),
886 mpGDIMetaFile(&rGDIMetaFile
),
887 mpInputStream(&rStreamWMF
),
892 mbFillStyleSelected(false),
893 mbClipNeedsUpdate(true),
894 mbComplexClip(false),
895 mbIsMapWinSet(false),
898 SvLockBytes
*pLB
= mpInputStream
->GetLockBytes();
902 pLB
->SetSynchronMode();
905 mnStartPos
= mpInputStream
->Tell();
908 mpGDIMetaFile
->AddAction( new MetaPushAction( PushFlags::CLIPREGION
) ); // The original clipregion has to be on top
909 // of the stack so it can always be restored
910 // this is necessary to be able to support
911 // SetClipRgn( NULL ) and similar ClipRgn actions (SJ)
913 maFont
.SetFamilyName( "Arial" ); // sj: #i57205#, we do have some scaling problems if using
914 maFont
.SetCharSet( RTL_TEXTENCODING_MS_1252
); // the default font then most times a x11 font is used, we
915 maFont
.SetFontHeight( 423 ); // will prevent this defining a font
917 maLatestLineStyle
.aLineColor
= Color( 0x12, 0x34, 0x56 );
918 maLatestFillStyle
.aFillColor
= Color( 0x12, 0x34, 0x56 );
920 mnRop
= WMFRasterOp::Black
;
921 meRasterOp
= RasterOp::OverPaint
;
922 mpGDIMetaFile
->AddAction( new MetaRasterOpAction( RasterOp::OverPaint
) );
925 MtfTools::~MtfTools() COVERITY_NOEXCEPT_FALSE
927 mpGDIMetaFile
->AddAction( new MetaPopAction() );
928 mpGDIMetaFile
->SetPrefMapMode(MapMode(MapUnit::Map100thMM
));
929 if ( mrclFrame
.IsEmpty() )
930 mpGDIMetaFile
->SetPrefSize( Size( mnDevWidth
, mnDevHeight
) );
932 mpGDIMetaFile
->SetPrefSize( mrclFrame
.GetSize() );
935 void MtfTools::UpdateClipRegion()
937 if (mbClipNeedsUpdate
)
939 mbClipNeedsUpdate
= false;
940 mbComplexClip
= false;
942 mpGDIMetaFile
->AddAction( new MetaPopAction() ); // taking the original clipregion
943 mpGDIMetaFile
->AddAction( new MetaPushAction( PushFlags::CLIPREGION
) );
945 // skip for 'no clipping at all' case
946 if( !maClipPath
.isEmpty() )
948 const basegfx::B2DPolyPolygon
& rClipPoly( maClipPath
.getClipPath() );
950 mbComplexClip
= rClipPoly
.count() > 1
951 || !basegfx::utils::isRectangle(rClipPoly
);
953 static bool bEnableComplexClipViaRegion
= getenv("SAL_WMF_COMPLEXCLIP_VIA_REGION") != nullptr;
955 if (bEnableComplexClipViaRegion
)
957 //this makes cases like tdf#45820 work in reasonable time, and I feel in theory should
958 //be just fine. In practice I see the output is different so needs work before its the
959 //default, but for file fuzzing it should be good enough
962 mpGDIMetaFile
->AddAction(
963 new MetaISectRegionClipRegionAction(
964 vcl::Region(rClipPoly
)));
965 mbComplexClip
= false;
969 mpGDIMetaFile
->AddAction(
970 new MetaISectRectClipRegionAction(
971 vcl::unotools::rectangleFromB2DRectangle(
972 rClipPoly
.getB2DRange())));
978 mpGDIMetaFile
->AddAction(
979 new MetaISectRectClipRegionAction(
980 vcl::unotools::rectangleFromB2DRectangle(
981 rClipPoly
.getB2DRange())));
987 void MtfTools::ImplSetNonPersistentLineColorTransparenz()
989 WinMtfLineStyle
aTransparentLine( COL_TRANSPARENT
, true );
990 if ( ! ( maLatestLineStyle
== aTransparentLine
) )
992 maLatestLineStyle
= aTransparentLine
;
993 mpGDIMetaFile
->AddAction( new MetaLineColorAction( aTransparentLine
.aLineColor
, !aTransparentLine
.bTransparent
) );
997 void MtfTools::UpdateLineStyle()
999 if (!( maLatestLineStyle
== maLineStyle
) )
1001 maLatestLineStyle
= maLineStyle
;
1002 mpGDIMetaFile
->AddAction( new MetaLineColorAction( maLineStyle
.aLineColor
, !maLineStyle
.bTransparent
) );
1006 void MtfTools::UpdateFillStyle()
1008 if ( !mbFillStyleSelected
) // SJ: #i57205# taking care of bkcolor if no brush is selected
1009 maFillStyle
= WinMtfFillStyle( maBkColor
, mnBkMode
== BkMode::Transparent
);
1010 if (!( maLatestFillStyle
== maFillStyle
) )
1012 maLatestFillStyle
= maFillStyle
;
1013 if (maFillStyle
.aType
== WinMtfFillStyleType::Solid
)
1014 mpGDIMetaFile
->AddAction( new MetaFillColorAction( maFillStyle
.aFillColor
, !maFillStyle
.bTransparent
) );
1018 WMFRasterOp
MtfTools::SetRasterOp( WMFRasterOp nRasterOp
)
1020 WMFRasterOp nRetROP
= mnRop
;
1021 if ( nRasterOp
!= mnRop
)
1025 if ( mbNopMode
&& ( nRasterOp
!= WMFRasterOp::Nop
) )
1026 { // changing modes from WMFRasterOp::Nop so set pen and brush
1027 maFillStyle
= maNopFillStyle
;
1028 maLineStyle
= maNopLineStyle
;
1033 case WMFRasterOp::Not
:
1034 meRasterOp
= RasterOp::Invert
;
1037 case WMFRasterOp::XorPen
:
1038 meRasterOp
= RasterOp::Xor
;
1041 case WMFRasterOp::Nop
:
1043 meRasterOp
= RasterOp::OverPaint
;
1046 maNopFillStyle
= maFillStyle
;
1047 maNopLineStyle
= maLineStyle
;
1048 maFillStyle
= WinMtfFillStyle( COL_TRANSPARENT
, true );
1049 maLineStyle
= WinMtfLineStyle( COL_TRANSPARENT
, true );
1056 meRasterOp
= RasterOp::OverPaint
;
1060 if ( nRetROP
!= nRasterOp
)
1061 mpGDIMetaFile
->AddAction( new MetaRasterOpAction( meRasterOp
) );
1065 void MtfTools::StrokeAndFillPath( bool bStroke
, bool bFill
)
1067 if ( maPathObj
.Count() )
1076 mpGDIMetaFile
->AddAction( new MetaPushAction( PushFlags::LINECOLOR
) );
1077 mpGDIMetaFile
->AddAction( new MetaLineColorAction( Color(), false ) );
1079 if ( maPathObj
.Count() == 1 )
1080 mpGDIMetaFile
->AddAction( new MetaPolygonAction( maPathObj
.GetObject( 0 ) ) );
1082 mpGDIMetaFile
->AddAction( new MetaPolyPolygonAction( maPathObj
) );
1085 mpGDIMetaFile
->AddAction( new MetaPopAction() );
1089 sal_uInt16 i
, nCount
= maPathObj
.Count();
1090 for ( i
= 0; i
< nCount
; i
++ )
1091 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( maPathObj
[ i
], maLineStyle
.aLineInfo
) );
1097 void MtfTools::DrawPixel( const Point
& rSource
, const Color
& rColor
)
1099 mpGDIMetaFile
->AddAction( new MetaPixelAction( ImplMap( rSource
), rColor
) );
1102 void MtfTools::MoveTo( const Point
& rPoint
, bool bRecordPath
)
1104 Point
aDest( ImplMap( rPoint
) );
1107 // fdo#57353 create new subpath for subsequent moves
1108 if ( maPathObj
.Count() )
1109 if ( maPathObj
[ maPathObj
.Count() - 1 ].GetSize() )
1110 maPathObj
.Insert( tools::Polygon() );
1111 maPathObj
.AddPoint( aDest
);
1116 void MtfTools::LineTo( const Point
& rPoint
, bool bRecordPath
)
1119 Point
aDest( ImplMap( rPoint
) );
1121 maPathObj
.AddPoint( aDest
);
1125 mpGDIMetaFile
->AddAction( new MetaLineAction( maActPos
, aDest
, maLineStyle
.aLineInfo
) );
1130 void MtfTools::DrawRect( const tools::Rectangle
& rRect
, bool bEdge
)
1135 if ( mbComplexClip
)
1137 tools::Polygon
aPoly( ImplMap( rRect
) );
1138 tools::PolyPolygon
aPolyPolyRect( aPoly
);
1139 tools::PolyPolygon aDest
;
1140 tools::PolyPolygon(maClipPath
.getClipPath()).GetIntersection( aPolyPolyRect
, aDest
);
1141 ImplDrawClippedPolyPolygon( aDest
);
1147 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1149 ImplSetNonPersistentLineColorTransparenz();
1150 mpGDIMetaFile
->AddAction( new MetaRectAction( ImplMap( rRect
) ) );
1152 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( ImplMap( rRect
) ),maLineStyle
.aLineInfo
) );
1157 mpGDIMetaFile
->AddAction( new MetaRectAction( ImplMap( rRect
) ) );
1162 ImplSetNonPersistentLineColorTransparenz();
1163 mpGDIMetaFile
->AddAction( new MetaRectAction( ImplMap( rRect
) ) );
1168 void MtfTools::DrawRoundRect( const tools::Rectangle
& rRect
, const Size
& rSize
)
1173 mpGDIMetaFile
->AddAction( new MetaRoundRectAction( ImplMap( rRect
), labs( ImplMap( rSize
).Width() ), labs( ImplMap( rSize
).Height() ) ) );
1176 void MtfTools::DrawEllipse( const tools::Rectangle
& rRect
)
1181 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1183 Point
aCenter( ImplMap( rRect
.Center() ) );
1184 Size
aRad( ImplMap( Size( rRect
.GetWidth() / 2, rRect
.GetHeight() / 2 ) ) );
1186 ImplSetNonPersistentLineColorTransparenz();
1187 mpGDIMetaFile
->AddAction( new MetaEllipseAction( ImplMap( rRect
) ) );
1189 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( aCenter
, aRad
.Width(), aRad
.Height() ), maLineStyle
.aLineInfo
) );
1194 mpGDIMetaFile
->AddAction( new MetaEllipseAction( ImplMap( rRect
) ) );
1198 void MtfTools::DrawArc( const tools::Rectangle
& rRect
, const Point
& rStart
, const Point
& rEnd
, bool bTo
)
1204 tools::Rectangle
aRect( ImplMap( rRect
) );
1205 Point
aStart( ImplMap( rStart
) );
1206 Point
aEnd( ImplMap( rEnd
) );
1208 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1210 if ( aStart
== aEnd
)
1211 { // SJ: #i53768# if start & end is identical, then we have to draw a full ellipse
1212 Point
aCenter( aRect
.Center() );
1213 Size
aRad( aRect
.GetWidth() / 2, aRect
.GetHeight() / 2 );
1215 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( aCenter
, aRad
.Width(), aRad
.Height() ), maLineStyle
.aLineInfo
) );
1218 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( aRect
, aStart
, aEnd
, PolyStyle::Arc
), maLineStyle
.aLineInfo
) );
1221 mpGDIMetaFile
->AddAction( new MetaArcAction( aRect
, aStart
, aEnd
) );
1227 void MtfTools::DrawPie( const tools::Rectangle
& rRect
, const Point
& rStart
, const Point
& rEnd
)
1232 tools::Rectangle
aRect( ImplMap( rRect
) );
1233 Point
aStart( ImplMap( rStart
) );
1234 Point
aEnd( ImplMap( rEnd
) );
1236 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1238 ImplSetNonPersistentLineColorTransparenz();
1239 mpGDIMetaFile
->AddAction( new MetaPieAction( aRect
, aStart
, aEnd
) );
1241 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( aRect
, aStart
, aEnd
, PolyStyle::Pie
), maLineStyle
.aLineInfo
) );
1246 mpGDIMetaFile
->AddAction( new MetaPieAction( aRect
, aStart
, aEnd
) );
1250 void MtfTools::DrawChord( const tools::Rectangle
& rRect
, const Point
& rStart
, const Point
& rEnd
)
1255 tools::Rectangle
aRect( ImplMap( rRect
) );
1256 Point
aStart( ImplMap( rStart
) );
1257 Point
aEnd( ImplMap( rEnd
) );
1259 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1261 ImplSetNonPersistentLineColorTransparenz();
1262 mpGDIMetaFile
->AddAction( new MetaChordAction( aRect
, aStart
, aEnd
) );
1264 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( aRect
, aStart
, aEnd
, PolyStyle::Chord
), maLineStyle
.aLineInfo
) );
1269 mpGDIMetaFile
->AddAction( new MetaChordAction( aRect
, aStart
, aEnd
) );
1273 void MtfTools::DrawPolygon( tools::Polygon rPolygon
, bool bRecordPath
)
1276 ImplMap( rPolygon
);
1278 maPathObj
.AddPolygon( rPolygon
);
1283 if ( mbComplexClip
)
1285 tools::PolyPolygon
aPolyPoly( rPolygon
);
1286 tools::PolyPolygon aDest
;
1287 tools::PolyPolygon(maClipPath
.getClipPath()).GetIntersection( aPolyPoly
, aDest
);
1288 ImplDrawClippedPolyPolygon( aDest
);
1292 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1294 sal_uInt16 nCount
= rPolygon
.GetSize();
1297 if ( rPolygon
[ nCount
- 1 ] != rPolygon
[ 0 ] )
1299 Point
aPoint( rPolygon
[ 0 ] );
1300 rPolygon
.Insert( nCount
, aPoint
);
1303 ImplSetNonPersistentLineColorTransparenz();
1304 mpGDIMetaFile
->AddAction( new MetaPolygonAction( rPolygon
) );
1306 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( rPolygon
, maLineStyle
.aLineInfo
) );
1312 if (maLatestFillStyle
.aType
!= WinMtfFillStyleType::Pattern
)
1313 mpGDIMetaFile
->AddAction( new MetaPolygonAction( rPolygon
) );
1315 SvtGraphicFill aFill
= SvtGraphicFill( tools::PolyPolygon( rPolygon
),
1318 SvtGraphicFill::fillNonZero
,
1319 SvtGraphicFill::fillTexture
,
1320 SvtGraphicFill::Transform(),
1322 SvtGraphicFill::hatchSingle
,
1324 SvtGraphicFill::GradientType::Linear
,
1328 Graphic (maLatestFillStyle
.aBmp
) );
1330 SvMemoryStream aMemStm
;
1332 WriteSvtGraphicFill( aMemStm
, aFill
);
1334 mpGDIMetaFile
->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_BEGIN", 0,
1335 static_cast<const sal_uInt8
*>(aMemStm
.GetData()),
1336 aMemStm
.TellEnd() ) );
1337 mpGDIMetaFile
->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_END" ) );
1345 void MtfTools::DrawPolyPolygon( tools::PolyPolygon
& rPolyPolygon
, bool bRecordPath
)
1349 ImplMap( rPolyPolygon
);
1352 maPathObj
.AddPolyPolygon( rPolyPolygon
);
1357 if ( mbComplexClip
)
1359 tools::PolyPolygon aDest
;
1360 tools::PolyPolygon(maClipPath
.getClipPath()).GetIntersection( rPolyPolygon
, aDest
);
1361 ImplDrawClippedPolyPolygon( aDest
);
1366 mpGDIMetaFile
->AddAction( new MetaPolyPolygonAction( rPolyPolygon
) );
1367 if (maLineStyle
.aLineInfo
.GetWidth() > 0 || maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
)
1369 for (sal_uInt16 nPoly
= 0; nPoly
< rPolyPolygon
.Count(); ++nPoly
)
1371 mpGDIMetaFile
->AddAction(new MetaPolyLineAction(rPolyPolygon
[nPoly
], maLineStyle
.aLineInfo
));
1378 void MtfTools::DrawPolyLine( tools::Polygon rPolygon
, bool bTo
, bool bRecordPath
)
1382 sal_uInt16 nPoints
= rPolygon
.GetSize();
1385 ImplMap( rPolygon
);
1388 rPolygon
[ 0 ] = maActPos
;
1389 maActPos
= rPolygon
[ rPolygon
.GetSize() - 1 ];
1392 maPathObj
.AddPolyLine( rPolygon
);
1396 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( rPolygon
, maLineStyle
.aLineInfo
) );
1401 void MtfTools::DrawPolyBezier( tools::Polygon rPolygon
, bool bTo
, bool bRecordPath
)
1403 sal_uInt16 nPoints
= rPolygon
.GetSize();
1404 if ( ( nPoints
>= 4 ) && ( ( ( nPoints
- 4 ) % 3 ) == 0 ) )
1408 ImplMap( rPolygon
);
1411 rPolygon
[ 0 ] = maActPos
;
1412 maActPos
= rPolygon
[ nPoints
- 1 ];
1415 for ( i
= 0; ( i
+ 2 ) < nPoints
; )
1417 rPolygon
.SetFlags( i
++, PolyFlags::Normal
);
1418 rPolygon
.SetFlags( i
++, PolyFlags::Control
);
1419 rPolygon
.SetFlags( i
++, PolyFlags::Control
);
1422 maPathObj
.AddPolyLine( rPolygon
);
1426 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( rPolygon
, maLineStyle
.aLineInfo
) );
1431 void MtfTools::DrawText( Point
& rPosition
, OUString
const & rText
, long* pDXArry
, long* pDYArry
, bool bRecordPath
, sal_Int32 nGfxMode
)
1434 rPosition
= ImplMap( rPosition
);
1435 sal_Int32 nOldGfxMode
= GetGfxMode();
1436 SetGfxMode( GM_COMPATIBLE
);
1440 sal_Int32 nSumX
= 0, nSumY
= 0;
1441 for (sal_Int32 i
= 0; i
< rText
.getLength(); i
++ )
1443 nSumX
+= pDXArry
[i
];
1445 // #i121382# Map DXArray using WorldTransform
1446 const Size
aSizeX(ImplMap(Size(nSumX
, 0)));
1447 const basegfx::B2DVector
aVectorX(aSizeX
.Width(), aSizeX
.Height());
1448 pDXArry
[i
] = basegfx::fround(aVectorX
.getLength());
1449 pDXArry
[i
] *= (nSumX
>= 0 ? 1 : -1);
1453 nSumY
+= pDYArry
[i
];
1455 const Size
aSizeY(ImplMap(Size(0, nSumY
)));
1456 const basegfx::B2DVector
aVectorY(aSizeY
.Width(), aSizeY
.Height());
1458 pDYArry
[i
] = basegfx::fround(aVectorY
.getLength());
1459 pDYArry
[i
] *= (nSumY
>= 0 ? -1 : 1);
1463 if ( mnLatestTextLayoutMode
!= mnTextLayoutMode
)
1465 mnLatestTextLayoutMode
= mnTextLayoutMode
;
1466 mpGDIMetaFile
->AddAction( new MetaLayoutModeAction( mnTextLayoutMode
) );
1468 SetGfxMode( nGfxMode
);
1469 TextAlign eTextAlign
;
1470 if ( ( mnTextAlign
& TA_BASELINE
) == TA_BASELINE
)
1471 eTextAlign
= ALIGN_BASELINE
;
1472 else if( ( mnTextAlign
& TA_BOTTOM
) == TA_BOTTOM
)
1473 eTextAlign
= ALIGN_BOTTOM
;
1475 eTextAlign
= ALIGN_TOP
;
1476 bool bChangeFont
= false;
1477 if ( mnLatestTextAlign
!= mnTextAlign
)
1480 mnLatestTextAlign
= mnTextAlign
;
1481 mpGDIMetaFile
->AddAction( new MetaTextAlignAction( eTextAlign
) );
1483 if ( maLatestTextColor
!= maTextColor
)
1486 maLatestTextColor
= maTextColor
;
1487 mpGDIMetaFile
->AddAction( new MetaTextColorAction( maTextColor
) );
1489 bool bChangeFillColor
= false;
1490 if ( maLatestBkColor
!= maBkColor
)
1492 bChangeFillColor
= true;
1493 maLatestBkColor
= maBkColor
;
1495 if ( mnLatestBkMode
!= mnBkMode
)
1497 bChangeFillColor
= true;
1498 mnLatestBkMode
= mnBkMode
;
1500 if ( bChangeFillColor
)
1503 mpGDIMetaFile
->AddAction( new MetaTextFillColorAction( maFont
.GetFillColor(), !maFont
.IsTransparent() ) );
1505 vcl::Font
aTmp( maFont
);
1506 aTmp
.SetColor( maTextColor
);
1507 aTmp
.SetFillColor( maBkColor
);
1509 if( mnBkMode
== BkMode::Transparent
)
1510 aTmp
.SetTransparent( true );
1512 aTmp
.SetTransparent( false );
1514 aTmp
.SetAlignment( eTextAlign
);
1516 if ( nGfxMode
== GM_ADVANCED
)
1518 // check whether there is a font rotation applied via transformation
1519 Point
aP1( ImplMap( Point() ) );
1520 Point
aP2( ImplMap( Point( 0, 100 ) ) );
1521 aP2
.AdjustX( -(aP1
.X()) );
1522 aP2
.AdjustY( -(aP1
.Y()) );
1523 double fX
= aP2
.X();
1524 double fY
= aP2
.Y();
1527 double fOrientation
= acos( fX
/ sqrt( fX
* fX
+ fY
* fY
) ) * 57.29577951308;
1529 fOrientation
= 360 - fOrientation
;
1532 fOrientation
+= aTmp
.GetOrientation();
1533 aTmp
.SetOrientation( sal_Int16( fOrientation
) );
1537 if( mnTextAlign
& ( TA_UPDATECP
| TA_RIGHT_CENTER
) )
1539 // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
1540 SolarMutexGuard aGuard
;
1541 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
1542 sal_Int32 nTextWidth
;
1544 pVDev
->SetMapMode( MapMode( MapUnit::Map100thMM
) );
1545 pVDev
->SetFont( maFont
);
1546 const sal_uInt32 nLen
= pDXArry
? rText
.getLength() : 0;
1549 nTextWidth
= pVDev
->GetTextWidth( OUString(rText
[ nLen
- 1 ]) );
1551 nTextWidth
+= pDXArry
[ nLen
- 2 ];
1552 // tdf#39894: We should consider the distance to next character cell origin
1553 aActPosDelta
.setX( pDXArry
[ nLen
- 1 ] );
1556 aActPosDelta
.setY( pDYArry
[ nLen
- 1 ] );
1561 nTextWidth
= pVDev
->GetTextWidth( rText
);
1562 aActPosDelta
.setX( nTextWidth
);
1565 if( mnTextAlign
& TA_UPDATECP
)
1566 rPosition
= maActPos
;
1568 if ( mnTextAlign
& TA_RIGHT_CENTER
)
1570 Point
aDisplacement( ( ( mnTextAlign
& TA_RIGHT_CENTER
) == TA_RIGHT
) ? nTextWidth
: nTextWidth
>> 1, 0 );
1571 Point().RotateAround(aDisplacement
, maFont
.GetOrientation());
1572 rPosition
-= aDisplacement
;
1575 if( mnTextAlign
& TA_UPDATECP
)
1577 Point().RotateAround(aActPosDelta
, maFont
.GetOrientation());
1578 maActPos
= rPosition
+ aActPosDelta
;
1581 if ( bChangeFont
|| ( maLatestFont
!= aTmp
) )
1583 maLatestFont
= aTmp
;
1584 mpGDIMetaFile
->AddAction( new MetaFontAction( aTmp
) );
1585 mpGDIMetaFile
->AddAction( new MetaTextAlignAction( aTmp
.GetAlignment() ) );
1586 mpGDIMetaFile
->AddAction( new MetaTextColorAction( aTmp
.GetColor() ) );
1587 mpGDIMetaFile
->AddAction( new MetaTextFillColorAction( aTmp
.GetFillColor(), !aTmp
.IsTransparent() ) );
1595 if ( pDXArry
&& pDYArry
)
1597 for (sal_Int32 i
= 0; i
< rText
.getLength(); ++i
)
1599 Point
aCharDisplacement( i
? pDXArry
[i
-1] : 0, i
? pDYArry
[i
-1] : 0 );
1600 Point().RotateAround(aCharDisplacement
, maFont
.GetOrientation());
1601 mpGDIMetaFile
->AddAction( new MetaTextArrayAction( rPosition
+ aCharDisplacement
, OUString( rText
[i
] ), nullptr, 0, 1 ) );
1606 /* because text without dx array is badly scaled, we
1607 will create such an array if necessary */
1608 long* pDX
= pDXArry
;
1611 // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
1612 SolarMutexGuard aGuard
;
1613 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
1614 pDX
= new long[ rText
.getLength() ];
1615 pVDev
->SetMapMode(MapMode(MapUnit::Map100thMM
));
1616 pVDev
->SetFont( maLatestFont
);
1617 pVDev
->GetTextArray( rText
, pDX
, 0, rText
.getLength());
1619 mpGDIMetaFile
->AddAction( new MetaTextArrayAction( rPosition
, rText
, pDX
, 0, rText
.getLength() ) );
1620 if ( !pDXArry
) // this means we have created our own array
1621 delete[] pDX
; // which must be deleted
1624 SetGfxMode( nOldGfxMode
);
1627 void MtfTools::ImplDrawBitmap( const Point
& rPos
, const Size
& rSize
, const BitmapEx
& rBitmap
)
1629 BitmapEx
aBmpEx( rBitmap
);
1630 if ( mbComplexClip
)
1632 vcl::bitmap::DrawAndClipBitmap(rPos
, rSize
, rBitmap
, aBmpEx
, maClipPath
.getClipPath());
1635 if ( aBmpEx
.IsTransparent() )
1636 mpGDIMetaFile
->AddAction( new MetaBmpExScaleAction( rPos
, rSize
, aBmpEx
) );
1638 mpGDIMetaFile
->AddAction( new MetaBmpScaleAction( rPos
, rSize
, aBmpEx
.GetBitmap() ) );
1641 void MtfTools::ResolveBitmapActions( std::vector
<std::unique_ptr
<BSaveStruct
>>& rSaveList
)
1645 size_t nObjects
= rSaveList
.size();
1646 size_t nObjectsLeft
= nObjects
;
1648 while ( nObjectsLeft
)
1651 size_t nObjectsOfSameSize
= 0;
1652 size_t nObjectStartIndex
= nObjects
- nObjectsLeft
;
1654 BSaveStruct
* pSave
= rSaveList
[nObjectStartIndex
].get();
1655 tools::Rectangle
aRect( pSave
->aOutRect
);
1657 for ( i
= nObjectStartIndex
; i
< nObjects
; )
1659 nObjectsOfSameSize
++;
1660 if ( ++i
< nObjects
)
1662 pSave
= rSaveList
[i
].get();
1663 if ( pSave
->aOutRect
!= aRect
)
1667 Point
aPos( ImplMap( aRect
.TopLeft() ) );
1668 Size
aSize( ImplMap( aRect
.GetSize() ) );
1670 for ( i
= nObjectStartIndex
; i
< ( nObjectStartIndex
+ nObjectsOfSameSize
); i
++ )
1672 pSave
= rSaveList
[i
].get();
1674 sal_uInt32 nWinRop
= pSave
->nWinRop
;
1675 sal_uInt8 nRasterOperation
= static_cast<sal_uInt8
>( nWinRop
>> 16 );
1677 sal_uInt32 nUsed
= 0;
1678 if ( ( nRasterOperation
& 0xf ) != ( nRasterOperation
>> 4 ) )
1679 nUsed
|= 1; // pattern is used
1680 if ( ( nRasterOperation
& 0x33 ) != ( ( nRasterOperation
& 0xcc ) >> 2 ) )
1681 nUsed
|= 2; // source is used
1682 if ( ( nRasterOperation
& 0xaa ) != ( ( nRasterOperation
& 0x55 ) << 1 ) )
1683 nUsed
|= 4; // destination is used
1685 if ( (nUsed
& 1) && (( nUsed
& 2 ) == 0) && nWinRop
!= PATINVERT
)
1686 { // patterns aren't well supported yet
1687 WMFRasterOp nOldRop
= SetRasterOp( WMFRasterOp::NONE
); // in this case nRasterOperation is either 0 or 0xff
1689 DrawRect( aRect
, false );
1690 SetRasterOp( nOldRop
);
1694 bool bDrawn
= false;
1696 if ( i
== nObjectStartIndex
) // optimizing, sometimes it is possible to create just one transparent bitmap
1698 if ( nObjectsOfSameSize
== 2 )
1700 BSaveStruct
* pSave2
= rSaveList
[i
+ 1].get();
1701 if ( ( pSave
->aBmpEx
.GetPrefSize() == pSave2
->aBmpEx
.GetPrefSize() ) &&
1702 ( pSave
->aBmpEx
.GetPrefMapMode() == pSave2
->aBmpEx
.GetPrefMapMode() ) )
1704 // TODO: Strictly speaking, we should
1705 // check whether mask is monochrome, and
1706 // whether image is black (upper branch)
1707 // or white (lower branch). Otherwise, the
1708 // effect is not the same as a masked
1710 if ( ( nWinRop
== SRCPAINT
) && ( pSave2
->nWinRop
== SRCAND
) )
1712 Bitmap
aMask( pSave
->aBmpEx
.GetBitmap() ); aMask
.Invert();
1713 BitmapEx
aBmpEx( pSave2
->aBmpEx
.GetBitmap(), aMask
);
1714 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1718 // #i20085# This is just the other way
1719 // around as above. Only difference: mask
1721 else if ( ( nWinRop
== SRCAND
) && ( pSave2
->nWinRop
== SRCPAINT
) )
1723 Bitmap
aMask( pSave
->aBmpEx
.GetBitmap() );
1724 BitmapEx
aBmpEx( pSave2
->aBmpEx
.GetBitmap(), aMask
);
1725 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1730 else if ( ( nWinRop
== SRCAND
) && ( pSave2
->nWinRop
== SRCINVERT
) )
1732 Bitmap
aMask( pSave
->aBmpEx
.GetBitmap() );
1733 BitmapEx
aBmpEx( pSave2
->aBmpEx
.GetBitmap(), aMask
);
1734 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1745 WMFRasterOp nOldRop
= SetRasterOp( WMFRasterOp::CopyPen
);
1746 Bitmap
aBitmap( pSave
->aBmpEx
.GetBitmap() );
1747 sal_uInt32 nOperation
= ( nRasterOperation
& 0xf );
1748 switch( nOperation
)
1753 if(pSave
->aBmpEx
.IsAlpha())
1755 ImplDrawBitmap( aPos
, aSize
, pSave
->aBmpEx
);
1759 SetRasterOp( WMFRasterOp::XorPen
);
1760 ImplDrawBitmap( aPos
, aSize
, BitmapEx(aBitmap
) );
1761 SetRasterOp( WMFRasterOp::CopyPen
);
1762 Bitmap
aMask( aBitmap
);
1764 BitmapEx
aBmpEx( aBitmap
, aMask
);
1765 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1766 if ( nOperation
== 0x1 )
1768 SetRasterOp( WMFRasterOp::Not
);
1769 DrawRect( aRect
, false );
1777 Bitmap
aMask( aBitmap
);
1778 if ( ( nUsed
& 1 ) && ( nRasterOperation
& 0xb0 ) == 0xb0 ) // pattern used
1780 aBitmap
.Convert( BmpConversion::N24Bit
);
1781 aBitmap
.Erase( maFillStyle
.aFillColor
);
1783 BitmapEx
aBmpEx( aBitmap
, aMask
);
1784 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1785 if ( nOperation
== 0x7 )
1787 SetRasterOp( WMFRasterOp::Not
);
1788 DrawRect( aRect
, false );
1796 SetRasterOp( WMFRasterOp::Not
);
1797 DrawRect( aRect
, false );
1798 SetRasterOp( WMFRasterOp::CopyPen
);
1799 Bitmap
aMask( aBitmap
);
1801 BitmapEx
aBmpEx( aBitmap
, aMask
);
1802 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1803 SetRasterOp( WMFRasterOp::XorPen
);
1804 ImplDrawBitmap( aPos
, aSize
, BitmapEx(aBitmap
) );
1805 if ( nOperation
== 0xb )
1807 SetRasterOp( WMFRasterOp::Not
);
1808 DrawRect( aRect
, false );
1816 Bitmap
aMask( aBitmap
);
1818 BitmapEx
aBmpEx( aBitmap
, aMask
);
1819 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1820 SetRasterOp( WMFRasterOp::XorPen
);
1821 ImplDrawBitmap( aPos
, aSize
, BitmapEx(aBitmap
) );
1822 if ( nOperation
== 0xd )
1824 SetRasterOp( WMFRasterOp::Not
);
1825 DrawRect( aRect
, false );
1832 SetRasterOp( WMFRasterOp::XorPen
);
1833 ImplDrawBitmap( aPos
, aSize
, BitmapEx(aBitmap
) );
1834 if ( nOperation
== 0x9 )
1836 SetRasterOp( WMFRasterOp::Not
);
1837 DrawRect( aRect
, false );
1842 case 0x0 : // WHITENESS
1843 case 0xf : // BLACKNESS
1844 { // in this case nRasterOperation is either 0 or 0xff
1845 maFillStyle
= WinMtfFillStyle( Color( nRasterOperation
, nRasterOperation
, nRasterOperation
) );
1847 DrawRect( aRect
, false );
1851 case 0x3 : // only source is used
1854 if ( nRasterOperation
== 0x33 )
1856 ImplDrawBitmap( aPos
, aSize
, BitmapEx(aBitmap
) );
1860 case 0x5 : // only destination is used
1862 SetRasterOp( WMFRasterOp::Not
);
1863 DrawRect( aRect
, false );
1867 case 0xa : // no operation
1870 SetRasterOp( nOldRop
);
1875 nObjectsLeft
-= nObjectsOfSameSize
;
1881 void MtfTools::SetDevOrg( const Point
& rPoint
)
1883 mnDevOrgX
= rPoint
.X();
1884 mnDevOrgY
= rPoint
.Y();
1887 void MtfTools::SetDevOrgOffset( sal_Int32 nXAdd
, sal_Int32 nYAdd
)
1893 void MtfTools::SetDevExt( const Size
& rSize
,bool regular
)
1895 if ( rSize
.Width() && rSize
.Height() )
1900 case MM_ANISOTROPIC
:
1902 mnDevWidth
= rSize
.Width();
1903 mnDevHeight
= rSize
.Height();
1913 void MtfTools::ScaleDevExt(double fX
, double fY
)
1915 mnDevWidth
= basegfx::fround(mnDevWidth
* fX
);
1916 mnDevHeight
= basegfx::fround(mnDevHeight
* fY
);
1919 void MtfTools::SetWinOrg( const Point
& rPoint
, bool bIsEMF
)
1921 mnWinOrgX
= rPoint
.X();
1922 mnWinOrgY
= rPoint
.Y();
1930 void MtfTools::SetWinOrgOffset( sal_Int32 nXAdd
, sal_Int32 nYAdd
)
1936 void MtfTools::SetDevByWin() //mnWinExt...-stuff has to be assigned before.
1940 if ( mnMapMode
== MM_ISOTROPIC
) //TODO: WHAT ABOUT ANISOTROPIC???
1943 if (o3tl::checked_add(mnWinExtX
, mnWinOrgX
, nX
) || o3tl::checked_sub(mnWinExtY
, mnWinOrgY
, nY
))
1945 Size
aSize(nX
>> MS_FIXPOINT_BITCOUNT_28_4
, -(nY
>> MS_FIXPOINT_BITCOUNT_28_4
));
1946 SetDevExt(aSize
, false);
1951 void MtfTools::SetWinExt(const Size
& rSize
, bool bIsEMF
)
1953 if (rSize
.Width() && rSize
.Height())
1958 case MM_ANISOTROPIC
:
1960 mnWinExtX
= rSize
.Width();
1961 mnWinExtY
= rSize
.Height();
1966 mbIsMapWinSet
= true;
1972 void MtfTools::ScaleWinExt(double fX
, double fY
)
1974 mnWinExtX
= basegfx::fround(mnWinExtX
* fX
);
1975 mnWinExtY
= basegfx::fround(mnWinExtY
* fY
);
1978 void MtfTools::SetrclBounds( const tools::Rectangle
& rRect
)
1983 void MtfTools::SetrclFrame( const tools::Rectangle
& rRect
)
1988 void MtfTools::SetRefPix( const Size
& rSize
)
1990 mnPixX
= rSize
.Width();
1991 mnPixY
= rSize
.Height();
1994 void MtfTools::SetRefMill( const Size
& rSize
)
1996 mnMillX
= rSize
.Width();
1997 mnMillY
= rSize
.Height();
2000 void MtfTools::SetMapMode( sal_uInt32 nMapMode
)
2002 mnMapMode
= nMapMode
;
2003 if ( nMapMode
== MM_TEXT
&& !mbIsMapWinSet
)
2005 mnWinExtX
= mnDevWidth
;
2006 mnWinExtY
= mnDevHeight
;
2008 else if ( mnMapMode
== MM_HIMETRIC
)
2010 sal_Int32 nWinExtX
, nWinExtY
;
2011 if (o3tl::checked_multiply
<sal_Int32
>(mnMillX
, 100, nWinExtX
) ||
2012 o3tl::checked_multiply
<sal_Int32
>(mnMillY
, 100, nWinExtY
))
2016 mnWinExtX
= nWinExtX
;
2017 mnWinExtY
= nWinExtY
;
2021 void MtfTools::SetWorldTransform( const XForm
& rXForm
)
2023 maXForm
.eM11
= rXForm
.eM11
;
2024 maXForm
.eM12
= rXForm
.eM12
;
2025 maXForm
.eM21
= rXForm
.eM21
;
2026 maXForm
.eM22
= rXForm
.eM22
;
2027 maXForm
.eDx
= rXForm
.eDx
;
2028 maXForm
.eDy
= rXForm
.eDy
;
2031 void MtfTools::ModifyWorldTransform( const XForm
& rXForm
, sal_uInt32 nMode
)
2037 maXForm
.eM11
= maXForm
.eM22
= 1.0f
;
2038 maXForm
.eM12
= maXForm
.eM21
= maXForm
.eDx
= maXForm
.eDy
= 0.0f
;
2042 case MWT_RIGHTMULTIPLY
:
2043 case MWT_LEFTMULTIPLY
:
2046 const XForm
* pRight
;
2048 if ( nMode
== MWT_LEFTMULTIPLY
)
2063 aF
[0][0] = pLeft
->eM11
;
2064 aF
[0][1] = pLeft
->eM12
;
2066 aF
[1][0] = pLeft
->eM21
;
2067 aF
[1][1] = pLeft
->eM22
;
2069 aF
[2][0] = pLeft
->eDx
;
2070 aF
[2][1] = pLeft
->eDy
;
2073 bF
[0][0] = pRight
->eM11
;
2074 bF
[0][1] = pRight
->eM12
;
2076 bF
[1][0] = pRight
->eM21
;
2077 bF
[1][1] = pRight
->eM22
;
2079 bF
[2][0] = pRight
->eDx
;
2080 bF
[2][1] = pRight
->eDy
;
2084 for ( i
= 0; i
< 3; i
++ )
2086 for ( j
= 0; j
< 3; j
++ )
2089 for ( k
= 0; k
< 3; k
++ )
2090 cF
[i
][j
] += aF
[i
][k
] * bF
[k
][j
];
2093 maXForm
.eM11
= cF
[0][0];
2094 maXForm
.eM12
= cF
[0][1];
2095 maXForm
.eM21
= cF
[1][0];
2096 maXForm
.eM22
= cF
[1][1];
2097 maXForm
.eDx
= cF
[2][0];
2098 maXForm
.eDy
= cF
[2][1];
2103 SetWorldTransform(rXForm
);
2109 void MtfTools::Push() // !! to be able to access the original ClipRegion it
2110 { // is not allowed to use the MetaPushAction()
2111 UpdateClipRegion(); // (the original clip region is on top of the stack) (SJ)
2112 std::shared_ptr
<SaveStruct
> pSave( new SaveStruct
);
2114 pSave
->aLineStyle
= maLineStyle
;
2115 pSave
->aFillStyle
= maFillStyle
;
2117 pSave
->aFont
= maFont
;
2118 pSave
->aTextColor
= maTextColor
;
2119 pSave
->nTextAlign
= mnTextAlign
;
2120 pSave
->nTextLayoutMode
= mnTextLayoutMode
;
2121 pSave
->nMapMode
= mnMapMode
;
2122 pSave
->nGfxMode
= mnGfxMode
;
2123 pSave
->nBkMode
= mnBkMode
;
2124 pSave
->aBkColor
= maBkColor
;
2125 pSave
->bFillStyleSelected
= mbFillStyleSelected
;
2127 pSave
->aActPos
= maActPos
;
2128 pSave
->aXForm
= maXForm
;
2129 pSave
->eRasterOp
= meRasterOp
;
2131 pSave
->nWinOrgX
= mnWinOrgX
;
2132 pSave
->nWinOrgY
= mnWinOrgY
;
2133 pSave
->nWinExtX
= mnWinExtX
;
2134 pSave
->nWinExtY
= mnWinExtY
;
2135 pSave
->nDevOrgX
= mnDevOrgX
;
2136 pSave
->nDevOrgY
= mnDevOrgY
;
2137 pSave
->nDevWidth
= mnDevWidth
;
2138 pSave
->nDevHeight
= mnDevHeight
;
2140 pSave
->maPathObj
= maPathObj
;
2141 pSave
->maClipPath
= maClipPath
;
2143 mvSaveStack
.push_back( pSave
);
2146 void MtfTools::Pop()
2148 // Get the latest data from the stack
2149 if( !mvSaveStack
.empty() )
2151 // Backup the current data on the stack
2152 std::shared_ptr
<SaveStruct
> pSave( mvSaveStack
.back() );
2154 maLineStyle
= pSave
->aLineStyle
;
2155 maFillStyle
= pSave
->aFillStyle
;
2157 maFont
= pSave
->aFont
;
2158 maTextColor
= pSave
->aTextColor
;
2159 mnTextAlign
= pSave
->nTextAlign
;
2160 mnTextLayoutMode
= pSave
->nTextLayoutMode
;
2161 mnBkMode
= pSave
->nBkMode
;
2162 mnGfxMode
= pSave
->nGfxMode
;
2163 mnMapMode
= pSave
->nMapMode
;
2164 maBkColor
= pSave
->aBkColor
;
2165 mbFillStyleSelected
= pSave
->bFillStyleSelected
;
2167 maActPos
= pSave
->aActPos
;
2168 maXForm
= pSave
->aXForm
;
2169 meRasterOp
= pSave
->eRasterOp
;
2171 mnWinOrgX
= pSave
->nWinOrgX
;
2172 mnWinOrgY
= pSave
->nWinOrgY
;
2173 mnWinExtX
= pSave
->nWinExtX
;
2174 mnWinExtY
= pSave
->nWinExtY
;
2175 mnDevOrgX
= pSave
->nDevOrgX
;
2176 mnDevOrgY
= pSave
->nDevOrgY
;
2177 mnDevWidth
= pSave
->nDevWidth
;
2178 mnDevHeight
= pSave
->nDevHeight
;
2180 maPathObj
= pSave
->maPathObj
;
2181 if ( ! ( maClipPath
== pSave
->maClipPath
) )
2183 maClipPath
= pSave
->maClipPath
;
2184 mbClipNeedsUpdate
= true;
2186 if ( meLatestRasterOp
!= meRasterOp
)
2188 mpGDIMetaFile
->AddAction( new MetaRasterOpAction( meRasterOp
) );
2189 meLatestRasterOp
= meRasterOp
;
2191 mvSaveStack
.pop_back();
2195 void MtfTools::AddFromGDIMetaFile( GDIMetaFile
& rGDIMetaFile
)
2197 rGDIMetaFile
.Play( *mpGDIMetaFile
);
2200 void MtfTools::PassEMFPlusHeaderInfo()
2202 EMFP_DEBUG(printf ("\t\t\tadd EMF_PLUS header info\n"));
2205 sal_Int32 nLeft
, nRight
, nTop
, nBottom
;
2207 nLeft
= mrclFrame
.Left();
2208 nTop
= mrclFrame
.Top();
2209 nRight
= mrclFrame
.Right();
2210 nBottom
= mrclFrame
.Bottom();
2213 mem
.WriteInt32( nLeft
).WriteInt32( nTop
).WriteInt32( nRight
).WriteInt32( nBottom
);
2214 mem
.WriteInt32( mnPixX
).WriteInt32( mnPixY
).WriteInt32( mnMillX
).WriteInt32( mnMillY
);
2221 // add transformation matrix to be used in vcl's metaact.cxx for
2222 // rotate and scale operations
2223 mem
.WriteFloat( one
).WriteFloat( zero
).WriteFloat( zero
).WriteFloat( one
).WriteFloat( zero
).WriteFloat( zero
);
2225 // need to flush the stream, otherwise GetEndOfData will return 0
2226 // on windows where the function parameters are probably resolved in reverse order
2229 mpGDIMetaFile
->AddAction( new MetaCommentAction( "EMF_PLUS_HEADER_INFO", 0, static_cast<const sal_uInt8
*>(mem
.GetData()), mem
.GetEndOfData() ) );
2230 mpGDIMetaFile
->UseCanvas( true );
2233 void MtfTools::PassEMFPlus( void const * pBuffer
, sal_uInt32 nLength
)
2235 EMFP_DEBUG(printf ("\t\t\tadd EMF_PLUS comment length %04x\n",(unsigned int) nLength
));
2236 mpGDIMetaFile
->AddAction( new MetaCommentAction( "EMF_PLUS", 0, static_cast<const sal_uInt8
*>(pBuffer
), nLength
) );
2240 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */