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>
33 #if OSL_DEBUG_LEVEL > 1
34 #define EMFP_DEBUG(x) x
39 void WinMtfClipPath::intersectClipRect( const Rectangle
& rRect
)
41 maClip
.intersectRange(
42 vcl::unotools::b2DRectangleFromRectangle(rRect
));
45 void WinMtfClipPath::excludeClipRect( const Rectangle
& rRect
)
48 vcl::unotools::b2DRectangleFromRectangle(rRect
));
51 void WinMtfClipPath::setClipPath( const tools::PolyPolygon
& rPolyPolygon
, sal_Int32 nClippingMode
)
53 const basegfx::B2DPolyPolygon
& rB2DPoly
=rPolyPolygon
.getB2DPolyPolygon();
54 switch ( nClippingMode
)
57 maClip
.unionPolyPolygon(rB2DPoly
);
60 maClip
.xorPolyPolygon(rB2DPoly
);
63 maClip
.subtractPolyPolygon(rB2DPoly
);
66 maClip
.intersectPolyPolygon(rB2DPoly
);
69 maClip
= basegfx::tools::B2DClipState(rB2DPoly
);
74 void WinMtfClipPath::moveClipRegion( const Size
& rSize
)
76 // what a weird concept. emulate, don't want this in B2DClipState
78 basegfx::B2DPolyPolygon aCurrClip
=maClip
.getClipPoly();
79 basegfx::B2DHomMatrix aTranslate
;
80 aTranslate
.translate(rSize
.Width(), rSize
.Height());
82 aCurrClip
.transform(aTranslate
);
83 maClip
= basegfx::tools::B2DClipState( aCurrClip
);
86 void WinMtfClipPath::setDefaultClipPath()
88 // Empty clip region - everything visible
89 maClip
= basegfx::tools::B2DClipState();
92 basegfx::B2DPolyPolygon
WinMtfClipPath::getClipPath() const
94 return maClip
.getClipPoly();
97 void WinMtfPathObj::AddPoint( const Point
& rPoint
)
100 Insert( Polygon(), POLYPOLY_APPEND
);
101 Polygon
& rPoly
= ((tools::PolyPolygon
&)*this)[ Count() - 1 ];
102 rPoly
.Insert( rPoly
.GetSize(), rPoint
, POLY_NORMAL
);
106 void WinMtfPathObj::AddPolyLine( const Polygon
& rPolyLine
)
109 Insert( Polygon(), POLYPOLY_APPEND
);
110 Polygon
& rPoly
= ((tools::PolyPolygon
&)*this)[ Count() - 1 ];
111 rPoly
.Insert( rPoly
.GetSize(), rPolyLine
);
115 void WinMtfPathObj::AddPolygon( const Polygon
& rPoly
)
117 Insert( rPoly
, POLYPOLY_APPEND
);
121 void WinMtfPathObj::AddPolyPolygon( const tools::PolyPolygon
& rPolyPoly
)
123 sal_uInt16 i
, nCount
= rPolyPoly
.Count();
124 for ( i
= 0; i
< nCount
; i
++ )
125 Insert( rPolyPoly
[ i
], POLYPOLY_APPEND
);
129 void WinMtfPathObj::ClosePath()
133 Polygon
& rPoly
= ((tools::PolyPolygon
&)*this)[ Count() - 1 ];
134 if ( rPoly
.GetSize() > 2 )
136 Point
aFirst( rPoly
[ 0 ] );
137 if ( aFirst
!= rPoly
[ rPoly
.GetSize() - 1 ] )
138 rPoly
.Insert( rPoly
.GetSize(), aFirst
, POLY_NORMAL
);
144 WinMtfFontStyle::WinMtfFontStyle( LOGFONTW
& rFont
)
146 rtl_TextEncoding eCharSet
;
147 if ( ( rFont
.lfCharSet
== OEM_CHARSET
) || ( rFont
.lfCharSet
== DEFAULT_CHARSET
) )
148 eCharSet
= osl_getThreadTextEncoding();
150 eCharSet
= rtl_getTextEncodingFromWindowsCharset( rFont
.lfCharSet
);
151 if ( eCharSet
== RTL_TEXTENCODING_DONTKNOW
)
152 eCharSet
= RTL_TEXTENCODING_MS_1252
;
153 aFont
.SetCharSet( eCharSet
);
154 aFont
.SetName( rFont
.alfFaceName
);
156 switch ( rFont
.lfPitchAndFamily
& 0xf0 )
159 eFamily
= FAMILY_ROMAN
;
163 eFamily
= FAMILY_SWISS
;
167 eFamily
= FAMILY_MODERN
;
171 eFamily
= FAMILY_SCRIPT
;
175 eFamily
= FAMILY_DECORATIVE
;
179 eFamily
= FAMILY_DONTKNOW
;
182 aFont
.SetFamily( eFamily
);
185 switch ( rFont
.lfPitchAndFamily
& 0x0f )
188 ePitch
= PITCH_FIXED
;
194 ePitch
= PITCH_VARIABLE
;
197 aFont
.SetPitch( ePitch
);
200 if( rFont
.lfWeight
<= FW_THIN
)
201 eWeight
= WEIGHT_THIN
;
202 else if( rFont
.lfWeight
<= FW_ULTRALIGHT
)
203 eWeight
= WEIGHT_ULTRALIGHT
;
204 else if( rFont
.lfWeight
<= FW_LIGHT
)
205 eWeight
= WEIGHT_LIGHT
;
206 else if( rFont
.lfWeight
< FW_MEDIUM
)
207 eWeight
= WEIGHT_NORMAL
;
208 else if( rFont
.lfWeight
== FW_MEDIUM
)
209 eWeight
= WEIGHT_MEDIUM
;
210 else if( rFont
.lfWeight
<= FW_SEMIBOLD
)
211 eWeight
= WEIGHT_SEMIBOLD
;
212 else if( rFont
.lfWeight
<= FW_BOLD
)
213 eWeight
= WEIGHT_BOLD
;
214 else if( rFont
.lfWeight
<= FW_ULTRABOLD
)
215 eWeight
= WEIGHT_ULTRABOLD
;
217 eWeight
= WEIGHT_BLACK
;
218 aFont
.SetWeight( eWeight
);
221 aFont
.SetItalic( ITALIC_NORMAL
);
223 if( rFont
.lfUnderline
)
224 aFont
.SetUnderline( UNDERLINE_SINGLE
);
226 if( rFont
.lfStrikeOut
)
227 aFont
.SetStrikeout( STRIKEOUT_SINGLE
);
229 if ( rFont
.lfOrientation
)
230 aFont
.SetOrientation( (short)rFont
.lfOrientation
);
232 aFont
.SetOrientation( (short)rFont
.lfEscapement
);
234 Size
aFontSize( Size( rFont
.lfWidth
, rFont
.lfHeight
) );
235 if ( rFont
.lfHeight
> 0 )
237 // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
238 SolarMutexGuard aGuard
;
239 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
240 // converting the cell height into a font height
241 aFont
.SetSize( aFontSize
);
242 pVDev
->SetFont( aFont
);
243 FontMetric
aMetric( pVDev
->GetFontMetric() );
244 long nHeight
= aMetric
.GetAscent() + aMetric
.GetDescent();
247 double fHeight
= ((double)aFontSize
.Height() * rFont
.lfHeight
) / nHeight
;
248 aFontSize
.Height() = (sal_Int32
)( fHeight
+ 0.5 );
252 // Convert height to positive
253 aFontSize
.Height() = std::abs(aFontSize
.Height());
255 aFont
.SetSize(aFontSize
);
258 WinMtf::WinMtf( WinMtfOutput
* pWinMtfOutput
, SvStream
& rStreamWMF
, FilterConfigItem
* pConfigItem
)
259 : pOut( pWinMtfOutput
)
260 , pWMF( &rStreamWMF
)
262 , pFilterConfigItem( pConfigItem
)
264 SvLockBytes
*pLB
= pWMF
->GetLockBytes();
266 pLB
->SetSynchronMode( true );
268 nStartPos
= pWMF
->Tell();
270 pOut
->SetDevOrg( Point() );
271 if ( pFilterConfigItem
)
273 xStatusIndicator
= pFilterConfigItem
->GetStatusIndicator();
274 if ( xStatusIndicator
.is() )
277 xStatusIndicator
->start( aMsg
, 100 );
286 if ( xStatusIndicator
.is() )
287 xStatusIndicator
->end();
290 void WinMtf::Callback( sal_uInt16 nPercent
)
292 if ( xStatusIndicator
.is() )
293 xStatusIndicator
->setValue( nPercent
);
296 Color
WinMtf::ReadColor()
299 pWMF
->ReadUInt32( nColor
);
300 return Color( (sal_uInt8
)nColor
, (sal_uInt8
)( nColor
>> 8 ), (sal_uInt8
)( nColor
>> 16 ) );
303 Point
WinMtfOutput::ImplScale(const Point
& rPoint
) // Hack to set varying defaults for incompletely defined files.
306 return Point(rPoint
.X() * UNDOCUMENTED_WIN_RCL_RELATION
- mrclFrame
.Left(),
307 rPoint
.Y() * UNDOCUMENTED_WIN_RCL_RELATION
- mrclFrame
.Top());
312 Point
WinMtfOutput::ImplMap( const Point
& rPt
)
314 if ( mnWinExtX
&& mnWinExtY
)
319 double fX2
= fX
* maXForm
.eM11
+ fY
* maXForm
.eM21
+ maXForm
.eDx
;
320 double fY2
= fX
* maXForm
.eM12
+ fY
* maXForm
.eM22
+ maXForm
.eDy
;
322 if ( mnGfxMode
== GM_COMPATIBLE
)
330 fX2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
*10;
331 fY2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
*10;
340 fX2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
;
341 fY2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
;
350 fX2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
/MILLIINCH_PER_TWIPS
;
351 fY2
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
/MILLIINCH_PER_TWIPS
;
366 case MM_HIMETRIC
: // in hundredth of a millimeter
383 fY2
+= mnDevOrgY
; // fX2, fY2 now in device units
384 fX2
*= (double)mnMillX
* 100.0 / (double)mnPixX
;
385 fY2
*= (double)mnMillY
* 100.0 / (double)mnPixY
;
389 fX2
-= mrclFrame
.Left();
390 fY2
-= mrclFrame
.Top();
392 return Point( FRound( fX2
), FRound( fY2
) );
398 Size
WinMtfOutput::ImplMap(const Size
& rSz
, bool bDoWorldTransform
)
400 if ( mnWinExtX
&& mnWinExtY
)
402 // #i121382# apply the whole WorldTransform, else a rotation will be misinterpreted
403 double fWidth
, fHeight
;
404 if (bDoWorldTransform
)
406 fWidth
= rSz
.Width() * maXForm
.eM11
+ rSz
.Height() * maXForm
.eM21
;
407 fHeight
= rSz
.Width() * maXForm
.eM12
+ rSz
.Height() * maXForm
.eM22
;
411 //take the scale, but not the rotation
412 basegfx::B2DHomMatrix
aMatrix(maXForm
.eM11
, maXForm
.eM12
, 0,
413 maXForm
.eM21
, maXForm
.eM22
, 0);
414 basegfx::B2DTuple aScale
, aTranslate
;
415 double fRotate
, fShearX
;
416 if (!aMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
))
421 fWidth
= rSz
.Width() * aScale
.getX();
422 fHeight
= rSz
.Height() * aScale
.getY();
425 if ( mnGfxMode
== GM_COMPATIBLE
)
431 fWidth
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
*10;
432 fHeight
*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH
*10;
437 fWidth
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
;
438 fHeight
*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH
;
447 case MM_HIMETRIC
: // in hundredth of millimeters
454 fWidth
*= HUNDREDTH_MILLIMETERS_PER_MILLIINCH
/MILLIINCH_PER_TWIPS
;
455 fHeight
*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH
/MILLIINCH_PER_TWIPS
;
461 fHeight
/= mnWinExtY
;
462 fWidth
*= mnDevWidth
;
463 fHeight
*= mnDevHeight
;
464 fWidth
*= (double)mnMillX
* 100 / (double)mnPixX
;
465 fHeight
*= (double)mnMillY
* 100 / (double)mnPixY
;
470 return Size( FRound( fWidth
), FRound( fHeight
) );
476 Rectangle
WinMtfOutput::ImplMap( const Rectangle
& rRect
)
478 return Rectangle( ImplMap( rRect
.TopLeft() ), ImplMap( rRect
.GetSize() ) );
481 void WinMtfOutput::ImplMap( vcl::Font
& rFont
)
483 // !!! HACK: we now always set the width to zero because the OS width is interpreted differently;
484 // must later be made portable in SV (KA 1996-02-08)
485 Size aFontSize
= ImplMap (rFont
.GetSize(), false);
487 if( aFontSize
.Height() < 0 )
488 aFontSize
.Height() *= -1;
490 rFont
.SetSize( aFontSize
);
492 if( ( mnWinExtX
* mnWinExtY
) < 0 )
493 rFont
.SetOrientation( 3600 - rFont
.GetOrientation() );
496 Polygon
& WinMtfOutput::ImplMap( Polygon
& rPolygon
)
498 sal_uInt16 nPoints
= rPolygon
.GetSize();
499 for ( sal_uInt16 i
= 0; i
< nPoints
; i
++ )
501 rPolygon
[ i
] = ImplMap( rPolygon
[ i
] );
506 Polygon
& WinMtfOutput::ImplScale( Polygon
& rPolygon
)
508 sal_uInt16 nPoints
= rPolygon
.GetSize();
509 for ( sal_uInt16 i
= 0; i
< nPoints
; i
++ )
511 rPolygon
[ i
] = ImplScale( rPolygon
[ i
] );
516 tools::PolyPolygon
& WinMtfOutput::ImplScale( tools::PolyPolygon
& rPolyPolygon
)
518 sal_uInt16 nPolys
= rPolyPolygon
.Count();
519 for (sal_uInt16 i
= 0; i
< nPolys
; ++i
)
521 ImplScale(rPolyPolygon
[i
]);
526 tools::PolyPolygon
& WinMtfOutput::ImplMap( tools::PolyPolygon
& rPolyPolygon
)
528 sal_uInt16 nPolys
= rPolyPolygon
.Count();
529 for ( sal_uInt16 i
= 0; i
< nPolys
; ImplMap( rPolyPolygon
[ i
++ ] ) ) ;
533 void WinMtfOutput::SelectObject( sal_Int32 nIndex
)
535 GDIObj
* pGDIObj
= NULL
;
537 if ( nIndex
& ENHMETA_STOCK_OBJECT
)
538 pGDIObj
= new GDIObj();
541 nIndex
&= 0xffff; // safety check: don't allow index to be > 65535
543 if ( (sal_uInt32
)nIndex
< vGDIObj
.size() )
544 pGDIObj
= vGDIObj
[ nIndex
];
547 if( pGDIObj
== NULL
)
550 if ( nIndex
& ENHMETA_STOCK_OBJECT
)
552 sal_uInt16 nStockId
= (sal_uInt8
)nIndex
;
557 pGDIObj
->Set( GDI_BRUSH
, new WinMtfFillStyle( Color( COL_WHITE
) ) );
562 pGDIObj
->Set( GDI_BRUSH
, new WinMtfFillStyle( Color( COL_LIGHTGRAY
) ) );
568 pGDIObj
->Set( GDI_BRUSH
, new WinMtfFillStyle( Color( COL_GRAY
) ) );
573 pGDIObj
->Set( GDI_BRUSH
, new WinMtfFillStyle( Color( COL_BLACK
) ) );
578 pGDIObj
->Set( GDI_BRUSH
, new WinMtfFillStyle( Color( COL_TRANSPARENT
), true ) );
583 pGDIObj
->Set( GDI_PEN
, new WinMtfLineStyle( Color( COL_WHITE
) ) );
588 pGDIObj
->Set( GDI_PEN
, new WinMtfLineStyle( Color( COL_BLACK
) ) );
593 pGDIObj
->Set( GDI_PEN
, new WinMtfLineStyle( Color( COL_TRANSPARENT
), true ) );
600 if ( pGDIObj
->pStyle
)
602 switch( pGDIObj
->eType
)
605 maLineStyle
= static_cast<WinMtfLineStyle
*>(pGDIObj
->pStyle
);
609 maFillStyle
= static_cast<WinMtfFillStyle
*>(pGDIObj
->pStyle
);
610 mbFillStyleSelected
= true;
614 maFont
= static_cast<WinMtfFontStyle
*>(pGDIObj
->pStyle
)->aFont
;
617 break; // -Wall many options not handled.
620 if ( nIndex
& ENHMETA_STOCK_OBJECT
)
625 void WinMtfOutput::SetTextLayoutMode( ComplexTextLayoutMode nTextLayoutMode
)
627 mnTextLayoutMode
= nTextLayoutMode
;
630 void WinMtfOutput::SetBkMode( BkMode nMode
)
635 void WinMtfOutput::SetBkColor( const Color
& rColor
)
640 void WinMtfOutput::SetTextColor( const Color
& rColor
)
642 maTextColor
= rColor
;
645 void WinMtfOutput::SetTextAlign( sal_uInt32 nAlign
)
647 mnTextAlign
= nAlign
;
650 void WinMtfOutput::ImplResizeObjectArry( sal_uInt32 nNewEntrys
)
652 vGDIObj
.resize(nNewEntrys
, NULL
);
655 void WinMtfOutput::ImplDrawClippedPolyPolygon( const tools::PolyPolygon
& rPolyPoly
)
657 if ( rPolyPoly
.Count() )
659 ImplSetNonPersistentLineColorTransparenz();
660 if ( rPolyPoly
.Count() == 1 )
662 if ( rPolyPoly
.IsRect() )
663 mpGDIMetaFile
->AddAction( new MetaRectAction( rPolyPoly
.GetBoundRect() ) );
666 Polygon
aPoly( rPolyPoly
[ 0 ] );
667 sal_uInt16 nCount
= aPoly
.GetSize();
670 if ( aPoly
[ nCount
- 1 ] != aPoly
[ 0 ] )
672 Point
aPoint( aPoly
[ 0 ] );
673 aPoly
.Insert( nCount
, aPoint
);
675 mpGDIMetaFile
->AddAction( new MetaPolygonAction( aPoly
) );
680 mpGDIMetaFile
->AddAction( new MetaPolyPolygonAction( rPolyPoly
) );
684 void WinMtfOutput::CreateObject( GDIObjectType eType
, void* pStyle
)
688 if ( eType
== GDI_FONT
)
690 WinMtfFontStyle
* pFontStyle
= static_cast<WinMtfFontStyle
*>(pStyle
);
691 if (pFontStyle
->aFont
.GetHeight() == 0)
692 pFontStyle
->aFont
.SetHeight(423);
693 ImplMap(pFontStyle
->aFont
); // defaulting to 12pt
695 else if ( eType
== GDI_PEN
)
697 WinMtfLineStyle
* pLineStyle
= static_cast<WinMtfLineStyle
*>(pStyle
);
698 Size
aSize(pLineStyle
->aLineInfo
.GetWidth(), 0);
699 aSize
= ImplMap(aSize
);
700 pLineStyle
->aLineInfo
.SetWidth(aSize
.Width());
704 for ( nIndex
= 0; nIndex
< vGDIObj
.size(); nIndex
++ )
706 if ( vGDIObj
[ nIndex
] == NULL
)
709 if ( nIndex
== vGDIObj
.size() )
710 ImplResizeObjectArry( vGDIObj
.size() + 16 );
712 vGDIObj
[ nIndex
] = new GDIObj( eType
, pStyle
);
715 void WinMtfOutput::CreateObject( sal_Int32 nIndex
, GDIObjectType eType
, void* pStyle
)
717 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
719 nIndex
&= 0xffff; // safety check: do not allow index to be > 65535
722 if ( eType
== GDI_FONT
)
724 WinMtfFontStyle
* pFontStyle
= static_cast<WinMtfFontStyle
*>(pStyle
);
725 if (pFontStyle
->aFont
.GetHeight() == 0)
726 pFontStyle
->aFont
.SetHeight(423);
727 ImplMap(pFontStyle
->aFont
);
729 else if ( eType
== GDI_PEN
)
731 WinMtfLineStyle
* pLineStyle
= static_cast<WinMtfLineStyle
*>(pStyle
);
732 Size
aSize(pLineStyle
->aLineInfo
.GetWidth(), 0);
733 aSize
= ImplMap(aSize
);
734 pLineStyle
->aLineInfo
.SetWidth(aSize
.Width());
737 if ( (sal_uInt32
)nIndex
>= vGDIObj
.size() )
738 ImplResizeObjectArry( nIndex
+ 16 );
740 if ( vGDIObj
[ nIndex
] != NULL
)
741 delete vGDIObj
[ nIndex
];
743 vGDIObj
[ nIndex
] = new GDIObj( eType
, pStyle
);
750 delete static_cast<WinMtfLineStyle
*>(pStyle
);
753 delete static_cast<WinMtfFillStyle
*>(pStyle
);
756 delete static_cast<WinMtfFontStyle
*>(pStyle
);
760 OSL_FAIL( "unsupported style not deleted" );
766 void WinMtfOutput::DeleteObject( sal_Int32 nIndex
)
768 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
770 if ( (sal_uInt32
)nIndex
< vGDIObj
.size() )
772 delete vGDIObj
[ nIndex
];
773 vGDIObj
[ nIndex
] = NULL
;
778 void WinMtfOutput::IntersectClipRect( const Rectangle
& rRect
)
780 mbClipNeedsUpdate
=true;
781 if ((rRect
.Left()-rRect
.Right()==0) && (rRect
.Top()-rRect
.Bottom()==0))
783 return; // empty rectangles cause trouble
785 aClipPath
.intersectClipRect( ImplMap( rRect
) );
788 void WinMtfOutput::ExcludeClipRect( const Rectangle
& rRect
)
790 mbClipNeedsUpdate
=true;
791 aClipPath
.excludeClipRect( ImplMap( rRect
) );
794 void WinMtfOutput::MoveClipRegion( const Size
& rSize
)
796 mbClipNeedsUpdate
=true;
797 aClipPath
.moveClipRegion( ImplMap( rSize
) );
800 void WinMtfOutput::SetClipPath( const tools::PolyPolygon
& rPolyPolygon
, sal_Int32 nClippingMode
, bool bIsMapped
)
802 mbClipNeedsUpdate
= true;
803 tools::PolyPolygon
aPolyPolygon(rPolyPolygon
);
807 if (!mbIsMapDevSet
&& (mnMapMode
== MM_ISOTROPIC
|| mnMapMode
== MM_ANISOTROPIC
))
808 aPolyPolygon
= ImplScale(aPolyPolygon
);
810 aPolyPolygon
= ImplMap(aPolyPolygon
);
812 aClipPath
.setClipPath(aPolyPolygon
, nClippingMode
);
815 void WinMtfOutput::SetDefaultClipPath()
817 mbClipNeedsUpdate
= true;
818 aClipPath
.setDefaultClipPath();
821 WinMtfOutput::WinMtfOutput( GDIMetaFile
& rGDIMetaFile
) :
822 mnLatestTextAlign ( 0 ),
823 mnTextAlign ( TA_LEFT
| TA_TOP
| TA_NOUPDATECP
),
824 maLatestBkColor ( 0x12345678 ),
825 maBkColor ( COL_WHITE
),
826 mnLatestTextLayoutMode( TEXT_LAYOUT_DEFAULT
),
827 mnTextLayoutMode ( TEXT_LAYOUT_DEFAULT
),
828 mnLatestBkMode ( BkMode::NONE
),
829 mnBkMode ( BkMode::OPAQUE
),
830 meLatestRasterOp ( ROP_INVERT
),
831 meRasterOp ( ROP_OVERPAINT
),
832 maActPos ( Point() ),
834 mbFillStyleSelected ( false ),
835 mbClipNeedsUpdate ( true ),
836 mbComplexClip ( false ),
837 mnGfxMode ( GM_COMPATIBLE
),
838 mnMapMode ( MM_TEXT
),
851 mpGDIMetaFile ( &rGDIMetaFile
)
853 mbIsMapWinSet
= false;
854 mbIsMapDevSet
= false;
855 mpGDIMetaFile
->AddAction( new MetaPushAction( PushFlags::CLIPREGION
) ); // The original clipregion has to be on top
856 // of the stack so it can always be restored
857 // this is necessary to be able to support
858 // SetClipRgn( NULL ) and similar ClipRgn actions (SJ)
860 maFont
.SetName( "Arial" ); // sj: #i57205#, we do have some scaling problems if using
861 maFont
.SetCharSet( RTL_TEXTENCODING_MS_1252
); // the default font then most times a x11 font is used, we
862 maFont
.SetHeight( 423 ); // will prevent this defining a font
864 maLatestLineStyle
.aLineColor
= Color( 0x12, 0x34, 0x56 );
865 maLatestFillStyle
.aFillColor
= Color( 0x12, 0x34, 0x56 );
867 mnRop
= R2_BLACK
+ 1;
868 SetRasterOp( R2_BLACK
);
871 WinMtfOutput::~WinMtfOutput()
873 mpGDIMetaFile
->AddAction( new MetaPopAction() );
874 mpGDIMetaFile
->SetPrefMapMode( MAP_100TH_MM
);
875 if ( mrclFrame
.IsEmpty() )
876 mpGDIMetaFile
->SetPrefSize( Size( mnDevWidth
, mnDevHeight
) );
878 mpGDIMetaFile
->SetPrefSize( mrclFrame
.GetSize() );
880 for ( sal_uInt32 i
= 0; i
< vGDIObj
.size(); i
++ )
884 void WinMtfOutput::UpdateClipRegion()
886 if ( mbClipNeedsUpdate
)
888 mbClipNeedsUpdate
= false;
889 mbComplexClip
= false;
891 mpGDIMetaFile
->AddAction( new MetaPopAction() ); // taking the original clipregion
892 mpGDIMetaFile
->AddAction( new MetaPushAction( PushFlags::CLIPREGION
) );
894 // skip for 'no clipping at all' case
895 if( !aClipPath
.isEmpty() )
897 const basegfx::B2DPolyPolygon
& rClipPoly( aClipPath
.getClipPath() );
898 mpGDIMetaFile
->AddAction(
899 new MetaISectRectClipRegionAction(
900 vcl::unotools::rectangleFromB2DRectangle(
901 rClipPoly
.getB2DRange())));
903 mbComplexClip
= rClipPoly
.count() > 1
904 || !basegfx::tools::isRectangle(rClipPoly
);
909 void WinMtfOutput::ImplSetNonPersistentLineColorTransparenz()
911 Color
aColor( COL_TRANSPARENT
);
912 WinMtfLineStyle
aTransparentLine( aColor
, true );
913 if ( ! ( maLatestLineStyle
== aTransparentLine
) )
915 maLatestLineStyle
= aTransparentLine
;
916 mpGDIMetaFile
->AddAction( new MetaLineColorAction( aTransparentLine
.aLineColor
, !aTransparentLine
.bTransparent
) );
920 void WinMtfOutput::UpdateLineStyle()
922 if (!( maLatestLineStyle
== maLineStyle
) )
924 maLatestLineStyle
= maLineStyle
;
925 mpGDIMetaFile
->AddAction( new MetaLineColorAction( maLineStyle
.aLineColor
, !maLineStyle
.bTransparent
) );
929 void WinMtfOutput::UpdateFillStyle()
931 if ( !mbFillStyleSelected
) // SJ: #i57205# taking care of bkcolor if no brush is selected
932 maFillStyle
= WinMtfFillStyle( maBkColor
, mnBkMode
== BkMode::Transparent
);
933 if (!( maLatestFillStyle
== maFillStyle
) )
935 maLatestFillStyle
= maFillStyle
;
936 if (maFillStyle
.aType
== FillStyleSolid
)
937 mpGDIMetaFile
->AddAction( new MetaFillColorAction( maFillStyle
.aFillColor
, !maFillStyle
.bTransparent
) );
941 sal_uInt32
WinMtfOutput::SetRasterOp( sal_uInt32 nRasterOp
)
943 sal_uInt32 nRetROP
= mnRop
;
944 if ( nRasterOp
!= mnRop
)
947 static WinMtfLineStyle aNopLineStyle
;
949 if ( mbNopMode
&& ( nRasterOp
!= R2_NOP
) )
950 { // changing modes from R2_NOP so set pen and brush
951 maFillStyle
= m_NopFillStyle
;
952 maLineStyle
= aNopLineStyle
;
958 meRasterOp
= ROP_INVERT
;
962 meRasterOp
= ROP_XOR
;
967 meRasterOp
= ROP_OVERPAINT
;
970 m_NopFillStyle
= maFillStyle
;
971 aNopLineStyle
= maLineStyle
;
972 maFillStyle
= WinMtfFillStyle( Color( COL_TRANSPARENT
), true );
973 maLineStyle
= WinMtfLineStyle( Color( COL_TRANSPARENT
), true );
980 meRasterOp
= ROP_OVERPAINT
;
984 if ( nRetROP
!= nRasterOp
)
985 mpGDIMetaFile
->AddAction( new MetaRasterOpAction( meRasterOp
) );
989 void WinMtfOutput::StrokeAndFillPath( bool bStroke
, bool bFill
)
991 if ( aPathObj
.Count() )
1000 mpGDIMetaFile
->AddAction( new MetaPushAction( PushFlags::LINECOLOR
) );
1001 mpGDIMetaFile
->AddAction( new MetaLineColorAction( Color(), false ) );
1003 if ( aPathObj
.Count() == 1 )
1004 mpGDIMetaFile
->AddAction( new MetaPolygonAction( aPathObj
.GetObject( 0 ) ) );
1006 mpGDIMetaFile
->AddAction( new MetaPolyPolygonAction( aPathObj
) );
1009 mpGDIMetaFile
->AddAction( new MetaPopAction() );
1013 sal_uInt16 i
, nCount
= aPathObj
.Count();
1014 for ( i
= 0; i
< nCount
; i
++ )
1015 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( aPathObj
[ i
], maLineStyle
.aLineInfo
) );
1021 void WinMtfOutput::DrawPixel( const Point
& rSource
, const Color
& rColor
)
1023 mpGDIMetaFile
->AddAction( new MetaPixelAction( ImplMap( rSource
), rColor
) );
1026 void WinMtfOutput::MoveTo( const Point
& rPoint
, bool bRecordPath
)
1028 Point
aDest( ImplMap( rPoint
) );
1031 // fdo#57353 create new subpath for subsequent moves
1032 if ( aPathObj
.Count() )
1033 if ( aPathObj
[ aPathObj
.Count() - 1 ].GetSize() )
1034 aPathObj
.Insert( Polygon(), POLYPOLY_APPEND
);
1035 aPathObj
.AddPoint( aDest
);
1040 void WinMtfOutput::LineTo( const Point
& rPoint
, bool bRecordPath
)
1043 Point
aDest( ImplMap( rPoint
) );
1045 aPathObj
.AddPoint( aDest
);
1049 mpGDIMetaFile
->AddAction( new MetaLineAction( maActPos
, aDest
, maLineStyle
.aLineInfo
) );
1054 void WinMtfOutput::DrawRect( const Rectangle
& rRect
, bool bEdge
)
1059 if ( mbComplexClip
)
1061 Polygon
aPoly( ImplMap( rRect
) );
1062 tools::PolyPolygon
aPolyPolyRect( aPoly
);
1063 tools::PolyPolygon aDest
;
1064 tools::PolyPolygon(aClipPath
.getClipPath()).GetIntersection( aPolyPolyRect
, aDest
);
1065 ImplDrawClippedPolyPolygon( aDest
);
1071 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LINE_DASH
) )
1073 ImplSetNonPersistentLineColorTransparenz();
1074 mpGDIMetaFile
->AddAction( new MetaRectAction( ImplMap( rRect
) ) );
1076 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( Polygon( ImplMap( rRect
) ),maLineStyle
.aLineInfo
) );
1081 mpGDIMetaFile
->AddAction( new MetaRectAction( ImplMap( rRect
) ) );
1086 ImplSetNonPersistentLineColorTransparenz();
1087 mpGDIMetaFile
->AddAction( new MetaRectAction( ImplMap( rRect
) ) );
1092 void WinMtfOutput::DrawRoundRect( const Rectangle
& rRect
, const Size
& rSize
)
1097 mpGDIMetaFile
->AddAction( new MetaRoundRectAction( ImplMap( rRect
), labs( ImplMap( rSize
).Width() ), labs( ImplMap( rSize
).Height() ) ) );
1100 void WinMtfOutput::DrawEllipse( const Rectangle
& rRect
)
1105 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LINE_DASH
) )
1107 Point
aCenter( ImplMap( rRect
.Center() ) );
1108 Size
aRad( ImplMap( Size( rRect
.GetWidth() / 2, rRect
.GetHeight() / 2 ) ) );
1110 ImplSetNonPersistentLineColorTransparenz();
1111 mpGDIMetaFile
->AddAction( new MetaEllipseAction( ImplMap( rRect
) ) );
1113 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( Polygon( aCenter
, aRad
.Width(), aRad
.Height() ), maLineStyle
.aLineInfo
) );
1118 mpGDIMetaFile
->AddAction( new MetaEllipseAction( ImplMap( rRect
) ) );
1122 void WinMtfOutput::DrawArc( const Rectangle
& rRect
, const Point
& rStart
, const Point
& rEnd
, bool bTo
)
1128 Rectangle
aRect( ImplMap( rRect
) );
1129 Point
aStart( ImplMap( rStart
) );
1130 Point
aEnd( ImplMap( rEnd
) );
1132 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LINE_DASH
) )
1134 if ( aStart
== aEnd
)
1135 { // SJ: #i53768# if start & end is identical, then we have to draw a full ellipse
1136 Point
aCenter( aRect
.Center() );
1137 Size
aRad( aRect
.GetWidth() / 2, aRect
.GetHeight() / 2 );
1139 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( Polygon( aCenter
, aRad
.Width(), aRad
.Height() ), maLineStyle
.aLineInfo
) );
1142 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( Polygon( aRect
, aStart
, aEnd
, POLY_ARC
), maLineStyle
.aLineInfo
) );
1145 mpGDIMetaFile
->AddAction( new MetaArcAction( aRect
, aStart
, aEnd
) );
1151 void WinMtfOutput::DrawPie( const Rectangle
& rRect
, const Point
& rStart
, const Point
& rEnd
)
1156 Rectangle
aRect( ImplMap( rRect
) );
1157 Point
aStart( ImplMap( rStart
) );
1158 Point
aEnd( ImplMap( rEnd
) );
1160 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LINE_DASH
) )
1162 ImplSetNonPersistentLineColorTransparenz();
1163 mpGDIMetaFile
->AddAction( new MetaPieAction( aRect
, aStart
, aEnd
) );
1165 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( Polygon( aRect
, aStart
, aEnd
, POLY_PIE
), maLineStyle
.aLineInfo
) );
1170 mpGDIMetaFile
->AddAction( new MetaPieAction( aRect
, aStart
, aEnd
) );
1174 void WinMtfOutput::DrawChord( const Rectangle
& rRect
, const Point
& rStart
, const Point
& rEnd
)
1179 Rectangle
aRect( ImplMap( rRect
) );
1180 Point
aStart( ImplMap( rStart
) );
1181 Point
aEnd( ImplMap( rEnd
) );
1183 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LINE_DASH
) )
1185 ImplSetNonPersistentLineColorTransparenz();
1186 mpGDIMetaFile
->AddAction( new MetaChordAction( aRect
, aStart
, aEnd
) );
1188 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( Polygon( aRect
, aStart
, aEnd
, POLY_CHORD
), maLineStyle
.aLineInfo
) );
1193 mpGDIMetaFile
->AddAction( new MetaChordAction( aRect
, aStart
, aEnd
) );
1197 void WinMtfOutput::DrawPolygon( Polygon
& rPolygon
, bool bRecordPath
)
1200 ImplMap( rPolygon
);
1202 aPathObj
.AddPolygon( rPolygon
);
1207 if ( mbComplexClip
)
1209 tools::PolyPolygon
aPolyPoly( rPolygon
);
1210 tools::PolyPolygon aDest
;
1211 tools::PolyPolygon(aClipPath
.getClipPath()).GetIntersection( aPolyPoly
, aDest
);
1212 ImplDrawClippedPolyPolygon( aDest
);
1216 if ( maLineStyle
.aLineInfo
.GetWidth() || ( maLineStyle
.aLineInfo
.GetStyle() == LINE_DASH
) )
1218 sal_uInt16 nCount
= rPolygon
.GetSize();
1221 if ( rPolygon
[ nCount
- 1 ] != rPolygon
[ 0 ] )
1223 Point
aPoint( rPolygon
[ 0 ] );
1224 rPolygon
.Insert( nCount
, aPoint
);
1227 ImplSetNonPersistentLineColorTransparenz();
1228 mpGDIMetaFile
->AddAction( new MetaPolygonAction( rPolygon
) );
1230 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( rPolygon
, maLineStyle
.aLineInfo
) );
1236 if (maLatestFillStyle
.aType
!= FillStylePattern
)
1237 mpGDIMetaFile
->AddAction( new MetaPolygonAction( rPolygon
) );
1239 SvtGraphicFill aFill
= SvtGraphicFill( tools::PolyPolygon( rPolygon
),
1242 SvtGraphicFill::fillNonZero
,
1243 SvtGraphicFill::fillTexture
,
1244 SvtGraphicFill::Transform(),
1246 SvtGraphicFill::hatchSingle
,
1248 SvtGraphicFill::gradientLinear
,
1252 Graphic (maLatestFillStyle
.aBmp
) );
1254 SvMemoryStream aMemStm
;
1256 WriteSvtGraphicFill( aMemStm
, aFill
);
1258 mpGDIMetaFile
->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_BEGIN", 0,
1259 static_cast<const sal_uInt8
*>(aMemStm
.GetData()),
1260 aMemStm
.Seek( STREAM_SEEK_TO_END
) ) );
1261 mpGDIMetaFile
->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_END" ) );
1269 void WinMtfOutput::DrawPolyPolygon( tools::PolyPolygon
& rPolyPolygon
, bool bRecordPath
)
1273 ImplMap( rPolyPolygon
);
1276 aPathObj
.AddPolyPolygon( rPolyPolygon
);
1281 if ( mbComplexClip
)
1283 tools::PolyPolygon aDest
;
1284 tools::PolyPolygon(aClipPath
.getClipPath()).GetIntersection( rPolyPolygon
, aDest
);
1285 ImplDrawClippedPolyPolygon( aDest
);
1290 mpGDIMetaFile
->AddAction( new MetaPolyPolygonAction( rPolyPolygon
) );
1291 if (maLineStyle
.aLineInfo
.GetWidth() > 0 || maLineStyle
.aLineInfo
.GetStyle() == LINE_DASH
)
1293 for (sal_uInt16 nPoly
= 0; nPoly
< rPolyPolygon
.Count(); ++nPoly
)
1295 mpGDIMetaFile
->AddAction(new MetaPolyLineAction(rPolyPolygon
[nPoly
], maLineStyle
.aLineInfo
));
1302 void WinMtfOutput::DrawPolyLine( Polygon
& rPolygon
, bool bTo
, bool bRecordPath
)
1306 sal_uInt16 nPoints
= rPolygon
.GetSize();
1309 ImplMap( rPolygon
);
1312 rPolygon
[ 0 ] = maActPos
;
1313 maActPos
= rPolygon
[ rPolygon
.GetSize() - 1 ];
1316 aPathObj
.AddPolyLine( rPolygon
);
1320 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( rPolygon
, maLineStyle
.aLineInfo
) );
1325 void WinMtfOutput::DrawPolyBezier( Polygon
& rPolygon
, bool bTo
, bool bRecordPath
)
1329 sal_uInt16 nPoints
= rPolygon
.GetSize();
1330 if ( ( nPoints
>= 4 ) && ( ( ( nPoints
- 4 ) % 3 ) == 0 ) )
1332 ImplMap( rPolygon
);
1335 rPolygon
[ 0 ] = maActPos
;
1336 maActPos
= rPolygon
[ nPoints
- 1 ];
1339 for ( i
= 0; ( i
+ 2 ) < nPoints
; )
1341 rPolygon
.SetFlags( i
++, POLY_NORMAL
);
1342 rPolygon
.SetFlags( i
++, POLY_CONTROL
);
1343 rPolygon
.SetFlags( i
++, POLY_CONTROL
);
1346 aPathObj
.AddPolyLine( rPolygon
);
1350 mpGDIMetaFile
->AddAction( new MetaPolyLineAction( rPolygon
, maLineStyle
.aLineInfo
) );
1355 void WinMtfOutput::DrawText( Point
& rPosition
, OUString
& rText
, long* pDXArry
, bool bRecordPath
, sal_Int32 nGfxMode
)
1358 rPosition
= ImplMap( rPosition
);
1359 sal_Int32 nOldGfxMode
= GetGfxMode();
1360 SetGfxMode( GM_COMPATIBLE
);
1366 sal_Int32 nLen
= rText
.getLength();
1368 for (i
= 0; i
< nLen
; i
++ )
1372 // #i121382# Map DXArray using WorldTransform
1373 const Size
aSize(ImplMap(Size(nSum
, 0)));
1374 const basegfx::B2DVector
aVector(aSize
.Width(), aSize
.Height());
1375 pDXArry
[i
- 1] = basegfx::fround(aVector
.getLength());
1380 if ( mnLatestTextLayoutMode
!= mnTextLayoutMode
)
1382 mnLatestTextLayoutMode
= mnTextLayoutMode
;
1383 mpGDIMetaFile
->AddAction( new MetaLayoutModeAction( mnTextLayoutMode
) );
1385 SetGfxMode( nGfxMode
);
1386 bool bChangeFont
= false;
1387 if ( mnLatestTextAlign
!= mnTextAlign
)
1390 mnLatestTextAlign
= mnTextAlign
;
1391 TextAlign eTextAlign
;
1392 if ( ( mnTextAlign
& TA_BASELINE
) == TA_BASELINE
)
1393 eTextAlign
= ALIGN_BASELINE
;
1394 else if( ( mnTextAlign
& TA_BOTTOM
) == TA_BOTTOM
)
1395 eTextAlign
= ALIGN_BOTTOM
;
1397 eTextAlign
= ALIGN_TOP
;
1398 mpGDIMetaFile
->AddAction( new MetaTextAlignAction( eTextAlign
) );
1400 if ( maLatestTextColor
!= maTextColor
)
1403 maLatestTextColor
= maTextColor
;
1404 mpGDIMetaFile
->AddAction( new MetaTextColorAction( maTextColor
) );
1406 bool bChangeFillColor
= false;
1407 if ( maLatestBkColor
!= maBkColor
)
1409 bChangeFillColor
= true;
1410 maLatestBkColor
= maBkColor
;
1412 if ( mnLatestBkMode
!= mnBkMode
)
1414 bChangeFillColor
= true;
1415 mnLatestBkMode
= mnBkMode
;
1417 if ( bChangeFillColor
)
1420 mpGDIMetaFile
->AddAction( new MetaTextFillColorAction( maFont
.GetFillColor(), !maFont
.IsTransparent() ) );
1422 vcl::Font
aTmp( maFont
);
1423 aTmp
.SetColor( maTextColor
);
1424 aTmp
.SetFillColor( maBkColor
);
1426 if( mnBkMode
== BkMode::Transparent
)
1427 aTmp
.SetTransparent( true );
1429 aTmp
.SetTransparent( false );
1431 if ( ( mnTextAlign
& TA_BASELINE
) == TA_BASELINE
)
1432 aTmp
.SetAlign( ALIGN_BASELINE
);
1433 else if( ( mnTextAlign
& TA_BOTTOM
) == TA_BOTTOM
)
1434 aTmp
.SetAlign( ALIGN_BOTTOM
);
1436 aTmp
.SetAlign( ALIGN_TOP
);
1438 if ( nGfxMode
== GM_ADVANCED
)
1440 // check whether there is a font rotation applied via transformation
1441 Point
aP1( ImplMap( Point() ) );
1442 Point
aP2( ImplMap( Point( 0, 100 ) ) );
1445 double fX
= aP2
.X();
1446 double fY
= aP2
.Y();
1449 double fOrientation
= acos( fX
/ sqrt( fX
* fX
+ fY
* fY
) ) * 57.29577951308;
1451 fOrientation
= 360 - fOrientation
;
1454 fOrientation
+= aTmp
.GetOrientation();
1455 aTmp
.SetOrientation( sal_Int16( fOrientation
) );
1459 if( mnTextAlign
& ( TA_UPDATECP
| TA_RIGHT_CENTER
) )
1461 // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
1462 SolarMutexGuard aGuard
;
1463 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
1464 sal_Int32 nTextWidth
;
1465 pVDev
->SetMapMode( MapMode( MAP_100TH_MM
) );
1466 pVDev
->SetFont( maFont
);
1469 sal_uInt32 nLen
= rText
.getLength();
1470 nTextWidth
= pVDev
->GetTextWidth( OUString(rText
[ nLen
- 1 ]) );
1472 nTextWidth
+= pDXArry
[ nLen
- 2 ];
1475 nTextWidth
= pVDev
->GetTextWidth( rText
);
1477 if( mnTextAlign
& TA_UPDATECP
)
1478 rPosition
= maActPos
;
1480 if ( mnTextAlign
& TA_RIGHT_CENTER
)
1482 double fLength
= ( ( mnTextAlign
& TA_RIGHT_CENTER
) == TA_RIGHT
) ? nTextWidth
: nTextWidth
>> 1;
1483 rPosition
.X() -= (sal_Int32
)( fLength
* cos( maFont
.GetOrientation() * F_PI1800
) );
1484 rPosition
.Y() -= (sal_Int32
)(-( fLength
* sin( maFont
.GetOrientation() * F_PI1800
) ) );
1487 if( mnTextAlign
& TA_UPDATECP
)
1488 maActPos
.X() = rPosition
.X() + nTextWidth
;
1490 if ( bChangeFont
|| ( maLatestFont
!= aTmp
) )
1492 maLatestFont
= aTmp
;
1493 mpGDIMetaFile
->AddAction( new MetaFontAction( aTmp
) );
1494 mpGDIMetaFile
->AddAction( new MetaTextAlignAction( aTmp
.GetAlign() ) );
1495 mpGDIMetaFile
->AddAction( new MetaTextColorAction( aTmp
.GetColor() ) );
1496 mpGDIMetaFile
->AddAction( new MetaTextFillColorAction( aTmp
.GetFillColor(), !aTmp
.IsTransparent() ) );
1504 /* because text without dx array is badly scaled, we
1505 will create such an array if necessary */
1506 long* pDX
= pDXArry
;
1509 // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
1510 SolarMutexGuard aGuard
;
1511 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
1512 pDX
= new long[ rText
.getLength() ];
1513 pVDev
->SetMapMode( MAP_100TH_MM
);
1514 pVDev
->SetFont( maLatestFont
);
1515 pVDev
->GetTextArray( rText
, pDX
, 0, rText
.getLength());
1517 mpGDIMetaFile
->AddAction( new MetaTextArrayAction( rPosition
, rText
, pDX
, 0, rText
.getLength() ) );
1518 if ( !pDXArry
) // this means we have created our own array
1519 delete[] pDX
; // which must be deleted
1521 SetGfxMode( nOldGfxMode
);
1524 void WinMtfOutput::ImplDrawBitmap( const Point
& rPos
, const Size
& rSize
, const BitmapEx
& rBitmap
)
1526 BitmapEx
aBmpEx( rBitmap
);
1527 if ( mbComplexClip
)
1529 VclPtrInstance
< VirtualDevice
> pVDev
;
1530 MapMode
aMapMode( MAP_100TH_MM
);
1531 aMapMode
.SetOrigin( Point( -rPos
.X(), -rPos
.Y() ) );
1532 const Size
aOutputSizePixel( pVDev
->LogicToPixel( rSize
, aMapMode
) );
1533 const Size
aSizePixel( rBitmap
.GetSizePixel() );
1534 if ( aOutputSizePixel
.Width() && aOutputSizePixel
.Height() )
1536 aMapMode
.SetScaleX( Fraction( aSizePixel
.Width(), aOutputSizePixel
.Width() ) );
1537 aMapMode
.SetScaleY( Fraction( aSizePixel
.Height(), aOutputSizePixel
.Height() ) );
1539 pVDev
->SetMapMode( aMapMode
);
1540 pVDev
->SetOutputSizePixel( aSizePixel
);
1541 pVDev
->SetFillColor( Color( COL_BLACK
) );
1542 const tools::PolyPolygon
aClip( aClipPath
.getClipPath() );
1543 pVDev
->DrawPolyPolygon( aClip
);
1544 const Point aEmptyPoint
;
1546 // #i50672# Extract whole VDev content (to match size of rBitmap)
1547 pVDev
->EnableMapMode( false );
1548 Bitmap
aMask( pVDev
->GetBitmap( aEmptyPoint
, aSizePixel
).CreateMask( Color( COL_WHITE
) ) );
1550 if ( aBmpEx
.IsTransparent() )
1552 if ( rBitmap
.GetTransparentColor() == Color( COL_WHITE
) )
1553 aMask
.CombineSimple( rBitmap
.GetMask(), BMP_COMBINE_OR
);
1555 aMask
.CombineSimple( rBitmap
.GetMask(), BMP_COMBINE_AND
);
1556 aBmpEx
= BitmapEx( rBitmap
.GetBitmap(), aMask
);
1559 aBmpEx
= BitmapEx( rBitmap
.GetBitmap(), aMask
);
1561 if ( aBmpEx
.IsTransparent() )
1562 mpGDIMetaFile
->AddAction( new MetaBmpExScaleAction( rPos
, rSize
, aBmpEx
) );
1564 mpGDIMetaFile
->AddAction( new MetaBmpScaleAction( rPos
, rSize
, aBmpEx
.GetBitmap() ) );
1567 void WinMtfOutput::ResolveBitmapActions( BSaveStructList_impl
& rSaveList
)
1571 size_t nObjects
= rSaveList
.size();
1572 size_t nObjectsLeft
= nObjects
;
1574 while ( nObjectsLeft
)
1577 size_t nObjectsOfSameSize
= 0;
1578 size_t nObjectStartIndex
= nObjects
- nObjectsLeft
;
1580 BSaveStruct
* pSave
= rSaveList
[ nObjectStartIndex
];
1581 Rectangle
aRect( pSave
->aOutRect
);
1583 for ( i
= nObjectStartIndex
; i
< nObjects
; )
1585 nObjectsOfSameSize
++;
1586 if ( ++i
< nObjects
)
1588 pSave
= rSaveList
[ i
];
1589 if ( pSave
->aOutRect
!= aRect
)
1593 Point
aPos( ImplMap( aRect
.TopLeft() ) );
1594 Size
aSize( ImplMap( aRect
.GetSize() ) );
1596 for ( i
= nObjectStartIndex
; i
< ( nObjectStartIndex
+ nObjectsOfSameSize
); i
++ )
1598 pSave
= rSaveList
[ i
];
1600 sal_uInt32 nWinRop
= pSave
->nWinRop
;
1601 sal_uInt8 nRasterOperation
= (sal_uInt8
)( nWinRop
>> 16 );
1603 sal_uInt32 nUsed
= 0;
1604 if ( ( nRasterOperation
& 0xf ) != ( nRasterOperation
>> 4 ) )
1605 nUsed
|= 1; // pattern is used
1606 if ( ( nRasterOperation
& 0x33 ) != ( ( nRasterOperation
& 0xcc ) >> 2 ) )
1607 nUsed
|= 2; // source is used
1608 if ( ( nRasterOperation
& 0xaa ) != ( ( nRasterOperation
& 0x55 ) << 1 ) )
1609 nUsed
|= 4; // destination is used
1611 if ( (nUsed
& 1) && (( nUsed
& 2 ) == 0) && nWinRop
!= PATINVERT
)
1612 { // patterns aren't well supported yet
1613 sal_uInt32 nOldRop
= SetRasterOp( ROP_OVERPAINT
); // in this case nRasterOperation is either 0 or 0xff
1615 DrawRect( aRect
, false );
1616 SetRasterOp( nOldRop
);
1620 bool bDrawn
= false;
1622 if ( i
== nObjectStartIndex
) // optimizing, sometimes it is possible to create just one transparent bitmap
1624 if ( nObjectsOfSameSize
== 2 )
1626 BSaveStruct
* pSave2
= rSaveList
[ i
+ 1 ];
1627 if ( ( pSave
->aBmp
.GetPrefSize() == pSave2
->aBmp
.GetPrefSize() ) &&
1628 ( pSave
->aBmp
.GetPrefMapMode() == pSave2
->aBmp
.GetPrefMapMode() ) )
1630 // TODO: Strictly speaking, we should
1631 // check whether mask is monochrome, and
1632 // whether image is black (upper branch)
1633 // or white (lower branch). Otherwise, the
1634 // effect is not the same as a masked
1636 if ( ( nWinRop
== SRCPAINT
) && ( pSave2
->nWinRop
== SRCAND
) )
1638 Bitmap
aMask( pSave
->aBmp
); aMask
.Invert();
1639 BitmapEx
aBmpEx( pSave2
->aBmp
, aMask
);
1640 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1644 // #i20085# This is just the other way
1645 // around as above. Only difference: mask
1647 else if ( ( nWinRop
== SRCAND
) && ( pSave2
->nWinRop
== SRCPAINT
) )
1649 Bitmap
aMask( pSave
->aBmp
);
1650 BitmapEx
aBmpEx( pSave2
->aBmp
, aMask
);
1651 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1656 else if ( ( nWinRop
== SRCAND
) && ( pSave2
->nWinRop
== SRCINVERT
) )
1658 Bitmap
aMask( pSave
->aBmp
);
1659 BitmapEx
aBmpEx( pSave2
->aBmp
, aMask
);
1660 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1671 sal_uInt32 nOldRop
= SetRasterOp( R2_COPYPEN
);
1672 Bitmap
aBitmap( pSave
->aBmp
);
1673 sal_uInt32 nOperation
= ( nRasterOperation
& 0xf );
1674 switch( nOperation
)
1679 SetRasterOp( R2_XORPEN
);
1680 ImplDrawBitmap( aPos
, aSize
, aBitmap
);
1681 SetRasterOp( R2_COPYPEN
);
1682 Bitmap
aMask( aBitmap
);
1684 BitmapEx
aBmpEx( aBitmap
, aMask
);
1685 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1686 if ( nOperation
== 0x1 )
1688 SetRasterOp( R2_NOT
);
1689 DrawRect( aRect
, false );
1696 Bitmap
aMask( aBitmap
);
1697 if ( ( nUsed
& 1 ) && ( nRasterOperation
& 0xb0 ) == 0xb0 ) // pattern used
1699 aBitmap
.Convert( BMP_CONVERSION_24BIT
);
1700 aBitmap
.Erase( maFillStyle
.aFillColor
);
1702 BitmapEx
aBmpEx( aBitmap
, aMask
);
1703 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1704 if ( nOperation
== 0x7 )
1706 SetRasterOp( R2_NOT
);
1707 DrawRect( aRect
, false );
1715 SetRasterOp( R2_NOT
);
1716 DrawRect( aRect
, false );
1717 SetRasterOp( R2_COPYPEN
);
1718 Bitmap
aMask( aBitmap
);
1720 BitmapEx
aBmpEx( aBitmap
, aMask
);
1721 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1722 SetRasterOp( R2_XORPEN
);
1723 ImplDrawBitmap( aPos
, aSize
, aBitmap
);
1724 if ( nOperation
== 0xb )
1726 SetRasterOp( R2_NOT
);
1727 DrawRect( aRect
, false );
1735 Bitmap
aMask( aBitmap
);
1737 BitmapEx
aBmpEx( aBitmap
, aMask
);
1738 ImplDrawBitmap( aPos
, aSize
, aBmpEx
);
1739 SetRasterOp( R2_XORPEN
);
1740 ImplDrawBitmap( aPos
, aSize
, aBitmap
);
1741 if ( nOperation
== 0xd )
1743 SetRasterOp( R2_NOT
);
1744 DrawRect( aRect
, false );
1751 SetRasterOp( R2_XORPEN
);
1752 ImplDrawBitmap( aPos
, aSize
, aBitmap
);
1753 if ( nOperation
== 0x9 )
1755 SetRasterOp( R2_NOT
);
1756 DrawRect( aRect
, false );
1761 case 0x0 : // WHITENESS
1762 case 0xf : // BLACKNESS
1763 { // in this case nRasterOperation is either 0 or 0xff
1764 maFillStyle
= WinMtfFillStyle( Color( nRasterOperation
, nRasterOperation
, nRasterOperation
) );
1766 DrawRect( aRect
, false );
1770 case 0x3 : // only source is used
1773 if ( nRasterOperation
== 0x33 )
1775 ImplDrawBitmap( aPos
, aSize
, aBitmap
);
1779 case 0x5 : // only destination is used
1781 SetRasterOp( R2_NOT
);
1782 DrawRect( aRect
, false );
1784 case 0xa : // no operation
1787 SetRasterOp( nOldRop
);
1792 nObjectsLeft
-= nObjectsOfSameSize
;
1795 for( size_t i
= 0, n
= rSaveList
.size(); i
< n
; ++i
)
1796 delete rSaveList
[ i
];
1800 void WinMtfOutput::SetDevOrg( const Point
& rPoint
)
1802 mnDevOrgX
= rPoint
.X();
1803 mnDevOrgY
= rPoint
.Y();
1806 void WinMtfOutput::SetDevOrgOffset( sal_Int32 nXAdd
, sal_Int32 nYAdd
)
1812 void WinMtfOutput::SetDevExt( const Size
& rSize
,bool regular
)
1814 if ( rSize
.Width() && rSize
.Height() )
1819 case MM_ANISOTROPIC
:
1821 mnDevWidth
= rSize
.Width();
1822 mnDevHeight
= rSize
.Height();
1832 void WinMtfOutput::ScaleDevExt( double fX
, double fY
)
1834 mnDevWidth
= FRound( mnDevWidth
* fX
);
1835 mnDevHeight
= FRound( mnDevHeight
* fY
);
1838 void WinMtfOutput::SetWinOrg( const Point
& rPoint
, bool bIsEMF
)
1840 mnWinOrgX
= rPoint
.X();
1841 mnWinOrgY
= rPoint
.Y();
1849 void WinMtfOutput::SetWinOrgOffset( sal_Int32 nXAdd
, sal_Int32 nYAdd
)
1855 void WinMtfOutput::SetDevByWin() //mnWinExt...-stuff has to be assigned before.
1859 if ( mnMapMode
== MM_ISOTROPIC
) //TODO: WHAT ABOUT ANISOTROPIC???
1861 Size
aSize( (mnWinExtX
+ mnWinOrgX
) >> MS_FIXPOINT_BITCOUNT_28_4
,
1862 -((mnWinExtY
- mnWinOrgY
) >> MS_FIXPOINT_BITCOUNT_28_4
));
1864 SetDevExt(aSize
, false);
1869 void WinMtfOutput::SetWinExt(const Size
& rSize
, bool bIsEMF
)
1871 if (rSize
.Width() && rSize
.Height())
1876 case MM_ANISOTROPIC
:
1878 mnWinExtX
= rSize
.Width();
1879 mnWinExtY
= rSize
.Height();
1884 mbIsMapWinSet
= true;
1890 void WinMtfOutput::ScaleWinExt( double fX
, double fY
)
1892 mnWinExtX
= FRound( mnWinExtX
* fX
);
1893 mnWinExtY
= FRound( mnWinExtY
* fY
);
1896 void WinMtfOutput::SetrclBounds( const Rectangle
& rRect
)
1901 void WinMtfOutput::SetrclFrame( const Rectangle
& rRect
)
1906 void WinMtfOutput::SetRefPix( const Size
& rSize
)
1908 mnPixX
= rSize
.Width();
1909 mnPixY
= rSize
.Height();
1912 void WinMtfOutput::SetRefMill( const Size
& rSize
)
1914 mnMillX
= rSize
.Width();
1915 mnMillY
= rSize
.Height();
1918 void WinMtfOutput::SetMapMode( sal_uInt32 nMapMode
)
1920 mnMapMode
= nMapMode
;
1921 if ( nMapMode
== MM_TEXT
&& !mbIsMapWinSet
)
1923 mnWinExtX
= mnDevWidth
;
1924 mnWinExtY
= mnDevHeight
;
1926 else if ( mnMapMode
== MM_HIMETRIC
)
1928 mnWinExtX
= mnMillX
* 100;
1929 mnWinExtY
= mnMillY
* 100;
1933 void WinMtfOutput::SetWorldTransform( const XForm
& rXForm
)
1935 maXForm
.eM11
= rXForm
.eM11
;
1936 maXForm
.eM12
= rXForm
.eM12
;
1937 maXForm
.eM21
= rXForm
.eM21
;
1938 maXForm
.eM22
= rXForm
.eM22
;
1939 maXForm
.eDx
= rXForm
.eDx
;
1940 maXForm
.eDy
= rXForm
.eDy
;
1943 void WinMtfOutput::ModifyWorldTransform( const XForm
& rXForm
, sal_uInt32 nMode
)
1949 maXForm
.eM11
= maXForm
.eM22
= 1.0f
;
1950 maXForm
.eM12
= maXForm
.eM21
= maXForm
.eDx
= maXForm
.eDy
= 0.0f
;
1954 case MWT_RIGHTMULTIPLY
:
1955 case MWT_LEFTMULTIPLY
:
1958 const XForm
* pRight
;
1960 if ( nMode
== MWT_LEFTMULTIPLY
)
1975 aF
[0][0] = pLeft
->eM11
;
1976 aF
[0][1] = pLeft
->eM12
;
1978 aF
[1][0] = pLeft
->eM21
;
1979 aF
[1][1] = pLeft
->eM22
;
1981 aF
[2][0] = pLeft
->eDx
;
1982 aF
[2][1] = pLeft
->eDy
;
1985 bF
[0][0] = pRight
->eM11
;
1986 bF
[0][1] = pRight
->eM12
;
1988 bF
[1][0] = pRight
->eM21
;
1989 bF
[1][1] = pRight
->eM22
;
1991 bF
[2][0] = pRight
->eDx
;
1992 bF
[2][1] = pRight
->eDy
;
1996 for ( i
= 0; i
< 3; i
++ )
1998 for ( j
= 0; j
< 3; j
++ )
2001 for ( k
= 0; k
< 3; k
++ )
2002 cF
[i
][j
] += aF
[i
][k
] * bF
[k
][j
];
2005 maXForm
.eM11
= cF
[0][0];
2006 maXForm
.eM12
= cF
[0][1];
2007 maXForm
.eM21
= cF
[1][0];
2008 maXForm
.eM22
= cF
[1][1];
2009 maXForm
.eDx
= cF
[2][0];
2010 maXForm
.eDy
= cF
[2][1];
2015 SetWorldTransform(rXForm
);
2021 void WinMtfOutput::Push() // !! to be able to access the original ClipRegion it
2022 { // is not allowed to use the MetaPushAction()
2023 UpdateClipRegion(); // (the original clip region is on top of the stack) (SJ)
2024 SaveStructPtr
pSave( new SaveStruct
);
2026 pSave
->aLineStyle
= maLineStyle
;
2027 pSave
->aFillStyle
= maFillStyle
;
2029 pSave
->aFont
= maFont
;
2030 pSave
->aTextColor
= maTextColor
;
2031 pSave
->nTextAlign
= mnTextAlign
;
2032 pSave
->nTextLayoutMode
= mnTextLayoutMode
;
2033 pSave
->nMapMode
= mnMapMode
;
2034 pSave
->nGfxMode
= mnGfxMode
;
2035 pSave
->nBkMode
= mnBkMode
;
2036 pSave
->aBkColor
= maBkColor
;
2037 pSave
->bFillStyleSelected
= mbFillStyleSelected
;
2039 pSave
->aActPos
= maActPos
;
2040 pSave
->aXForm
= maXForm
;
2041 pSave
->eRasterOp
= meRasterOp
;
2043 pSave
->nWinOrgX
= mnWinOrgX
;
2044 pSave
->nWinOrgY
= mnWinOrgY
;
2045 pSave
->nWinExtX
= mnWinExtX
;
2046 pSave
->nWinExtY
= mnWinExtY
;
2047 pSave
->nDevOrgX
= mnDevOrgX
;
2048 pSave
->nDevOrgY
= mnDevOrgY
;
2049 pSave
->nDevWidth
= mnDevWidth
;
2050 pSave
->nDevHeight
= mnDevHeight
;
2052 pSave
->aPathObj
= aPathObj
;
2053 pSave
->aClipPath
= aClipPath
;
2055 vSaveStack
.push_back( pSave
);
2058 void WinMtfOutput::Pop()
2060 // Get the latest data from the stack
2061 if( !vSaveStack
.empty() )
2063 // Backup the current data on the stack
2064 SaveStructPtr
pSave( vSaveStack
.back() );
2066 maLineStyle
= pSave
->aLineStyle
;
2067 maFillStyle
= pSave
->aFillStyle
;
2069 maFont
= pSave
->aFont
;
2070 maTextColor
= pSave
->aTextColor
;
2071 mnTextAlign
= pSave
->nTextAlign
;
2072 mnTextLayoutMode
= pSave
->nTextLayoutMode
;
2073 mnBkMode
= pSave
->nBkMode
;
2074 mnGfxMode
= pSave
->nGfxMode
;
2075 mnMapMode
= pSave
->nMapMode
;
2076 maBkColor
= pSave
->aBkColor
;
2077 mbFillStyleSelected
= pSave
->bFillStyleSelected
;
2079 maActPos
= pSave
->aActPos
;
2080 maXForm
= pSave
->aXForm
;
2081 meRasterOp
= pSave
->eRasterOp
;
2083 mnWinOrgX
= pSave
->nWinOrgX
;
2084 mnWinOrgY
= pSave
->nWinOrgY
;
2085 mnWinExtX
= pSave
->nWinExtX
;
2086 mnWinExtY
= pSave
->nWinExtY
;
2087 mnDevOrgX
= pSave
->nDevOrgX
;
2088 mnDevOrgY
= pSave
->nDevOrgY
;
2089 mnDevWidth
= pSave
->nDevWidth
;
2090 mnDevHeight
= pSave
->nDevHeight
;
2092 aPathObj
= pSave
->aPathObj
;
2093 if ( ! ( aClipPath
== pSave
->aClipPath
) )
2095 aClipPath
= pSave
->aClipPath
;
2096 mbClipNeedsUpdate
= true;
2098 if ( meLatestRasterOp
!= meRasterOp
)
2099 mpGDIMetaFile
->AddAction( new MetaRasterOpAction( meRasterOp
) );
2100 vSaveStack
.pop_back();
2104 void WinMtfOutput::AddFromGDIMetaFile( GDIMetaFile
& rGDIMetaFile
)
2106 rGDIMetaFile
.Play( *mpGDIMetaFile
, 0xFFFFFFFF );
2109 void WinMtfOutput::PassEMFPlusHeaderInfo()
2111 EMFP_DEBUG(printf ("\t\t\tadd EMF_PLUS header info\n"));
2114 sal_Int32 nLeft
, nRight
, nTop
, nBottom
;
2116 nLeft
= mrclFrame
.Left();
2117 nTop
= mrclFrame
.Top();
2118 nRight
= mrclFrame
.Right();
2119 nBottom
= mrclFrame
.Bottom();
2122 mem
.WriteInt32( nLeft
).WriteInt32( nTop
).WriteInt32( nRight
).WriteInt32( nBottom
);
2123 mem
.WriteInt32( mnPixX
).WriteInt32( mnPixY
).WriteInt32( mnMillX
).WriteInt32( mnMillY
);
2130 // add transformation matrix to be used in vcl's metaact.cxx for
2131 // rotate and scale operations
2132 mem
.WriteFloat( one
).WriteFloat( zero
).WriteFloat( zero
).WriteFloat( one
).WriteFloat( zero
).WriteFloat( zero
);
2134 // need to flush the stream, otherwise GetEndOfData will return 0
2135 // on windows where the function parameters are probably resolved in reverse order
2138 mpGDIMetaFile
->AddAction( new MetaCommentAction( "EMF_PLUS_HEADER_INFO", 0, static_cast<const sal_uInt8
*>(mem
.GetData()), mem
.GetEndOfData() ) );
2139 mpGDIMetaFile
->UseCanvas( true );
2142 void WinMtfOutput::PassEMFPlus( void* pBuffer
, sal_uInt32 nLength
)
2144 EMFP_DEBUG(printf ("\t\t\tadd EMF_PLUS comment length %04x\n",(unsigned int) nLength
));
2145 mpGDIMetaFile
->AddAction( new MetaCommentAction( "EMF_PLUS", 0, static_cast<const sal_uInt8
*>(pBuffer
), nLength
) );
2148 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */