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 .
21 #include <basegfx/matrix/b2dhommatrix.hxx>
22 #include <basegfx/polygon/b2dpolypolygontools.hxx>
23 #include <vcl/metaact.hxx>
24 #include <vcl/graphictools.hxx>
25 #include <vcl/canvastools.hxx>
26 #include <vcl/metric.hxx>
27 #include <vcl/svapp.hxx>
28 #include <tools/fract.hxx>
29 #include <rtl/strbuf.hxx>
30 #include <rtl/tencinfo.h>
31 #include <vcl/virdev.hxx>
32 #include <o3tl/make_unique.hxx>
33 #include "officecfg/Setup.hxx"
34 #include "officecfg/Office/Linguistic.hxx"
35 #include "unotools/wincodepage.hxx"
37 #if OSL_DEBUG_LEVEL > 1
38 #define EMFP_DEBUG(x) x
43 void WinMtfClipPath::intersectClipRect( const Rectangle
& rRect
)
45 maClip
.intersectRange(
46 vcl::unotools::b2DRectangleFromRectangle(rRect
));
49 void WinMtfClipPath::excludeClipRect( const Rectangle
& rRect
)
52 vcl::unotools::b2DRectangleFromRectangle(rRect
));
55 void WinMtfClipPath::setClipPath( const tools::PolyPolygon
& rPolyPolygon
, sal_Int32 nClippingMode
)
57 const basegfx::B2DPolyPolygon
& rB2DPoly
=rPolyPolygon
.getB2DPolyPolygon();
58 switch ( nClippingMode
)
61 maClip
.unionPolyPolygon(rB2DPoly
);
64 maClip
.xorPolyPolygon(rB2DPoly
);
67 maClip
.subtractPolyPolygon(rB2DPoly
);
70 maClip
.intersectPolyPolygon(rB2DPoly
);
73 maClip
= basegfx::tools::B2DClipState(rB2DPoly
);
78 void WinMtfClipPath::moveClipRegion( const Size
& rSize
)
80 // what a weird concept. emulate, don't want this in B2DClipState
82 basegfx::B2DPolyPolygon aCurrClip
=maClip
.getClipPoly();
83 basegfx::B2DHomMatrix aTranslate
;
84 aTranslate
.translate(rSize
.Width(), rSize
.Height());
86 aCurrClip
.transform(aTranslate
);
87 maClip
= basegfx::tools::B2DClipState( aCurrClip
);
90 void WinMtfClipPath::setDefaultClipPath()
92 // Empty clip region - everything visible
93 maClip
= basegfx::tools::B2DClipState();
96 basegfx::B2DPolyPolygon
WinMtfClipPath::getClipPath() const
98 return maClip
.getClipPoly();
101 void WinMtfPathObj::AddPoint( const Point
& rPoint
)
104 Insert( tools::Polygon() );
105 tools::Polygon
& rPoly
= ((tools::PolyPolygon
&)*this)[ Count() - 1 ];
106 rPoly
.Insert( rPoly
.GetSize(), rPoint
);
110 void WinMtfPathObj::AddPolyLine( const tools::Polygon
& rPolyLine
)
113 Insert( tools::Polygon() );
114 tools::Polygon
& rPoly
= ((tools::PolyPolygon
&)*this)[ Count() - 1 ];
115 rPoly
.Insert( rPoly
.GetSize(), rPolyLine
);
119 void WinMtfPathObj::AddPolygon( const tools::Polygon
& rPoly
)
125 void WinMtfPathObj::AddPolyPolygon( const tools::PolyPolygon
& rPolyPoly
)
127 sal_uInt16 i
, nCount
= rPolyPoly
.Count();
128 for ( i
= 0; i
< nCount
; i
++ )
129 Insert( rPolyPoly
[ i
] );
133 void WinMtfPathObj::ClosePath()
137 tools::Polygon
& rPoly
= ((tools::PolyPolygon
&)*this)[ Count() - 1 ];
138 if ( rPoly
.GetSize() > 2 )
140 Point
aFirst( rPoly
[ 0 ] );
141 if ( aFirst
!= rPoly
[ rPoly
.GetSize() - 1 ] )
142 rPoly
.Insert( rPoly
.GetSize(), aFirst
);
150 OUString
getLODefaultLanguage()
152 OUString
result(officecfg::Office::Linguistic::General::DefaultLocale::get());
153 if (result
.isEmpty())
154 result
= officecfg::Setup::L10N::ooSetupSystemLocale::get();
160 WinMtfFontStyle::WinMtfFontStyle( LOGFONTW
& rFont
)
162 rtl_TextEncoding eCharSet
;
163 if ((rFont
.alfFaceName
== "Symbol")
164 || (rFont
.alfFaceName
== "MT Extra"))
165 eCharSet
= RTL_TEXTENCODING_SYMBOL
;
166 else if ((rFont
.lfCharSet
== DEFAULT_CHARSET
) || (rFont
.lfCharSet
== OEM_CHARSET
))
167 eCharSet
= utl_getWinTextEncodingFromLangStr(getLODefaultLanguage().toUtf8().getStr(),
168 rFont
.lfCharSet
== OEM_CHARSET
);
170 eCharSet
= rtl_getTextEncodingFromWindowsCharset( rFont
.lfCharSet
);
171 if ( eCharSet
== RTL_TEXTENCODING_DONTKNOW
)
172 eCharSet
= RTL_TEXTENCODING_MS_1252
;
173 aFont
.SetCharSet( eCharSet
);
174 aFont
.SetFamilyName( rFont
.alfFaceName
);
176 switch ( rFont
.lfPitchAndFamily
& 0xf0 )
179 eFamily
= FAMILY_ROMAN
;
183 eFamily
= FAMILY_SWISS
;
187 eFamily
= FAMILY_MODERN
;
191 eFamily
= FAMILY_SCRIPT
;
195 eFamily
= FAMILY_DECORATIVE
;
199 eFamily
= FAMILY_DONTKNOW
;
202 aFont
.SetFamily( eFamily
);
205 switch ( rFont
.lfPitchAndFamily
& 0x0f )
208 ePitch
= PITCH_FIXED
;
214 ePitch
= PITCH_VARIABLE
;
217 aFont
.SetPitch( ePitch
);
220 if (rFont
.lfWeight
== 0) // default weight SHOULD be used
221 eWeight
= WEIGHT_DONTKNOW
;
222 else if (rFont
.lfWeight
<= FW_THIN
)
223 eWeight
= WEIGHT_THIN
;
224 else if( rFont
.lfWeight
<= FW_ULTRALIGHT
)
225 eWeight
= WEIGHT_ULTRALIGHT
;
226 else if( rFont
.lfWeight
<= FW_LIGHT
)
227 eWeight
= WEIGHT_LIGHT
;
228 else if( rFont
.lfWeight
< FW_MEDIUM
)
229 eWeight
= WEIGHT_NORMAL
;
230 else if( rFont
.lfWeight
== FW_MEDIUM
)
231 eWeight
= WEIGHT_MEDIUM
;
232 else if( rFont
.lfWeight
<= FW_SEMIBOLD
)
233 eWeight
= WEIGHT_SEMIBOLD
;
234 else if( rFont
.lfWeight
<= FW_BOLD
)
235 eWeight
= WEIGHT_BOLD
;
236 else if( rFont
.lfWeight
<= FW_ULTRABOLD
)
237 eWeight
= WEIGHT_ULTRABOLD
;
239 eWeight
= WEIGHT_BLACK
;
240 aFont
.SetWeight( eWeight
);
243 aFont
.SetItalic( ITALIC_NORMAL
);
245 if( rFont
.lfUnderline
)
246 aFont
.SetUnderline( LINESTYLE_SINGLE
);
248 if( rFont
.lfStrikeOut
)
249 aFont
.SetStrikeout( STRIKEOUT_SINGLE
);
251 aFont
.SetOrientation( (short)rFont
.lfEscapement
);
253 Size
aFontSize( Size( rFont
.lfWidth
, rFont
.lfHeight
) );
254 if ( rFont
.lfHeight
> 0 )
256 // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
257 SolarMutexGuard aGuard
;
258 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
259 // converting the cell height into a font height
260 aFont
.SetFontSize( aFontSize
);
261 pVDev
->SetFont( aFont
);
262 FontMetric
aMetric( pVDev
->GetFontMetric() );
263 long nHeight
= aMetric
.GetAscent() + aMetric
.GetDescent();
266 double fHeight
= ((double)aFontSize
.Height() * rFont
.lfHeight
) / nHeight
;
267 aFontSize
.Height() = (sal_Int32
)( fHeight
+ 0.5 );
271 // Convert height to positive
272 aFontSize
.Height() = std::abs(aFontSize
.Height());
274 aFont
.SetFontSize(aFontSize
);
277 WinMtf::WinMtf( GDIMetaFile
& rGDIMetaFile
, SvStream
& rStreamWMF
, FilterConfigItem
* pConfigItem
)
278 : pOut( o3tl::make_unique
<WinMtfOutput
>(rGDIMetaFile
) )
279 , pWMF( &rStreamWMF
)
281 , pFilterConfigItem( pConfigItem
)
283 SvLockBytes
*pLB
= pWMF
->GetLockBytes();
285 pLB
->SetSynchronMode();
287 nStartPos
= pWMF
->Tell();
289 pOut
->SetDevOrg( Point() );
290 if ( pFilterConfigItem
)
292 xStatusIndicator
= pFilterConfigItem
->GetStatusIndicator();
293 if ( xStatusIndicator
.is() )
296 xStatusIndicator
->start( aMsg
, 100 );
303 if ( xStatusIndicator
.is() )
304 xStatusIndicator
->end();
307 void WinMtf::Callback( sal_uInt16 nPercent
)
309 if ( xStatusIndicator
.is() )
310 xStatusIndicator
->setValue( nPercent
);
313 Color
WinMtf::ReadColor()
316 pWMF
->ReadUInt32( nColor
);
317 return Color( (sal_uInt8
)nColor
, (sal_uInt8
)( nColor
>> 8 ), (sal_uInt8
)( nColor
>> 16 ) );
320 Point
WinMtfOutput::ImplScale(const Point
& rPoint
) // Hack to set varying defaults for incompletely defined files.
323 return Point(rPoint
.X() * UNDOCUMENTED_WIN_RCL_RELATION
- mrclFrame
.Left(),
324 rPoint
.Y() * UNDOCUMENTED_WIN_RCL_RELATION
- mrclFrame
.Top());
329 Point
WinMtfOutput::ImplMap( const Point
& rPt
)
331 if ( mnWinExtX
&& mnWinExtY
)
336 double fX2
= fX
* maXForm
.eM11
+ fY
* maXForm
.eM21
+ maXForm
.eDx
;
337 double fY2
= fX
* maXForm
.eM12
+ fY
* maXForm
.eM22
+ maXForm
.eDy
;
339 if ( mnGfxMode
== GM_COMPATIBLE
)
347 fX2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
*10;
348 fY2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
*10;
357 fX2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
;
358 fY2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
;
367 fX2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
/MILLIINCH_PER_TWIPS
;
368 fY2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
/MILLIINCH_PER_TWIPS
;
383 case MM_HIMETRIC
: // in hundredth of a millimeter
400 fY2
+= mnDevOrgY
; // fX2, fY2 now in device units
401 fX2
*= (double)mnMillX
* 100.0 / (double)mnPixX
;
402 fY2
*= (double)mnMillY
* 100.0 / (double)mnPixY
;
406 fX2
-= mrclFrame
.Left();
407 fY2
-= mrclFrame
.Top();
409 return Point( FRound( fX2
), FRound( fY2
) );
415 Size
WinMtfOutput::ImplMap(const Size
& rSz
, bool bDoWorldTransform
)
417 if ( mnWinExtX
&& mnWinExtY
)
419 // #i121382# apply the whole WorldTransform, else a rotation will be misinterpreted
420 double fWidth
, fHeight
;
421 if (bDoWorldTransform
)
423 fWidth
= rSz
.Width() * maXForm
.eM11
+ rSz
.Height() * maXForm
.eM21
;
424 fHeight
= rSz
.Width() * maXForm
.eM12
+ rSz
.Height() * maXForm
.eM22
;
428 //take the scale, but not the rotation
429 basegfx::B2DHomMatrix
aMatrix(maXForm
.eM11
, maXForm
.eM12
, 0,
430 maXForm
.eM21
, maXForm
.eM22
, 0);
431 basegfx::B2DTuple aScale
, aTranslate
;
432 double fRotate
, fShearX
;
433 if (!aMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
))
438 fWidth
= rSz
.Width() * aScale
.getX();
439 fHeight
= rSz
.Height() * aScale
.getY();
442 if ( mnGfxMode
== GM_COMPATIBLE
)
448 fWidth
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
*10;
449 fHeight
*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH
*10;
454 fWidth
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
;
455 fHeight
*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH
;
464 case MM_HIMETRIC
: // in hundredth of millimeters
471 fWidth
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
/MILLIINCH_PER_TWIPS
;
472 fHeight
*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH
/MILLIINCH_PER_TWIPS
;
478 fHeight
/= mnWinExtY
;
479 fWidth
*= mnDevWidth
;
480 fHeight
*= mnDevHeight
;
481 fWidth
*= (double)mnMillX
* 100 / (double)mnPixX
;
482 fHeight
*= (double)mnMillY
* 100 / (double)mnPixY
;
487 return Size( FRound( fWidth
), FRound( fHeight
) );
493 Rectangle
WinMtfOutput::ImplMap( const Rectangle
& rRect
)
495 return Rectangle( ImplMap( rRect
.TopLeft() ), ImplMap( rRect
.GetSize() ) );
498 void WinMtfOutput::ImplMap( vcl::Font
& rFont
)
500 // !!! HACK: we now always set the width to zero because the OS width is interpreted differently;
501 // must later be made portable in SV (KA 1996-02-08)
502 Size aFontSize
= ImplMap (rFont
.GetFontSize(), false);
504 if( aFontSize
.Height() < 0 )
505 aFontSize
.Height() *= -1;
507 rFont
.SetFontSize( aFontSize
);
509 if( ( mnWinExtX
* mnWinExtY
) < 0 )
510 rFont
.SetOrientation( 3600 - rFont
.GetOrientation() );
513 tools::Polygon
& WinMtfOutput::ImplMap( tools::Polygon
& rPolygon
)
515 sal_uInt16 nPoints
= rPolygon
.GetSize();
516 for ( sal_uInt16 i
= 0; i
< nPoints
; i
++ )
518 rPolygon
[ i
] = ImplMap( rPolygon
[ i
] );
523 void WinMtfOutput::ImplScale( tools::Polygon
& rPolygon
)
525 sal_uInt16 nPoints
= rPolygon
.GetSize();
526 for ( sal_uInt16 i
= 0; i
< nPoints
; i
++ )
528 rPolygon
[ i
] = ImplScale( rPolygon
[ i
] );
532 tools::PolyPolygon
& WinMtfOutput::ImplScale( tools::PolyPolygon
& rPolyPolygon
)
534 sal_uInt16 nPolys
= rPolyPolygon
.Count();
535 for (sal_uInt16 i
= 0; i
< nPolys
; ++i
)
537 ImplScale(rPolyPolygon
[i
]);
542 tools::PolyPolygon
& WinMtfOutput::ImplMap( tools::PolyPolygon
& rPolyPolygon
)
544 sal_uInt16 nPolys
= rPolyPolygon
.Count();
545 for ( sal_uInt16 i
= 0; i
< nPolys
; ImplMap( rPolyPolygon
[ i
++ ] ) ) ;
549 void WinMtfOutput::SelectObject( sal_Int32 nIndex
)
551 if ( nIndex
& ENHMETA_STOCK_OBJECT
)
553 sal_uInt16 nStockId
= (sal_uInt8
)nIndex
;
558 maFillStyle
= WinMtfFillStyle( Color( COL_WHITE
) );
559 mbFillStyleSelected
= true;
564 maFillStyle
= WinMtfFillStyle( Color( COL_LIGHTGRAY
) );
565 mbFillStyleSelected
= true;
571 maFillStyle
= WinMtfFillStyle( Color( COL_GRAY
) );
572 mbFillStyleSelected
= true;
577 maFillStyle
= WinMtfFillStyle( Color( COL_BLACK
) );
578 mbFillStyleSelected
= true;
583 maFillStyle
= WinMtfFillStyle( Color( COL_TRANSPARENT
), true );
584 mbFillStyleSelected
= true;
589 maLineStyle
= WinMtfLineStyle( Color( COL_WHITE
) );
594 maLineStyle
= WinMtfLineStyle( Color( COL_BLACK
) );
599 maLineStyle
= WinMtfLineStyle( Color( COL_TRANSPARENT
), true );
608 nIndex
&= 0xffff; // safety check: don't allow index to be > 65535
610 GDIObj
*pGDIObj
= nullptr;
612 if ( (sal_uInt32
)nIndex
< vGDIObj
.size() )
613 pGDIObj
= vGDIObj
[ nIndex
].get();
617 const auto pen
= dynamic_cast<WinMtfLineStyle
*>(pGDIObj
);
621 const auto brush
= dynamic_cast<WinMtfFillStyle
*>(pGDIObj
);
624 maFillStyle
= *brush
;
625 mbFillStyleSelected
= true;
628 const auto font
= dynamic_cast<WinMtfFontStyle
*>(pGDIObj
);
630 maFont
= font
->aFont
;
635 void WinMtfOutput::SetTextLayoutMode( ComplexTextLayoutFlags nTextLayoutMode
)
637 mnTextLayoutMode
= nTextLayoutMode
;
640 void WinMtfOutput::SetBkMode( BkMode nMode
)
645 void WinMtfOutput::SetBkColor( const Color
& rColor
)
650 void WinMtfOutput::SetTextColor( const Color
& rColor
)
652 maTextColor
= rColor
;
655 void WinMtfOutput::SetTextAlign( sal_uInt32 nAlign
)
657 mnTextAlign
= nAlign
;
660 void WinMtfOutput::ImplResizeObjectArry( sal_uInt32 nNewEntrys
)
662 vGDIObj
.resize(nNewEntrys
);
665 void WinMtfOutput::ImplDrawClippedPolyPolygon( const tools::PolyPolygon
& rPolyPoly
)
667 if ( rPolyPoly
.Count() )
669 ImplSetNonPersistentLineColorTransparenz();
670 if ( rPolyPoly
.Count() == 1 )
672 if ( rPolyPoly
.IsRect() )
673 mpGDIMetaFile
->AddAction( new MetaRectAction( rPolyPoly
.GetBoundRect() ) );
676 tools::Polygon
aPoly( rPolyPoly
[ 0 ] );
677 sal_uInt16 nCount
= aPoly
.GetSize();
680 if ( aPoly
[ nCount
- 1 ] != aPoly
[ 0 ] )
682 Point
aPoint( aPoly
[ 0 ] );
683 aPoly
.Insert( nCount
, aPoint
);
685 mpGDIMetaFile
->AddAction( new MetaPolygonAction( aPoly
) );
690 mpGDIMetaFile
->AddAction( new MetaPolyPolygonAction( rPolyPoly
) );
694 void WinMtfOutput::CreateObject( std::unique_ptr
<GDIObj
> pObject
)
698 const auto pLineStyle
= dynamic_cast<WinMtfLineStyle
*>(pObject
.get());
699 const auto pFontStyle
= dynamic_cast<WinMtfFontStyle
*>(pObject
.get());
703 if (pFontStyle
->aFont
.GetFontHeight() == 0)
704 pFontStyle
->aFont
.SetFontHeight(423);
705 ImplMap(pFontStyle
->aFont
); // defaulting to 12pt
707 else if ( pLineStyle
)
709 Size
aSize(pLineStyle
->aLineInfo
.GetWidth(), 0);
710 aSize
= ImplMap(aSize
);
711 pLineStyle
->aLineInfo
.SetWidth(aSize
.Width());
715 for ( nIndex
= 0; nIndex
< vGDIObj
.size(); nIndex
++ )
717 if ( !vGDIObj
[ nIndex
] )
720 if ( nIndex
== vGDIObj
.size() )
721 ImplResizeObjectArry( vGDIObj
.size() + 16 );
723 vGDIObj
[ nIndex
] = std::move(pObject
);
726 void WinMtfOutput::CreateObjectIndexed( sal_Int32 nIndex
, std::unique_ptr
<GDIObj
> pObject
)
728 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
730 nIndex
&= 0xffff; // safety check: do not allow index to be > 65535
733 const auto pLineStyle
= dynamic_cast<WinMtfLineStyle
*>(pObject
.get());
734 const auto pFontStyle
= dynamic_cast<WinMtfFontStyle
*>(pObject
.get());
737 if (pFontStyle
->aFont
.GetFontHeight() == 0)
738 pFontStyle
->aFont
.SetFontHeight(423);
739 ImplMap(pFontStyle
->aFont
);
741 else if ( pLineStyle
)
743 Size
aSize(pLineStyle
->aLineInfo
.GetWidth(), 0);
744 pLineStyle
->aLineInfo
.SetWidth( ImplMap(aSize
).Width() );
746 if ( pLineStyle
->aLineInfo
.GetStyle() == LineStyle::Dash
)
749 long nDotLen
= ImplMap( aSize
).Width();
750 pLineStyle
->aLineInfo
.SetDistance( nDotLen
);
751 pLineStyle
->aLineInfo
.SetDotLen( nDotLen
);
752 pLineStyle
->aLineInfo
.SetDashLen( nDotLen
* 3 );
756 if ( (sal_uInt32
)nIndex
>= vGDIObj
.size() )
757 ImplResizeObjectArry( nIndex
+ 16 );
759 vGDIObj
[ nIndex
] = std::move(pObject
);
763 void WinMtfOutput::DeleteObject( sal_Int32 nIndex
)
765 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
767 if ( (sal_uInt32
)nIndex
< vGDIObj
.size() )
769 vGDIObj
[ nIndex
].reset();
774 void WinMtfOutput::IntersectClipRect( const Rectangle
& rRect
)
776 mbClipNeedsUpdate
=true;
777 if ((rRect
.Left()-rRect
.Right()==0) && (rRect
.Top()-rRect
.Bottom()==0))
779 return; // empty rectangles cause trouble
781 aClipPath
.intersectClipRect( ImplMap( rRect
) );
784 void WinMtfOutput::ExcludeClipRect( const Rectangle
& rRect
)
786 mbClipNeedsUpdate
=true;
787 aClipPath
.excludeClipRect( ImplMap( rRect
) );
790 void WinMtfOutput::MoveClipRegion( const Size
& rSize
)
792 mbClipNeedsUpdate
=true;
793 aClipPath
.moveClipRegion( ImplMap( rSize
) );
796 void WinMtfOutput::SetClipPath( const tools::PolyPolygon
& rPolyPolygon
, sal_Int32 nClippingMode
, bool bIsMapped
)
798 mbClipNeedsUpdate
= true;
799 tools::PolyPolygon
aPolyPolygon(rPolyPolygon
);
803 if (!mbIsMapDevSet
&& (mnMapMode
== MM_ISOTROPIC
|| mnMapMode
== MM_ANISOTROPIC
))
804 aPolyPolygon
= ImplScale(aPolyPolygon
);
806 aPolyPolygon
= ImplMap(aPolyPolygon
);
808 aClipPath
.setClipPath(aPolyPolygon
, nClippingMode
);
811 void WinMtfOutput::SetDefaultClipPath()
813 mbClipNeedsUpdate
= true;
814 aClipPath
.setDefaultClipPath();
817 WinMtfOutput::WinMtfOutput( GDIMetaFile
& rGDIMetaFile
) :
818 mnLatestTextAlign ( 0 ),
819 mnTextAlign ( TA_LEFT
| TA_TOP
| TA_NOUPDATECP
),
820 maLatestBkColor ( 0x12345678 ),
821 maBkColor ( COL_WHITE
),
822 mnLatestTextLayoutMode( ComplexTextLayoutFlags::Default
),
823 mnTextLayoutMode ( ComplexTextLayoutFlags::Default
),
824 mnLatestBkMode ( BkMode::NONE
),
825 mnBkMode ( BkMode::OPAQUE
),
826 meLatestRasterOp ( RasterOp::Invert
),
827 meRasterOp ( RasterOp::OverPaint
),
828 maActPos ( Point() ),
830 mbFillStyleSelected ( false ),
831 mbClipNeedsUpdate ( true ),
832 mbComplexClip ( false ),
833 mnGfxMode ( GM_COMPATIBLE
),
834 mnMapMode ( MM_TEXT
),
847 mpGDIMetaFile ( &rGDIMetaFile
)
849 mbIsMapWinSet
= false;
850 mbIsMapDevSet
= false;
851 mpGDIMetaFile
->AddAction( new MetaPushAction( PushFlags::CLIPREGION
) ); // The original clipregion has to be on top
852 // of the stack so it can always be restored
853 // this is necessary to be able to support
854 // SetClipRgn( NULL ) and similar ClipRgn actions (SJ)
856 maFont
.SetFamilyName( "Arial" ); // sj: #i57205#, we do have some scaling problems if using
857 maFont
.SetCharSet( RTL_TEXTENCODING_MS_1252
); // the default font then most times a x11 font is used, we
858 maFont
.SetFontHeight( 423 ); // will prevent this defining a font
860 maLatestLineStyle
.aLineColor
= Color( 0x12, 0x34, 0x56 );
861 maLatestFillStyle
.aFillColor
= Color( 0x12, 0x34, 0x56 );
863 mnRop
= WMFRasterOp::Black
;
864 meRasterOp
= RasterOp::OverPaint
;
865 mpGDIMetaFile
->AddAction( new MetaRasterOpAction( RasterOp::OverPaint
) );
868 WinMtfOutput::~WinMtfOutput()
870 mpGDIMetaFile
->AddAction( new MetaPopAction() );
871 mpGDIMetaFile
->SetPrefMapMode( MapUnit::Map100thMM
);
872 if ( mrclFrame
.IsEmpty() )
873 mpGDIMetaFile
->SetPrefSize( Size( mnDevWidth
, mnDevHeight
) );
875 mpGDIMetaFile
->SetPrefSize( mrclFrame
.GetSize() );
878 void WinMtfOutput::UpdateClipRegion()
880 if ( mbClipNeedsUpdate
)
882 mbClipNeedsUpdate
= false;
883 mbComplexClip
= false;
885 mpGDIMetaFile
->AddAction( new MetaPopAction() ); // taking the original clipregion
886 mpGDIMetaFile
->AddAction( new MetaPushAction( PushFlags::CLIPREGION
) );
888 // skip for 'no clipping at all' case
889 if( !aClipPath
.isEmpty() )
891 const basegfx::B2DPolyPolygon
& rClipPoly( aClipPath
.getClipPath() );
892 mpGDIMetaFile
->AddAction(
893 new MetaISectRectClipRegionAction(
894 vcl::unotools::rectangleFromB2DRectangle(
895 rClipPoly
.getB2DRange())));
897 mbComplexClip
= rClipPoly
.count() > 1
898 || !basegfx::tools::isRectangle(rClipPoly
);
903 void WinMtfOutput::ImplSetNonPersistentLineColorTransparenz()
905 Color
aColor( COL_TRANSPARENT
);
906 WinMtfLineStyle
aTransparentLine( aColor
, true );
907 if ( ! ( maLatestLineStyle
== aTransparentLine
) )
909 maLatestLineStyle
= aTransparentLine
;
910 mpGDIMetaFile
->AddAction( new MetaLineColorAction( aTransparentLine
.aLineColor
, !aTransparentLine
.bTransparent
) );
914 void WinMtfOutput::UpdateLineStyle()
916 if (!( maLatestLineStyle
== maLineStyle
) )
918 maLatestLineStyle
= maLineStyle
;
919 mpGDIMetaFile
->AddAction( new MetaLineColorAction( maLineStyle
.aLineColor
, !maLineStyle
.bTransparent
) );
923 void WinMtfOutput::UpdateFillStyle()
925 if ( !mbFillStyleSelected
) // SJ: #i57205# taking care of bkcolor if no brush is selected
926 maFillStyle
= WinMtfFillStyle( maBkColor
, mnBkMode
== BkMode::Transparent
);
927 if (!( maLatestFillStyle
== maFillStyle
) )
929 maLatestFillStyle
= maFillStyle
;
930 if (maFillStyle
.aType
== WinMtfFillStyleType::Solid
)
931 mpGDIMetaFile
->AddAction( new MetaFillColorAction( maFillStyle
.aFillColor
, !maFillStyle
.bTransparent
) );
935 WMFRasterOp
WinMtfOutput::SetRasterOp( WMFRasterOp nRasterOp
)
937 WMFRasterOp nRetROP
= mnRop
;
938 if ( nRasterOp
!= mnRop
)
942 if ( mbNopMode
&& ( nRasterOp
!= WMFRasterOp::Nop
) )
943 { // changing modes from WMFRasterOp::Nop so set pen and brush
944 maFillStyle
= m_NopFillStyle
;
945 maLineStyle
= m_NopLineStyle
;
950 case WMFRasterOp::Not
:
951 meRasterOp
= RasterOp::Invert
;
954 case WMFRasterOp::XorPen
:
955 meRasterOp
= RasterOp::Xor
;
958 case WMFRasterOp::Nop
:
960 meRasterOp
= RasterOp::OverPaint
;
963 m_NopFillStyle
= maFillStyle
;
964 m_NopLineStyle
= maLineStyle
;
965 maFillStyle
= WinMtfFillStyle( Color( COL_TRANSPARENT
), true );
966 maLineStyle
= WinMtfLineStyle( Color( COL_TRANSPARENT
), true );
973 meRasterOp
= RasterOp::OverPaint
;
977 if ( nRetROP
!= nRasterOp
)
978 mpGDIMetaFile
->AddAction( new MetaRasterOpAction( meRasterOp
) );
982 void WinMtfOutput::StrokeAndFillPath( bool bStroke
, bool bFill
)
984 if ( aPathObj
.Count() )
993 mpGDIMetaFile
->AddAction( new MetaPushAction( PushFlags::LINECOLOR
) );
994 mpGDIMetaFile
->AddAction( new MetaLineColorAction( Color(), false ) );
996 if ( aPathObj
.Count() == 1 )
997 mpGDIMetaFile
->AddAction( new MetaPolygonAction( aPathObj
.GetObject( 0 ) ) );
999 mpGDIMetaFile
->AddAction( new MetaPolyPolygonAction( aPathObj
) );
1002 mpGDIMetaFile
->AddAction( new MetaPopAction() );
1006 sal_uInt16 i
, nCount
= aPathObj
.Count();
1007 for ( i
= 0; i
< nCount
; i
++ )
1008 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( aPathObj
[ i
], maLineStyle
.aLineInfo
) );
1014 void WinMtfOutput::DrawPixel( const Point
& rSource
, const Color
& rColor
)
1016 mpGDIMetaFile
->AddAction( new MetaPixelAction( ImplMap( rSource
), rColor
) );
1019 void WinMtfOutput::MoveTo( const Point
& rPoint
, bool bRecordPath
)
1021 Point
aDest( ImplMap( rPoint
) );
1024 // fdo#57353 create new subpath for subsequent moves
1025 if ( aPathObj
.Count() )
1026 if ( aPathObj
[ aPathObj
.Count() - 1 ].GetSize() )
1027 aPathObj
.Insert( tools::Polygon() );
1028 aPathObj
.AddPoint( aDest
);
1033 void WinMtfOutput::LineTo( const Point
& rPoint
, bool bRecordPath
)
1036 Point
aDest( ImplMap( rPoint
) );
1038 aPathObj
.AddPoint( aDest
);
1042 mpGDIMetaFile
->AddAction( new MetaLineAction( maActPos
, aDest
, maLineStyle
.aLineInfo
) );
1047 void WinMtfOutput::DrawRect( const Rectangle
& rRect
, bool bEdge
)
1052 if ( mbComplexClip
)
1054 tools::Polygon
aPoly( ImplMap( rRect
) );
1055 tools::PolyPolygon
aPolyPolyRect( aPoly
);
1056 tools::PolyPolygon aDest
;
1057 tools::PolyPolygon(aClipPath
.getClipPath()).GetIntersection( aPolyPolyRect
, aDest
);
1058 ImplDrawClippedPolyPolygon( aDest
);
1064 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1066 ImplSetNonPersistentLineColorTransparenz();
1067 mpGDIMetaFile
->AddAction( new MetaRectAction( ImplMap( rRect
) ) );
1069 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( ImplMap( rRect
) ),maLineStyle
.aLineInfo
) );
1074 mpGDIMetaFile
->AddAction( new MetaRectAction( ImplMap( rRect
) ) );
1079 ImplSetNonPersistentLineColorTransparenz();
1080 mpGDIMetaFile
->AddAction( new MetaRectAction( ImplMap( rRect
) ) );
1085 void WinMtfOutput::DrawRoundRect( const Rectangle
& rRect
, const Size
& rSize
)
1090 mpGDIMetaFile
->AddAction( new MetaRoundRectAction( ImplMap( rRect
), labs( ImplMap( rSize
).Width() ), labs( ImplMap( rSize
).Height() ) ) );
1093 void WinMtfOutput::DrawEllipse( const Rectangle
& rRect
)
1098 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1100 Point
aCenter( ImplMap( rRect
.Center() ) );
1101 Size
aRad( ImplMap( Size( rRect
.GetWidth() / 2, rRect
.GetHeight() / 2 ) ) );
1103 ImplSetNonPersistentLineColorTransparenz();
1104 mpGDIMetaFile
->AddAction( new MetaEllipseAction( ImplMap( rRect
) ) );
1106 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( aCenter
, aRad
.Width(), aRad
.Height() ), maLineStyle
.aLineInfo
) );
1111 mpGDIMetaFile
->AddAction( new MetaEllipseAction( ImplMap( rRect
) ) );
1115 void WinMtfOutput::DrawArc( const Rectangle
& rRect
, const Point
& rStart
, const Point
& rEnd
, bool bTo
)
1121 Rectangle
aRect( ImplMap( rRect
) );
1122 Point
aStart( ImplMap( rStart
) );
1123 Point
aEnd( ImplMap( rEnd
) );
1125 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1127 if ( aStart
== aEnd
)
1128 { // SJ: #i53768# if start & end is identical, then we have to draw a full ellipse
1129 Point
aCenter( aRect
.Center() );
1130 Size
aRad( aRect
.GetWidth() / 2, aRect
.GetHeight() / 2 );
1132 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( aCenter
, aRad
.Width(), aRad
.Height() ), maLineStyle
.aLineInfo
) );
1135 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( aRect
, aStart
, aEnd
, POLY_ARC
), maLineStyle
.aLineInfo
) );
1138 mpGDIMetaFile
->AddAction( new MetaArcAction( aRect
, aStart
, aEnd
) );
1144 void WinMtfOutput::DrawPie( const Rectangle
& rRect
, const Point
& rStart
, const Point
& rEnd
)
1149 Rectangle
aRect( ImplMap( rRect
) );
1150 Point
aStart( ImplMap( rStart
) );
1151 Point
aEnd( ImplMap( rEnd
) );
1153 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1155 ImplSetNonPersistentLineColorTransparenz();
1156 mpGDIMetaFile
->AddAction( new MetaPieAction( aRect
, aStart
, aEnd
) );
1158 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( aRect
, aStart
, aEnd
, POLY_PIE
), maLineStyle
.aLineInfo
) );
1163 mpGDIMetaFile
->AddAction( new MetaPieAction( aRect
, aStart
, aEnd
) );
1167 void WinMtfOutput::DrawChord( const Rectangle
& rRect
, const Point
& rStart
, const Point
& rEnd
)
1172 Rectangle
aRect( ImplMap( rRect
) );
1173 Point
aStart( ImplMap( rStart
) );
1174 Point
aEnd( ImplMap( rEnd
) );
1176 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1178 ImplSetNonPersistentLineColorTransparenz();
1179 mpGDIMetaFile
->AddAction( new MetaChordAction( aRect
, aStart
, aEnd
) );
1181 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( tools::Polygon( aRect
, aStart
, aEnd
, POLY_CHORD
), maLineStyle
.aLineInfo
) );
1186 mpGDIMetaFile
->AddAction( new MetaChordAction( aRect
, aStart
, aEnd
) );
1190 void WinMtfOutput::DrawPolygon( tools::Polygon
& rPolygon
, bool bRecordPath
)
1193 ImplMap( rPolygon
);
1195 aPathObj
.AddPolygon( rPolygon
);
1200 if ( mbComplexClip
)
1202 tools::PolyPolygon
aPolyPoly( rPolygon
);
1203 tools::PolyPolygon aDest
;
1204 tools::PolyPolygon(aClipPath
.getClipPath()).GetIntersection( aPolyPoly
, aDest
);
1205 ImplDrawClippedPolyPolygon( aDest
);
1209 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
) )
1211 sal_uInt16 nCount
= rPolygon
.GetSize();
1214 if ( rPolygon
[ nCount
- 1 ] != rPolygon
[ 0 ] )
1216 Point
aPoint( rPolygon
[ 0 ] );
1217 rPolygon
.Insert( nCount
, aPoint
);
1220 ImplSetNonPersistentLineColorTransparenz();
1221 mpGDIMetaFile
->AddAction( new MetaPolygonAction( rPolygon
) );
1223 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( rPolygon
, maLineStyle
.aLineInfo
) );
1229 if (maLatestFillStyle
.aType
!= WinMtfFillStyleType::Pattern
)
1230 mpGDIMetaFile
->AddAction( new MetaPolygonAction( rPolygon
) );
1232 SvtGraphicFill aFill
= SvtGraphicFill( tools::PolyPolygon( rPolygon
),
1235 SvtGraphicFill::fillNonZero
,
1236 SvtGraphicFill::fillTexture
,
1237 SvtGraphicFill::Transform(),
1239 SvtGraphicFill::hatchSingle
,
1241 SvtGraphicFill::gradientLinear
,
1245 Graphic (maLatestFillStyle
.aBmp
) );
1247 SvMemoryStream aMemStm
;
1249 WriteSvtGraphicFill( aMemStm
, aFill
);
1251 mpGDIMetaFile
->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_BEGIN", 0,
1252 static_cast<const sal_uInt8
*>(aMemStm
.GetData()),
1253 aMemStm
.Seek( STREAM_SEEK_TO_END
) ) );
1254 mpGDIMetaFile
->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_END" ) );
1262 void WinMtfOutput::DrawPolyPolygon( tools::PolyPolygon
& rPolyPolygon
, bool bRecordPath
)
1266 ImplMap( rPolyPolygon
);
1269 aPathObj
.AddPolyPolygon( rPolyPolygon
);
1274 if ( mbComplexClip
)
1276 tools::PolyPolygon aDest
;
1277 tools::PolyPolygon(aClipPath
.getClipPath()).GetIntersection( rPolyPolygon
, aDest
);
1278 ImplDrawClippedPolyPolygon( aDest
);
1283 mpGDIMetaFile
->AddAction( new MetaPolyPolygonAction( rPolyPolygon
) );
1284 if (maLineStyle
.aLineInfo
.GetWidth() > 0 || maLineStyle
.aLineInfo
.GetStyle() == LineStyle::Dash
)
1286 for (sal_uInt16 nPoly
= 0; nPoly
< rPolyPolygon
.Count(); ++nPoly
)
1288 mpGDIMetaFile
->AddAction(new MetaPolyLineAction(rPolyPolygon
[nPoly
], maLineStyle
.aLineInfo
));
1295 void WinMtfOutput::DrawPolyLine( tools::Polygon
& rPolygon
, bool bTo
, bool bRecordPath
)
1299 sal_uInt16 nPoints
= rPolygon
.GetSize();
1302 ImplMap( rPolygon
);
1305 rPolygon
[ 0 ] = maActPos
;
1306 maActPos
= rPolygon
[ rPolygon
.GetSize() - 1 ];
1309 aPathObj
.AddPolyLine( rPolygon
);
1313 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( rPolygon
, maLineStyle
.aLineInfo
) );
1318 void WinMtfOutput::DrawPolyBezier( tools::Polygon
& rPolygon
, bool bTo
, bool bRecordPath
)
1322 sal_uInt16 nPoints
= rPolygon
.GetSize();
1323 if ( ( nPoints
>= 4 ) && ( ( ( nPoints
- 4 ) % 3 ) == 0 ) )
1325 ImplMap( rPolygon
);
1328 rPolygon
[ 0 ] = maActPos
;
1329 maActPos
= rPolygon
[ nPoints
- 1 ];
1332 for ( i
= 0; ( i
+ 2 ) < nPoints
; )
1334 rPolygon
.SetFlags( i
++, PolyFlags::Normal
);
1335 rPolygon
.SetFlags( i
++, PolyFlags::Control
);
1336 rPolygon
.SetFlags( i
++, PolyFlags::Control
);
1339 aPathObj
.AddPolyLine( rPolygon
);
1343 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( rPolygon
, maLineStyle
.aLineInfo
) );
1348 void WinMtfOutput::DrawText( Point
& rPosition
, OUString
& rText
, long* pDXArry
, bool bRecordPath
, sal_Int32 nGfxMode
)
1351 rPosition
= ImplMap( rPosition
);
1352 sal_Int32 nOldGfxMode
= GetGfxMode();
1353 SetGfxMode( GM_COMPATIBLE
);
1359 sal_Int32 nLen
= rText
.getLength();
1361 for (i
= 0; i
< nLen
; i
++ )
1365 // #i121382# Map DXArray using WorldTransform
1366 const Size
aSize(ImplMap(Size(nSum
, 0)));
1367 const basegfx::B2DVector
aVector(aSize
.Width(), aSize
.Height());
1368 pDXArry
[i
- 1] = basegfx::fround(aVector
.getLength());
1373 if ( mnLatestTextLayoutMode
!= mnTextLayoutMode
)
1375 mnLatestTextLayoutMode
= mnTextLayoutMode
;
1376 mpGDIMetaFile
->AddAction( new MetaLayoutModeAction( mnTextLayoutMode
) );
1378 SetGfxMode( nGfxMode
);
1379 bool bChangeFont
= false;
1380 if ( mnLatestTextAlign
!= mnTextAlign
)
1383 mnLatestTextAlign
= mnTextAlign
;
1384 TextAlign eTextAlign
;
1385 if ( ( mnTextAlign
& TA_BASELINE
) == TA_BASELINE
)
1386 eTextAlign
= ALIGN_BASELINE
;
1387 else if( ( mnTextAlign
& TA_BOTTOM
) == TA_BOTTOM
)
1388 eTextAlign
= ALIGN_BOTTOM
;
1390 eTextAlign
= ALIGN_TOP
;
1391 mpGDIMetaFile
->AddAction( new MetaTextAlignAction( eTextAlign
) );
1393 if ( maLatestTextColor
!= maTextColor
)
1396 maLatestTextColor
= maTextColor
;
1397 mpGDIMetaFile
->AddAction( new MetaTextColorAction( maTextColor
) );
1399 bool bChangeFillColor
= false;
1400 if ( maLatestBkColor
!= maBkColor
)
1402 bChangeFillColor
= true;
1403 maLatestBkColor
= maBkColor
;
1405 if ( mnLatestBkMode
!= mnBkMode
)
1407 bChangeFillColor
= true;
1408 mnLatestBkMode
= mnBkMode
;
1410 if ( bChangeFillColor
)
1413 mpGDIMetaFile
->AddAction( new MetaTextFillColorAction( maFont
.GetFillColor(), !maFont
.IsTransparent() ) );
1415 vcl::Font
aTmp( maFont
);
1416 aTmp
.SetColor( maTextColor
);
1417 aTmp
.SetFillColor( maBkColor
);
1419 if( mnBkMode
== BkMode::Transparent
)
1420 aTmp
.SetTransparent( true );
1422 aTmp
.SetTransparent( false );
1424 if ( ( mnTextAlign
& TA_BASELINE
) == TA_BASELINE
)
1425 aTmp
.SetAlignment( ALIGN_BASELINE
);
1426 else if( ( mnTextAlign
& TA_BOTTOM
) == TA_BOTTOM
)
1427 aTmp
.SetAlignment( ALIGN_BOTTOM
);
1429 aTmp
.SetAlignment( ALIGN_TOP
);
1431 if ( nGfxMode
== GM_ADVANCED
)
1433 // check whether there is a font rotation applied via transformation
1434 Point
aP1( ImplMap( Point() ) );
1435 Point
aP2( ImplMap( Point( 0, 100 ) ) );
1438 double fX
= aP2
.X();
1439 double fY
= aP2
.Y();
1442 double fOrientation
= acos( fX
/ sqrt( fX
* fX
+ fY
* fY
) ) * 57.29577951308;
1444 fOrientation
= 360 - fOrientation
;
1447 fOrientation
+= aTmp
.GetOrientation();
1448 aTmp
.SetOrientation( sal_Int16( fOrientation
) );
1452 if( mnTextAlign
& ( TA_UPDATECP
| TA_RIGHT_CENTER
) )
1454 // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
1455 SolarMutexGuard aGuard
;
1456 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
1457 sal_Int32 nTextWidth
;
1458 pVDev
->SetMapMode( MapMode( MapUnit::Map100thMM
) );
1459 pVDev
->SetFont( maFont
);
1460 const sal_uInt32 nLen
= pDXArry
? rText
.getLength() : 0;
1463 nTextWidth
= pVDev
->GetTextWidth( OUString(rText
[ nLen
- 1 ]) );
1465 nTextWidth
+= pDXArry
[ nLen
- 2 ];
1468 nTextWidth
= pVDev
->GetTextWidth( rText
);
1470 if( mnTextAlign
& TA_UPDATECP
)
1471 rPosition
= maActPos
;
1473 if ( mnTextAlign
& TA_RIGHT_CENTER
)
1475 double fLength
= ( ( mnTextAlign
& TA_RIGHT_CENTER
) == TA_RIGHT
) ? nTextWidth
: nTextWidth
>> 1;
1476 rPosition
.X() -= (sal_Int32
)( fLength
* cos( maFont
.GetOrientation() * F_PI1800
) );
1477 rPosition
.Y() -= (sal_Int32
)(-( fLength
* sin( maFont
.GetOrientation() * F_PI1800
) ) );
1480 if( mnTextAlign
& TA_UPDATECP
)
1481 maActPos
.X() = rPosition
.X() + nTextWidth
;
1483 if ( bChangeFont
|| ( maLatestFont
!= aTmp
) )
1485 maLatestFont
= aTmp
;
1486 mpGDIMetaFile
->AddAction( new MetaFontAction( aTmp
) );
1487 mpGDIMetaFile
->AddAction( new MetaTextAlignAction( aTmp
.GetAlignment() ) );
1488 mpGDIMetaFile
->AddAction( new MetaTextColorAction( aTmp
.GetColor() ) );
1489 mpGDIMetaFile
->AddAction( new MetaTextFillColorAction( aTmp
.GetFillColor(), !aTmp
.IsTransparent() ) );
1497 /* because text without dx array is badly scaled, we
1498 will create such an array if necessary */
1499 long* pDX
= pDXArry
;
1502 // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
1503 SolarMutexGuard aGuard
;
1504 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
1505 pDX
= new long[ rText
.getLength() ];
1506 pVDev
->SetMapMode( MapUnit::Map100thMM
);
1507 pVDev
->SetFont( maLatestFont
);
1508 pVDev
->GetTextArray( rText
, pDX
, 0, rText
.getLength());
1510 mpGDIMetaFile
->AddAction( new MetaTextArrayAction( rPosition
, rText
, pDX
, 0, rText
.getLength() ) );
1511 if ( !pDXArry
) // this means we have created our own array
1512 delete[] pDX
; // which must be deleted
1514 SetGfxMode( nOldGfxMode
);
1517 void WinMtfOutput::ImplDrawBitmap( const Point
& rPos
, const Size
& rSize
, const BitmapEx
& rBitmap
)
1519 BitmapEx
aBmpEx( rBitmap
);
1520 if ( mbComplexClip
)
1522 VclPtrInstance
< VirtualDevice
> pVDev
;
1523 MapMode
aMapMode( MapUnit::Map100thMM
);
1524 aMapMode
.SetOrigin( Point( -rPos
.X(), -rPos
.Y() ) );
1525 const Size
aOutputSizePixel( pVDev
->LogicToPixel( rSize
, aMapMode
) );
1526 const Size
aSizePixel( rBitmap
.GetSizePixel() );
1527 if ( aOutputSizePixel
.Width() && aOutputSizePixel
.Height() )
1529 aMapMode
.SetScaleX( Fraction( aSizePixel
.Width(), aOutputSizePixel
.Width() ) );
1530 aMapMode
.SetScaleY( Fraction( aSizePixel
.Height(), aOutputSizePixel
.Height() ) );
1532 pVDev
->SetMapMode( aMapMode
);
1533 pVDev
->SetOutputSizePixel( aSizePixel
);
1534 pVDev
->SetFillColor( Color( COL_BLACK
) );
1535 const tools::PolyPolygon
aClip( aClipPath
.getClipPath() );
1536 pVDev
->DrawPolyPolygon( aClip
);
1537 const Point aEmptyPoint
;
1539 // #i50672# Extract whole VDev content (to match size of rBitmap)
1540 pVDev
->EnableMapMode( false );
1541 const Bitmap
aVDevMask(pVDev
->GetBitmap(aEmptyPoint
, aSizePixel
));
1543 if(aBmpEx
.IsTransparent())
1545 // bitmap already uses a Mask or Alpha, we need to blend that with
1546 // the new masking in pVDev
1547 if(aBmpEx
.IsAlpha())
1549 // need to blend in AlphaMask quality (8Bit)
1550 AlphaMask
fromVDev(aVDevMask
);
1551 AlphaMask
fromBmpEx(aBmpEx
.GetAlpha());
1552 AlphaMask::ScopedReadAccess
pR(fromVDev
);
1553 AlphaMask::ScopedWriteAccess
pW(fromBmpEx
);
1557 const long nWidth(std::min(pR
->Width(), pW
->Width()));
1558 const long nHeight(std::min(pR
->Height(), pW
->Height()));
1560 for(long nY(0); nY
< nHeight
; nY
++) for(long nX(0); nX
< nWidth
; nX
++)
1562 const sal_uInt8
nIndR(pR
->GetPixelIndex(nY
, nX
));
1563 const sal_uInt8
nIndW(pW
->GetPixelIndex(nY
, nX
));
1565 // these values represent transparency (0 == no, 255 == fully transparent),
1566 // so to blend these we have to multiply the inverse (opacity)
1567 // and re-invert the result to transparence
1568 const sal_uInt8
nCombined(0x00ff - (((0x00ff - nIndR
) * (0x00ff - nIndW
)) >> 8));
1570 pW
->SetPixelIndex(nY
, nX
, nCombined
);
1576 aBmpEx
= BitmapEx(aBmpEx
.GetBitmap(), fromBmpEx
);
1580 // need to blend in Mask quality (1Bit)
1581 Bitmap
aMask(aVDevMask
.CreateMask(Color(COL_WHITE
)));
1583 if ( rBitmap
.GetTransparentColor() == Color( COL_WHITE
) )
1585 aMask
.CombineSimple( rBitmap
.GetMask(), BmpCombine::Or
);
1589 aMask
.CombineSimple( rBitmap
.GetMask(), BmpCombine::And
);
1592 aBmpEx
= BitmapEx( rBitmap
.GetBitmap(), aMask
);
1597 // no mask yet, create and add new mask. For better quality, use Alpha,
1598 // this allows the drawn mask being processed with AnitAliasing (AAed)
1599 aBmpEx
= BitmapEx(rBitmap
.GetBitmap(), aVDevMask
);
1603 if ( aBmpEx
.IsTransparent() )
1604 mpGDIMetaFile
->AddAction( new MetaBmpExScaleAction( rPos
, rSize
, aBmpEx
) );
1606 mpGDIMetaFile
->AddAction( new MetaBmpScaleAction( rPos
, rSize
, aBmpEx
.GetBitmap() ) );
1609 void WinMtfOutput::ResolveBitmapActions( std::vector
<std::unique_ptr
<BSaveStruct
>>& rSaveList
)
1613 size_t nObjects
= rSaveList
.size();
1614 size_t nObjectsLeft
= nObjects
;
1616 while ( nObjectsLeft
)
1619 size_t nObjectsOfSameSize
= 0;
1620 size_t nObjectStartIndex
= nObjects
- nObjectsLeft
;
1622 BSaveStruct
* pSave
= rSaveList
[nObjectStartIndex
].get();
1623 Rectangle
aRect( pSave
->aOutRect
);
1625 for ( i
= nObjectStartIndex
; i
< nObjects
; )
1627 nObjectsOfSameSize
++;
1628 if ( ++i
< nObjects
)
1630 pSave
= rSaveList
[i
].get();
1631 if ( pSave
->aOutRect
!= aRect
)
1635 Point
aPos( ImplMap( aRect
.TopLeft() ) );
1636 Size
aSize( ImplMap( aRect
.GetSize() ) );
1638 for ( i
= nObjectStartIndex
; i
< ( nObjectStartIndex
+ nObjectsOfSameSize
); i
++ )
1640 pSave
= rSaveList
[i
].get();
1642 sal_uInt32 nWinRop
= pSave
->nWinRop
;
1643 sal_uInt8 nRasterOperation
= (sal_uInt8
)( nWinRop
>> 16 );
1645 sal_uInt32 nUsed
= 0;
1646 if ( ( nRasterOperation
& 0xf ) != ( nRasterOperation
>> 4 ) )
1647 nUsed
|= 1; // pattern is used
1648 if ( ( nRasterOperation
& 0x33 ) != ( ( nRasterOperation
& 0xcc ) >> 2 ) )
1649 nUsed
|= 2; // source is used
1650 if ( ( nRasterOperation
& 0xaa ) != ( ( nRasterOperation
& 0x55 ) << 1 ) )
1651 nUsed
|= 4; // destination is used
1653 if ( (nUsed
& 1) && (( nUsed
& 2 ) == 0) && nWinRop
!= PATINVERT
)
1654 { // patterns aren't well supported yet
1655 WMFRasterOp nOldRop
= SetRasterOp( WMFRasterOp::NONE
); // in this case nRasterOperation is either 0 or 0xff
1657 DrawRect( aRect
, false );
1658 SetRasterOp( nOldRop
);
1662 bool bDrawn
= false;
1664 if ( i
== nObjectStartIndex
) // optimizing, sometimes it is possible to create just one transparent bitmap
1666 if ( nObjectsOfSameSize
== 2 )
1668 BSaveStruct
* pSave2
= rSaveList
[i
+ 1].get();
1669 if ( ( pSave
->aBmpEx
.GetPrefSize() == pSave2
->aBmpEx
.GetPrefSize() ) &&
1670 ( pSave
->aBmpEx
.GetPrefMapMode() == pSave2
->aBmpEx
.GetPrefMapMode() ) )
1672 // TODO: Strictly speaking, we should
1673 // check whether mask is monochrome, and
1674 // whether image is black (upper branch)
1675 // or white (lower branch). Otherwise, the
1676 // effect is not the same as a masked
1678 if ( ( nWinRop
== SRCPAINT
) && ( pSave2
->nWinRop
== SRCAND
) )
1680 Bitmap
aMask( pSave
->aBmpEx
.GetBitmap() ); aMask
.Invert();
1681 BitmapEx
aBmpEx( pSave2
->aBmpEx
.GetBitmap(), aMask
);
1682 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1686 // #i20085# This is just the other way
1687 // around as above. Only difference: mask
1689 else if ( ( nWinRop
== SRCAND
) && ( pSave2
->nWinRop
== SRCPAINT
) )
1691 Bitmap
aMask( pSave
->aBmpEx
.GetBitmap() );
1692 BitmapEx
aBmpEx( pSave2
->aBmpEx
.GetBitmap(), aMask
);
1693 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1698 else if ( ( nWinRop
== SRCAND
) && ( pSave2
->nWinRop
== SRCINVERT
) )
1700 Bitmap
aMask( pSave
->aBmpEx
.GetBitmap() );
1701 BitmapEx
aBmpEx( pSave2
->aBmpEx
.GetBitmap(), aMask
);
1702 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1713 WMFRasterOp nOldRop
= SetRasterOp( WMFRasterOp::CopyPen
);
1714 Bitmap
aBitmap( pSave
->aBmpEx
.GetBitmap() );
1715 sal_uInt32 nOperation
= ( nRasterOperation
& 0xf );
1716 switch( nOperation
)
1721 if(pSave
->aBmpEx
.IsAlpha())
1723 ImplDrawBitmap( aPos
, aSize
, pSave
->aBmpEx
);
1727 SetRasterOp( WMFRasterOp::XorPen
);
1728 ImplDrawBitmap( aPos
, aSize
, aBitmap
);
1729 SetRasterOp( WMFRasterOp::CopyPen
);
1730 Bitmap
aMask( aBitmap
);
1732 BitmapEx
aBmpEx( aBitmap
, aMask
);
1733 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1734 if ( nOperation
== 0x1 )
1736 SetRasterOp( WMFRasterOp::Not
);
1737 DrawRect( aRect
, false );
1745 Bitmap
aMask( aBitmap
);
1746 if ( ( nUsed
& 1 ) && ( nRasterOperation
& 0xb0 ) == 0xb0 ) // pattern used
1748 aBitmap
.Convert( BmpConversion::N24Bit
);
1749 aBitmap
.Erase( maFillStyle
.aFillColor
);
1751 BitmapEx
aBmpEx( aBitmap
, aMask
);
1752 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1753 if ( nOperation
== 0x7 )
1755 SetRasterOp( WMFRasterOp::Not
);
1756 DrawRect( aRect
, false );
1764 SetRasterOp( WMFRasterOp::Not
);
1765 DrawRect( aRect
, false );
1766 SetRasterOp( WMFRasterOp::CopyPen
);
1767 Bitmap
aMask( aBitmap
);
1769 BitmapEx
aBmpEx( aBitmap
, aMask
);
1770 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1771 SetRasterOp( WMFRasterOp::XorPen
);
1772 ImplDrawBitmap( aPos
, aSize
, aBitmap
);
1773 if ( nOperation
== 0xb )
1775 SetRasterOp( WMFRasterOp::Not
);
1776 DrawRect( aRect
, false );
1784 Bitmap
aMask( aBitmap
);
1786 BitmapEx
aBmpEx( aBitmap
, aMask
);
1787 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1788 SetRasterOp( WMFRasterOp::XorPen
);
1789 ImplDrawBitmap( aPos
, aSize
, aBitmap
);
1790 if ( nOperation
== 0xd )
1792 SetRasterOp( WMFRasterOp::Not
);
1793 DrawRect( aRect
, false );
1800 SetRasterOp( WMFRasterOp::XorPen
);
1801 ImplDrawBitmap( aPos
, aSize
, aBitmap
);
1802 if ( nOperation
== 0x9 )
1804 SetRasterOp( WMFRasterOp::Not
);
1805 DrawRect( aRect
, false );
1810 case 0x0 : // WHITENESS
1811 case 0xf : // BLACKNESS
1812 { // in this case nRasterOperation is either 0 or 0xff
1813 maFillStyle
= WinMtfFillStyle( Color( nRasterOperation
, nRasterOperation
, nRasterOperation
) );
1815 DrawRect( aRect
, false );
1819 case 0x3 : // only source is used
1822 if ( nRasterOperation
== 0x33 )
1824 ImplDrawBitmap( aPos
, aSize
, aBitmap
);
1828 case 0x5 : // only destination is used
1830 SetRasterOp( WMFRasterOp::Not
);
1831 DrawRect( aRect
, false );
1835 case 0xa : // no operation
1838 SetRasterOp( nOldRop
);
1843 nObjectsLeft
-= nObjectsOfSameSize
;
1849 void WinMtfOutput::SetDevOrg( const Point
& rPoint
)
1851 mnDevOrgX
= rPoint
.X();
1852 mnDevOrgY
= rPoint
.Y();
1855 void WinMtfOutput::SetDevOrgOffset( sal_Int32 nXAdd
, sal_Int32 nYAdd
)
1861 void WinMtfOutput::SetDevExt( const Size
& rSize
,bool regular
)
1863 if ( rSize
.Width() && rSize
.Height() )
1868 case MM_ANISOTROPIC
:
1870 mnDevWidth
= rSize
.Width();
1871 mnDevHeight
= rSize
.Height();
1881 void WinMtfOutput::ScaleDevExt( double fX
, double fY
)
1883 mnDevWidth
= FRound( mnDevWidth
* fX
);
1884 mnDevHeight
= FRound( mnDevHeight
* fY
);
1887 void WinMtfOutput::SetWinOrg( const Point
& rPoint
, bool bIsEMF
)
1889 mnWinOrgX
= rPoint
.X();
1890 mnWinOrgY
= rPoint
.Y();
1898 void WinMtfOutput::SetWinOrgOffset( sal_Int32 nXAdd
, sal_Int32 nYAdd
)
1904 void WinMtfOutput::SetDevByWin() //mnWinExt...-stuff has to be assigned before.
1908 if ( mnMapMode
== MM_ISOTROPIC
) //TODO: WHAT ABOUT ANISOTROPIC???
1910 Size
aSize( (mnWinExtX
+ mnWinOrgX
) >> MS_FIXPOINT_BITCOUNT_28_4
,
1911 -((mnWinExtY
- mnWinOrgY
) >> MS_FIXPOINT_BITCOUNT_28_4
));
1913 SetDevExt(aSize
, false);
1918 void WinMtfOutput::SetWinExt(const Size
& rSize
, bool bIsEMF
)
1920 if (rSize
.Width() && rSize
.Height())
1925 case MM_ANISOTROPIC
:
1927 mnWinExtX
= rSize
.Width();
1928 mnWinExtY
= rSize
.Height();
1933 mbIsMapWinSet
= true;
1939 void WinMtfOutput::ScaleWinExt( double fX
, double fY
)
1941 mnWinExtX
= FRound( mnWinExtX
* fX
);
1942 mnWinExtY
= FRound( mnWinExtY
* fY
);
1945 void WinMtfOutput::SetrclBounds( const Rectangle
& rRect
)
1950 void WinMtfOutput::SetrclFrame( const Rectangle
& rRect
)
1955 void WinMtfOutput::SetRefPix( const Size
& rSize
)
1957 mnPixX
= rSize
.Width();
1958 mnPixY
= rSize
.Height();
1961 void WinMtfOutput::SetRefMill( const Size
& rSize
)
1963 mnMillX
= rSize
.Width();
1964 mnMillY
= rSize
.Height();
1967 void WinMtfOutput::SetMapMode( sal_uInt32 nMapMode
)
1969 mnMapMode
= nMapMode
;
1970 if ( nMapMode
== MM_TEXT
&& !mbIsMapWinSet
)
1972 mnWinExtX
= mnDevWidth
;
1973 mnWinExtY
= mnDevHeight
;
1975 else if ( mnMapMode
== MM_HIMETRIC
)
1977 mnWinExtX
= mnMillX
* 100;
1978 mnWinExtY
= mnMillY
* 100;
1982 void WinMtfOutput::SetWorldTransform( const XForm
& rXForm
)
1984 maXForm
.eM11
= rXForm
.eM11
;
1985 maXForm
.eM12
= rXForm
.eM12
;
1986 maXForm
.eM21
= rXForm
.eM21
;
1987 maXForm
.eM22
= rXForm
.eM22
;
1988 maXForm
.eDx
= rXForm
.eDx
;
1989 maXForm
.eDy
= rXForm
.eDy
;
1992 void WinMtfOutput::ModifyWorldTransform( const XForm
& rXForm
, sal_uInt32 nMode
)
1998 maXForm
.eM11
= maXForm
.eM22
= 1.0f
;
1999 maXForm
.eM12
= maXForm
.eM21
= maXForm
.eDx
= maXForm
.eDy
= 0.0f
;
2003 case MWT_RIGHTMULTIPLY
:
2004 case MWT_LEFTMULTIPLY
:
2007 const XForm
* pRight
;
2009 if ( nMode
== MWT_LEFTMULTIPLY
)
2024 aF
[0][0] = pLeft
->eM11
;
2025 aF
[0][1] = pLeft
->eM12
;
2027 aF
[1][0] = pLeft
->eM21
;
2028 aF
[1][1] = pLeft
->eM22
;
2030 aF
[2][0] = pLeft
->eDx
;
2031 aF
[2][1] = pLeft
->eDy
;
2034 bF
[0][0] = pRight
->eM11
;
2035 bF
[0][1] = pRight
->eM12
;
2037 bF
[1][0] = pRight
->eM21
;
2038 bF
[1][1] = pRight
->eM22
;
2040 bF
[2][0] = pRight
->eDx
;
2041 bF
[2][1] = pRight
->eDy
;
2045 for ( i
= 0; i
< 3; i
++ )
2047 for ( j
= 0; j
< 3; j
++ )
2050 for ( k
= 0; k
< 3; k
++ )
2051 cF
[i
][j
] += aF
[i
][k
] * bF
[k
][j
];
2054 maXForm
.eM11
= cF
[0][0];
2055 maXForm
.eM12
= cF
[0][1];
2056 maXForm
.eM21
= cF
[1][0];
2057 maXForm
.eM22
= cF
[1][1];
2058 maXForm
.eDx
= cF
[2][0];
2059 maXForm
.eDy
= cF
[2][1];
2064 SetWorldTransform(rXForm
);
2070 void WinMtfOutput::Push() // !! to be able to access the original ClipRegion it
2071 { // is not allowed to use the MetaPushAction()
2072 UpdateClipRegion(); // (the original clip region is on top of the stack) (SJ)
2073 std::shared_ptr
<SaveStruct
> pSave( new SaveStruct
);
2075 pSave
->aLineStyle
= maLineStyle
;
2076 pSave
->aFillStyle
= maFillStyle
;
2078 pSave
->aFont
= maFont
;
2079 pSave
->aTextColor
= maTextColor
;
2080 pSave
->nTextAlign
= mnTextAlign
;
2081 pSave
->nTextLayoutMode
= mnTextLayoutMode
;
2082 pSave
->nMapMode
= mnMapMode
;
2083 pSave
->nGfxMode
= mnGfxMode
;
2084 pSave
->nBkMode
= mnBkMode
;
2085 pSave
->aBkColor
= maBkColor
;
2086 pSave
->bFillStyleSelected
= mbFillStyleSelected
;
2088 pSave
->aActPos
= maActPos
;
2089 pSave
->aXForm
= maXForm
;
2090 pSave
->eRasterOp
= meRasterOp
;
2092 pSave
->nWinOrgX
= mnWinOrgX
;
2093 pSave
->nWinOrgY
= mnWinOrgY
;
2094 pSave
->nWinExtX
= mnWinExtX
;
2095 pSave
->nWinExtY
= mnWinExtY
;
2096 pSave
->nDevOrgX
= mnDevOrgX
;
2097 pSave
->nDevOrgY
= mnDevOrgY
;
2098 pSave
->nDevWidth
= mnDevWidth
;
2099 pSave
->nDevHeight
= mnDevHeight
;
2101 pSave
->aPathObj
= aPathObj
;
2102 pSave
->aClipPath
= aClipPath
;
2104 vSaveStack
.push_back( pSave
);
2107 void WinMtfOutput::Pop()
2109 // Get the latest data from the stack
2110 if( !vSaveStack
.empty() )
2112 // Backup the current data on the stack
2113 std::shared_ptr
<SaveStruct
> pSave( vSaveStack
.back() );
2115 maLineStyle
= pSave
->aLineStyle
;
2116 maFillStyle
= pSave
->aFillStyle
;
2118 maFont
= pSave
->aFont
;
2119 maTextColor
= pSave
->aTextColor
;
2120 mnTextAlign
= pSave
->nTextAlign
;
2121 mnTextLayoutMode
= pSave
->nTextLayoutMode
;
2122 mnBkMode
= pSave
->nBkMode
;
2123 mnGfxMode
= pSave
->nGfxMode
;
2124 mnMapMode
= pSave
->nMapMode
;
2125 maBkColor
= pSave
->aBkColor
;
2126 mbFillStyleSelected
= pSave
->bFillStyleSelected
;
2128 maActPos
= pSave
->aActPos
;
2129 maXForm
= pSave
->aXForm
;
2130 meRasterOp
= pSave
->eRasterOp
;
2132 mnWinOrgX
= pSave
->nWinOrgX
;
2133 mnWinOrgY
= pSave
->nWinOrgY
;
2134 mnWinExtX
= pSave
->nWinExtX
;
2135 mnWinExtY
= pSave
->nWinExtY
;
2136 mnDevOrgX
= pSave
->nDevOrgX
;
2137 mnDevOrgY
= pSave
->nDevOrgY
;
2138 mnDevWidth
= pSave
->nDevWidth
;
2139 mnDevHeight
= pSave
->nDevHeight
;
2141 aPathObj
= pSave
->aPathObj
;
2142 if ( ! ( aClipPath
== pSave
->aClipPath
) )
2144 aClipPath
= pSave
->aClipPath
;
2145 mbClipNeedsUpdate
= true;
2147 if ( meLatestRasterOp
!= meRasterOp
)
2148 mpGDIMetaFile
->AddAction( new MetaRasterOpAction( meRasterOp
) );
2149 vSaveStack
.pop_back();
2153 void WinMtfOutput::AddFromGDIMetaFile( GDIMetaFile
& rGDIMetaFile
)
2155 rGDIMetaFile
.Play( *mpGDIMetaFile
);
2158 void WinMtfOutput::PassEMFPlusHeaderInfo()
2160 EMFP_DEBUG(printf ("\t\t\tadd EMF_PLUS header info\n"));
2163 sal_Int32 nLeft
, nRight
, nTop
, nBottom
;
2165 nLeft
= mrclFrame
.Left();
2166 nTop
= mrclFrame
.Top();
2167 nRight
= mrclFrame
.Right();
2168 nBottom
= mrclFrame
.Bottom();
2171 mem
.WriteInt32( nLeft
).WriteInt32( nTop
).WriteInt32( nRight
).WriteInt32( nBottom
);
2172 mem
.WriteInt32( mnPixX
).WriteInt32( mnPixY
).WriteInt32( mnMillX
).WriteInt32( mnMillY
);
2179 // add transformation matrix to be used in vcl's metaact.cxx for
2180 // rotate and scale operations
2181 mem
.WriteFloat( one
).WriteFloat( zero
).WriteFloat( zero
).WriteFloat( one
).WriteFloat( zero
).WriteFloat( zero
);
2183 // need to flush the stream, otherwise GetEndOfData will return 0
2184 // on windows where the function parameters are probably resolved in reverse order
2187 mpGDIMetaFile
->AddAction( new MetaCommentAction( "EMF_PLUS_HEADER_INFO", 0, static_cast<const sal_uInt8
*>(mem
.GetData()), mem
.GetEndOfData() ) );
2188 mpGDIMetaFile
->UseCanvas( true );
2191 void WinMtfOutput::PassEMFPlus( void* pBuffer
, sal_uInt32 nLength
)
2193 EMFP_DEBUG(printf ("\t\t\tadd EMF_PLUS comment length %04x\n",(unsigned int) nLength
));
2194 mpGDIMetaFile
->AddAction( new MetaCommentAction( "EMF_PLUS", 0, static_cast<const sal_uInt8
*>(pBuffer
), nLength
) );
2197 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */