Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / source / filter / wmf / winmtf.cxx
blob513751d0a75bb8f2ae64f25c287db65357d1df93
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "winmtf.hxx"
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
35 #else
36 #define EMFP_DEBUG(x)
37 #endif
39 void WinMtfClipPath::intersectClipRect( const Rectangle& rRect )
41 maClip.intersectRange(
42 vcl::unotools::b2DRectangleFromRectangle(rRect));
45 void WinMtfClipPath::excludeClipRect( const Rectangle& rRect )
47 maClip.subtractRange(
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 )
56 case RGN_OR :
57 maClip.unionPolyPolygon(rB2DPoly);
58 break;
59 case RGN_XOR :
60 maClip.xorPolyPolygon(rB2DPoly);
61 break;
62 case RGN_DIFF :
63 maClip.subtractPolyPolygon(rB2DPoly);
64 break;
65 case RGN_AND :
66 maClip.intersectPolyPolygon(rB2DPoly);
67 break;
68 case RGN_COPY :
69 maClip = basegfx::tools::B2DClipState(rB2DPoly);
70 break;
74 void WinMtfClipPath::moveClipRegion( const Size& rSize )
76 // what a weird concept. emulate, don't want this in B2DClipState
77 // API
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 )
99 if ( bClosed )
100 Insert( Polygon(), POLYPOLY_APPEND );
101 Polygon& rPoly = ((tools::PolyPolygon&)*this)[ Count() - 1 ];
102 rPoly.Insert( rPoly.GetSize(), rPoint, POLY_NORMAL );
103 bClosed = false;
106 void WinMtfPathObj::AddPolyLine( const Polygon& rPolyLine )
108 if ( bClosed )
109 Insert( Polygon(), POLYPOLY_APPEND );
110 Polygon& rPoly = ((tools::PolyPolygon&)*this)[ Count() - 1 ];
111 rPoly.Insert( rPoly.GetSize(), rPolyLine );
112 bClosed = false;
115 void WinMtfPathObj::AddPolygon( const Polygon& rPoly )
117 Insert( rPoly, POLYPOLY_APPEND );
118 bClosed = true;
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 );
126 bClosed = true;
129 void WinMtfPathObj::ClosePath()
131 if ( Count() )
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 );
141 bClosed = true;
144 WinMtfFontStyle::WinMtfFontStyle( LOGFONTW& rFont )
146 rtl_TextEncoding eCharSet;
147 if ( ( rFont.lfCharSet == OEM_CHARSET ) || ( rFont.lfCharSet == DEFAULT_CHARSET ) )
148 eCharSet = osl_getThreadTextEncoding();
149 else
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 );
155 FontFamily eFamily;
156 switch ( rFont.lfPitchAndFamily & 0xf0 )
158 case FF_ROMAN:
159 eFamily = FAMILY_ROMAN;
160 break;
162 case FF_SWISS:
163 eFamily = FAMILY_SWISS;
164 break;
166 case FF_MODERN:
167 eFamily = FAMILY_MODERN;
168 break;
170 case FF_SCRIPT:
171 eFamily = FAMILY_SCRIPT;
172 break;
174 case FF_DECORATIVE:
175 eFamily = FAMILY_DECORATIVE;
176 break;
178 default:
179 eFamily = FAMILY_DONTKNOW;
180 break;
182 aFont.SetFamily( eFamily );
184 FontPitch ePitch;
185 switch ( rFont.lfPitchAndFamily & 0x0f )
187 case FIXED_PITCH:
188 ePitch = PITCH_FIXED;
189 break;
191 case DEFAULT_PITCH:
192 case VARIABLE_PITCH:
193 default:
194 ePitch = PITCH_VARIABLE;
195 break;
197 aFont.SetPitch( ePitch );
199 FontWeight eWeight;
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;
216 else
217 eWeight = WEIGHT_BLACK;
218 aFont.SetWeight( eWeight );
220 if( rFont.lfItalic )
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 );
231 else
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();
245 if (nHeight)
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 )
261 , nEndPos( 0 )
262 , pFilterConfigItem( pConfigItem )
264 SvLockBytes *pLB = pWMF->GetLockBytes();
265 if ( pLB )
266 pLB->SetSynchronMode( true );
268 nStartPos = pWMF->Tell();
270 pOut->SetDevOrg( Point() );
271 if ( pFilterConfigItem )
273 xStatusIndicator = pFilterConfigItem->GetStatusIndicator();
274 if ( xStatusIndicator.is() )
276 OUString aMsg;
277 xStatusIndicator->start( aMsg, 100 );
282 WinMtf::~WinMtf()
284 delete pOut;
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()
298 sal_uInt32 nColor;
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.
305 if (!mbIsMapDevSet)
306 return Point(rPoint.X() * UNDOCUMENTED_WIN_RCL_RELATION - mrclFrame.Left(),
307 rPoint.Y() * UNDOCUMENTED_WIN_RCL_RELATION - mrclFrame.Top());
308 else
309 return rPoint;
312 Point WinMtfOutput::ImplMap( const Point& rPt )
314 if ( mnWinExtX && mnWinExtY )
316 double fX = rPt.X();
317 double fY = rPt.Y();
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 )
324 switch( mnMapMode )
326 case MM_LOENGLISH :
328 fX2 -= mnWinOrgX;
329 fY2 = mnWinOrgY-fY2;
330 fX2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH*10;
331 fY2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH*10;
332 fX2 += mnDevOrgX;
333 fY2 += mnDevOrgY;
335 break;
336 case MM_HIENGLISH :
338 fX2 -= mnWinOrgX;
339 fY2 = mnWinOrgY-fY2;
340 fX2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH;
341 fY2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH;
342 fX2 += mnDevOrgX;
343 fY2 += mnDevOrgY;
345 break;
346 case MM_TWIPS:
348 fX2 -= mnWinOrgX;
349 fY2 = mnWinOrgY-fY2;
350 fX2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH/MILLIINCH_PER_TWIPS;
351 fY2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH/MILLIINCH_PER_TWIPS;
352 fX2 += mnDevOrgX;
353 fY2 += mnDevOrgY;
355 break;
356 case MM_LOMETRIC :
358 fX2 -= mnWinOrgX;
359 fY2 = mnWinOrgY-fY2;
360 fX2 *= 10;
361 fY2 *= 10;
362 fX2 += mnDevOrgX;
363 fY2 += mnDevOrgY;
365 break;
366 case MM_HIMETRIC : // in hundredth of a millimeter
368 fX2 -= mnWinOrgX;
369 fY2 = mnWinOrgY-fY2;
370 fX2 += mnDevOrgX;
371 fY2 += mnDevOrgY;
373 break;
374 default :
376 fX2 -= mnWinOrgX;
377 fY2 -= mnWinOrgY;
378 fX2 /= mnWinExtX;
379 fY2 /= mnWinExtY;
380 fX2 *= mnDevWidth;
381 fY2 *= mnDevHeight;
382 fX2 += mnDevOrgX;
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;
387 break;
389 fX2 -= mrclFrame.Left();
390 fY2 -= mrclFrame.Top();
392 return Point( FRound( fX2 ), FRound( fY2 ) );
394 else
395 return Point();
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;
409 else
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))
418 aScale.setX(1.0);
419 aScale.setY(1.0);
421 fWidth = rSz.Width() * aScale.getX();
422 fHeight = rSz.Height() * aScale.getY();
425 if ( mnGfxMode == GM_COMPATIBLE )
427 switch( mnMapMode )
429 case MM_LOENGLISH :
431 fWidth *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH*10;
432 fHeight*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH*10;
434 break;
435 case MM_HIENGLISH :
437 fWidth *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH;
438 fHeight*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH;
440 break;
441 case MM_LOMETRIC :
443 fWidth *= 10;
444 fHeight*=-10;
446 break;
447 case MM_HIMETRIC : // in hundredth of millimeters
449 fHeight *= -1;
451 break;
452 case MM_TWIPS:
454 fWidth *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH/MILLIINCH_PER_TWIPS;
455 fHeight*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH/MILLIINCH_PER_TWIPS;
457 break;
458 default :
460 fWidth /= mnWinExtX;
461 fHeight /= mnWinExtY;
462 fWidth *= mnDevWidth;
463 fHeight *= mnDevHeight;
464 fWidth *= (double)mnMillX * 100 / (double)mnPixX;
465 fHeight *= (double)mnMillY * 100 / (double)mnPixY;
467 break;
470 return Size( FRound( fWidth ), FRound( fHeight ) );
472 else
473 return Size();
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 ] );
503 return rPolygon;
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 ] );
513 return rPolygon;
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]);
523 return rPolyPolygon;
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++ ] ) ) ;
530 return rPolyPolygon;
533 void WinMtfOutput::SelectObject( sal_Int32 nIndex )
535 GDIObj* pGDIObj = NULL;
537 if ( nIndex & ENHMETA_STOCK_OBJECT )
538 pGDIObj = new GDIObj();
539 else
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 )
548 return;
550 if ( nIndex & ENHMETA_STOCK_OBJECT )
552 sal_uInt16 nStockId = (sal_uInt8)nIndex;
553 switch( nStockId )
555 case WHITE_BRUSH :
557 pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ) ) );
559 break;
560 case LTGRAY_BRUSH :
562 pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_LIGHTGRAY ) ) );
564 break;
565 case GRAY_BRUSH :
566 case DKGRAY_BRUSH :
568 pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_GRAY ) ) );
570 break;
571 case BLACK_BRUSH :
573 pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_BLACK ) ) );
575 break;
576 case NULL_BRUSH :
578 pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_TRANSPARENT ), true ) );
580 break;
581 case WHITE_PEN :
583 pGDIObj->Set( GDI_PEN, new WinMtfLineStyle( Color( COL_WHITE ) ) );
585 break;
586 case BLACK_PEN :
588 pGDIObj->Set( GDI_PEN, new WinMtfLineStyle( Color( COL_BLACK ) ) );
590 break;
591 case NULL_PEN :
593 pGDIObj->Set( GDI_PEN, new WinMtfLineStyle( Color( COL_TRANSPARENT ), true ) );
595 break;
596 default:
597 break;
600 if ( pGDIObj->pStyle )
602 switch( pGDIObj->eType )
604 case GDI_PEN :
605 maLineStyle = static_cast<WinMtfLineStyle*>(pGDIObj->pStyle);
606 break;
607 case GDI_BRUSH :
609 maFillStyle = static_cast<WinMtfFillStyle*>(pGDIObj->pStyle);
610 mbFillStyleSelected = true;
612 break;
613 case GDI_FONT :
614 maFont = static_cast<WinMtfFontStyle*>(pGDIObj->pStyle)->aFont;
615 break;
616 default:
617 break; // -Wall many options not handled.
620 if ( nIndex & ENHMETA_STOCK_OBJECT )
621 delete pGDIObj;
625 void WinMtfOutput::SetTextLayoutMode( ComplexTextLayoutMode nTextLayoutMode )
627 mnTextLayoutMode = nTextLayoutMode;
630 void WinMtfOutput::SetBkMode( BkMode nMode )
632 mnBkMode = nMode;
635 void WinMtfOutput::SetBkColor( const Color& rColor )
637 maBkColor = 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() ) );
664 else
666 Polygon aPoly( rPolyPoly[ 0 ] );
667 sal_uInt16 nCount = aPoly.GetSize();
668 if ( nCount )
670 if ( aPoly[ nCount - 1 ] != aPoly[ 0 ] )
672 Point aPoint( aPoly[ 0 ] );
673 aPoly.Insert( nCount, aPoint );
675 mpGDIMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
679 else
680 mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPoly ) );
684 void WinMtfOutput::CreateObject( GDIObjectType eType, void* pStyle )
686 if ( 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());
703 sal_uInt32 nIndex;
704 for ( nIndex = 0; nIndex < vGDIObj.size(); nIndex++ )
706 if ( vGDIObj[ nIndex ] == NULL )
707 break;
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
720 if ( pStyle )
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 );
745 else
747 switch ( eType )
749 case GDI_PEN :
750 delete static_cast<WinMtfLineStyle*>(pStyle);
751 break;
752 case GDI_BRUSH :
753 delete static_cast<WinMtfFillStyle*>(pStyle);
754 break;
755 case GDI_FONT :
756 delete static_cast<WinMtfFontStyle*>(pStyle);
757 break;
759 default:
760 OSL_FAIL( "unsupported style not deleted" );
761 break;
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);
805 if (!bIsMapped)
807 if (!mbIsMapDevSet && (mnMapMode == MM_ISOTROPIC || mnMapMode == MM_ANISOTROPIC))
808 aPolyPolygon = ImplScale(aPolyPolygon);
809 else
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() ),
833 mbNopMode ( false ),
834 mbFillStyleSelected ( false ),
835 mbClipNeedsUpdate ( true ),
836 mbComplexClip ( false ),
837 mnGfxMode ( GM_COMPATIBLE ),
838 mnMapMode ( MM_TEXT ),
839 mnDevOrgX ( 0 ),
840 mnDevOrgY ( 0 ),
841 mnDevWidth ( 1 ),
842 mnDevHeight ( 1 ),
843 mnWinOrgX ( 0 ),
844 mnWinOrgY ( 0 ),
845 mnWinExtX ( 1 ),
846 mnWinExtY ( 1 ),
847 mnPixX ( 100 ),
848 mnPixY ( 100 ),
849 mnMillX ( 1 ),
850 mnMillY ( 1 ),
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 ) );
877 else
878 mpGDIMetaFile->SetPrefSize( mrclFrame.GetSize() );
880 for ( sal_uInt32 i = 0; i < vGDIObj.size(); i++ )
881 delete vGDIObj[ 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 )
946 mnRop = nRasterOp;
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;
953 mbNopMode = false;
955 switch( nRasterOp )
957 case R2_NOT:
958 meRasterOp = ROP_INVERT;
959 break;
961 case R2_XORPEN:
962 meRasterOp = ROP_XOR;
963 break;
965 case R2_NOP:
967 meRasterOp = ROP_OVERPAINT;
968 if( !mbNopMode )
970 m_NopFillStyle = maFillStyle;
971 aNopLineStyle = maLineStyle;
972 maFillStyle = WinMtfFillStyle( Color( COL_TRANSPARENT ), true );
973 maLineStyle = WinMtfLineStyle( Color( COL_TRANSPARENT ), true );
974 mbNopMode = true;
977 break;
979 default:
980 meRasterOp = ROP_OVERPAINT;
981 break;
984 if ( nRetROP != nRasterOp )
985 mpGDIMetaFile->AddAction( new MetaRasterOpAction( meRasterOp ) );
986 return nRetROP;
989 void WinMtfOutput::StrokeAndFillPath( bool bStroke, bool bFill )
991 if ( aPathObj.Count() )
993 UpdateClipRegion();
994 UpdateLineStyle();
995 UpdateFillStyle();
996 if ( bFill )
998 if ( !bStroke )
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 ) ) );
1005 else
1006 mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( aPathObj ) );
1008 if ( !bStroke )
1009 mpGDIMetaFile->AddAction( new MetaPopAction() );
1011 else
1013 sal_uInt16 i, nCount = aPathObj.Count();
1014 for ( i = 0; i < nCount; i++ )
1015 mpGDIMetaFile->AddAction( new MetaPolyLineAction( aPathObj[ i ], maLineStyle.aLineInfo ) );
1017 ClearPath();
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 ) );
1029 if ( bRecordPath )
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 );
1037 maActPos = aDest;
1040 void WinMtfOutput::LineTo( const Point& rPoint, bool bRecordPath )
1042 UpdateClipRegion();
1043 Point aDest( ImplMap( rPoint ) );
1044 if ( bRecordPath )
1045 aPathObj.AddPoint( aDest );
1046 else
1048 UpdateLineStyle();
1049 mpGDIMetaFile->AddAction( new MetaLineAction( maActPos, aDest, maLineStyle.aLineInfo ) );
1051 maActPos = aDest;
1054 void WinMtfOutput::DrawRect( const Rectangle& rRect, bool bEdge )
1056 UpdateClipRegion();
1057 UpdateFillStyle();
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 );
1067 else
1069 if ( bEdge )
1071 if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) )
1073 ImplSetNonPersistentLineColorTransparenz();
1074 mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) );
1075 UpdateLineStyle();
1076 mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( ImplMap( rRect ) ),maLineStyle.aLineInfo ) );
1078 else
1080 UpdateLineStyle();
1081 mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) );
1084 else
1086 ImplSetNonPersistentLineColorTransparenz();
1087 mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) );
1092 void WinMtfOutput::DrawRoundRect( const Rectangle& rRect, const Size& rSize )
1094 UpdateClipRegion();
1095 UpdateLineStyle();
1096 UpdateFillStyle();
1097 mpGDIMetaFile->AddAction( new MetaRoundRectAction( ImplMap( rRect ), labs( ImplMap( rSize ).Width() ), labs( ImplMap( rSize ).Height() ) ) );
1100 void WinMtfOutput::DrawEllipse( const Rectangle& rRect )
1102 UpdateClipRegion();
1103 UpdateFillStyle();
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 ) ) );
1112 UpdateLineStyle();
1113 mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aCenter, aRad.Width(), aRad.Height() ), maLineStyle.aLineInfo ) );
1115 else
1117 UpdateLineStyle();
1118 mpGDIMetaFile->AddAction( new MetaEllipseAction( ImplMap( rRect ) ) );
1122 void WinMtfOutput::DrawArc( const Rectangle& rRect, const Point& rStart, const Point& rEnd, bool bTo )
1124 UpdateClipRegion();
1125 UpdateLineStyle();
1126 UpdateFillStyle();
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 ) );
1141 else
1142 mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aRect, aStart, aEnd, POLY_ARC ), maLineStyle.aLineInfo ) );
1144 else
1145 mpGDIMetaFile->AddAction( new MetaArcAction( aRect, aStart, aEnd ) );
1147 if ( bTo )
1148 maActPos = aEnd;
1151 void WinMtfOutput::DrawPie( const Rectangle& rRect, const Point& rStart, const Point& rEnd )
1153 UpdateClipRegion();
1154 UpdateFillStyle();
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 ) );
1164 UpdateLineStyle();
1165 mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aRect, aStart, aEnd, POLY_PIE ), maLineStyle.aLineInfo ) );
1167 else
1169 UpdateLineStyle();
1170 mpGDIMetaFile->AddAction( new MetaPieAction( aRect, aStart, aEnd ) );
1174 void WinMtfOutput::DrawChord( const Rectangle& rRect, const Point& rStart, const Point& rEnd )
1176 UpdateClipRegion();
1177 UpdateFillStyle();
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 ) );
1187 UpdateLineStyle();
1188 mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aRect, aStart, aEnd, POLY_CHORD ), maLineStyle.aLineInfo ) );
1190 else
1192 UpdateLineStyle();
1193 mpGDIMetaFile->AddAction( new MetaChordAction( aRect, aStart, aEnd ) );
1197 void WinMtfOutput::DrawPolygon( Polygon& rPolygon, bool bRecordPath )
1199 UpdateClipRegion();
1200 ImplMap( rPolygon );
1201 if ( bRecordPath )
1202 aPathObj.AddPolygon( rPolygon );
1203 else
1205 UpdateFillStyle();
1207 if ( mbComplexClip )
1209 tools::PolyPolygon aPolyPoly( rPolygon );
1210 tools::PolyPolygon aDest;
1211 tools::PolyPolygon(aClipPath.getClipPath()).GetIntersection( aPolyPoly, aDest );
1212 ImplDrawClippedPolyPolygon( aDest );
1214 else
1216 if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) )
1218 sal_uInt16 nCount = rPolygon.GetSize();
1219 if ( nCount )
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 ) );
1229 UpdateLineStyle();
1230 mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) );
1232 else
1234 UpdateLineStyle();
1236 if (maLatestFillStyle.aType != FillStylePattern)
1237 mpGDIMetaFile->AddAction( new MetaPolygonAction( rPolygon ) );
1238 else {
1239 SvtGraphicFill aFill = SvtGraphicFill( tools::PolyPolygon( rPolygon ),
1240 Color(),
1241 0.0,
1242 SvtGraphicFill::fillNonZero,
1243 SvtGraphicFill::fillTexture,
1244 SvtGraphicFill::Transform(),
1245 true,
1246 SvtGraphicFill::hatchSingle,
1247 Color(),
1248 SvtGraphicFill::gradientLinear,
1249 Color(),
1250 Color(),
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 )
1271 UpdateClipRegion();
1273 ImplMap( rPolyPolygon );
1275 if ( bRecordPath )
1276 aPathObj.AddPolyPolygon( rPolyPolygon );
1277 else
1279 UpdateFillStyle();
1281 if ( mbComplexClip )
1283 tools::PolyPolygon aDest;
1284 tools::PolyPolygon(aClipPath.getClipPath()).GetIntersection( rPolyPolygon, aDest );
1285 ImplDrawClippedPolyPolygon( aDest );
1287 else
1289 UpdateLineStyle();
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 )
1304 UpdateClipRegion();
1306 sal_uInt16 nPoints = rPolygon.GetSize();
1307 if (nPoints >= 1)
1309 ImplMap( rPolygon );
1310 if ( bTo )
1312 rPolygon[ 0 ] = maActPos;
1313 maActPos = rPolygon[ rPolygon.GetSize() - 1 ];
1315 if ( bRecordPath )
1316 aPathObj.AddPolyLine( rPolygon );
1317 else
1319 UpdateLineStyle();
1320 mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) );
1325 void WinMtfOutput::DrawPolyBezier( Polygon& rPolygon, bool bTo, bool bRecordPath )
1327 UpdateClipRegion();
1329 sal_uInt16 nPoints = rPolygon.GetSize();
1330 if ( ( nPoints >= 4 ) && ( ( ( nPoints - 4 ) % 3 ) == 0 ) )
1332 ImplMap( rPolygon );
1333 if ( bTo )
1335 rPolygon[ 0 ] = maActPos;
1336 maActPos = rPolygon[ nPoints - 1 ];
1338 sal_uInt16 i;
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 );
1345 if ( bRecordPath )
1346 aPathObj.AddPolyLine( rPolygon );
1347 else
1349 UpdateLineStyle();
1350 mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) );
1355 void WinMtfOutput::DrawText( Point& rPosition, OUString& rText, long* pDXArry, bool bRecordPath, sal_Int32 nGfxMode )
1357 UpdateClipRegion();
1358 rPosition = ImplMap( rPosition );
1359 sal_Int32 nOldGfxMode = GetGfxMode();
1360 SetGfxMode( GM_COMPATIBLE );
1362 if (pDXArry)
1364 sal_Int32 i;
1365 sal_Int32 nSum = 0;
1366 sal_Int32 nLen = rText.getLength();
1368 for (i = 0; i < nLen; i++ )
1370 if (i > 0)
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());
1377 nSum += pDXArry[i];
1380 if ( mnLatestTextLayoutMode != mnTextLayoutMode )
1382 mnLatestTextLayoutMode = mnTextLayoutMode;
1383 mpGDIMetaFile->AddAction( new MetaLayoutModeAction( mnTextLayoutMode ) );
1385 SetGfxMode( nGfxMode );
1386 bool bChangeFont = false;
1387 if ( mnLatestTextAlign != mnTextAlign )
1389 bChangeFont = true;
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;
1396 else
1397 eTextAlign = ALIGN_TOP;
1398 mpGDIMetaFile->AddAction( new MetaTextAlignAction( eTextAlign ) );
1400 if ( maLatestTextColor != maTextColor )
1402 bChangeFont = true;
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 )
1419 bChangeFont = true;
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 );
1428 else
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 );
1435 else
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 ) ) );
1443 aP2.X() -= aP1.X();
1444 aP2.Y() -= aP1.Y();
1445 double fX = aP2.X();
1446 double fY = aP2.Y();
1447 if ( fX )
1449 double fOrientation = acos( fX / sqrt( fX * fX + fY * fY ) ) * 57.29577951308;
1450 if ( fY > 0 )
1451 fOrientation = 360 - fOrientation;
1452 fOrientation += 90;
1453 fOrientation *= 10;
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 );
1467 if( pDXArry )
1469 sal_uInt32 nLen = rText.getLength();
1470 nTextWidth = pVDev->GetTextWidth( OUString(rText[ nLen - 1 ]) );
1471 if( nLen > 1 )
1472 nTextWidth += pDXArry[ nLen - 2 ];
1474 else
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() ) );
1498 if ( bRecordPath )
1500 // TODO
1502 else
1504 /* because text without dx array is badly scaled, we
1505 will create such an array if necessary */
1506 long* pDX = pDXArry;
1507 if (!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 );
1554 else
1555 aMask.CombineSimple( rBitmap.GetMask(), BMP_COMBINE_AND );
1556 aBmpEx = BitmapEx( rBitmap.GetBitmap(), aMask );
1558 else
1559 aBmpEx = BitmapEx( rBitmap.GetBitmap(), aMask );
1561 if ( aBmpEx.IsTransparent() )
1562 mpGDIMetaFile->AddAction( new MetaBmpExScaleAction( rPos, rSize, aBmpEx ) );
1563 else
1564 mpGDIMetaFile->AddAction( new MetaBmpScaleAction( rPos, rSize, aBmpEx.GetBitmap() ) );
1567 void WinMtfOutput::ResolveBitmapActions( BSaveStructList_impl& rSaveList )
1569 UpdateClipRegion();
1571 size_t nObjects = rSaveList.size();
1572 size_t nObjectsLeft = nObjects;
1574 while ( nObjectsLeft )
1576 size_t i;
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 )
1590 break;
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
1614 UpdateFillStyle();
1615 DrawRect( aRect, false );
1616 SetRasterOp( nOldRop );
1618 else
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
1635 // bitmap.
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 );
1641 bDrawn = true;
1642 i++;
1644 // #i20085# This is just the other way
1645 // around as above. Only difference: mask
1646 // is inverted
1647 else if ( ( nWinRop == SRCAND ) && ( pSave2->nWinRop == SRCPAINT ) )
1649 Bitmap aMask( pSave->aBmp );
1650 BitmapEx aBmpEx( pSave2->aBmp, aMask );
1651 ImplDrawBitmap( aPos, aSize, aBmpEx );
1652 bDrawn = true;
1653 i++;
1655 // tdf#90539
1656 else if ( ( nWinRop == SRCAND ) && ( pSave2->nWinRop == SRCINVERT ) )
1658 Bitmap aMask( pSave->aBmp );
1659 BitmapEx aBmpEx( pSave2->aBmp, aMask );
1660 ImplDrawBitmap( aPos, aSize, aBmpEx );
1661 bDrawn = true;
1662 i++;
1668 if ( !bDrawn )
1670 Push();
1671 sal_uInt32 nOldRop = SetRasterOp( R2_COPYPEN );
1672 Bitmap aBitmap( pSave->aBmp );
1673 sal_uInt32 nOperation = ( nRasterOperation & 0xf );
1674 switch( nOperation )
1676 case 0x1 :
1677 case 0xe :
1679 SetRasterOp( R2_XORPEN );
1680 ImplDrawBitmap( aPos, aSize, aBitmap );
1681 SetRasterOp( R2_COPYPEN );
1682 Bitmap aMask( aBitmap );
1683 aMask.Invert();
1684 BitmapEx aBmpEx( aBitmap, aMask );
1685 ImplDrawBitmap( aPos, aSize, aBmpEx );
1686 if ( nOperation == 0x1 )
1688 SetRasterOp( R2_NOT );
1689 DrawRect( aRect, false );
1692 break;
1693 case 0x7 :
1694 case 0x8 :
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 );
1710 break;
1712 case 0x4 :
1713 case 0xb :
1715 SetRasterOp( R2_NOT );
1716 DrawRect( aRect, false );
1717 SetRasterOp( R2_COPYPEN );
1718 Bitmap aMask( aBitmap );
1719 aBitmap.Invert();
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 );
1730 break;
1732 case 0x2 :
1733 case 0xd :
1735 Bitmap aMask( aBitmap );
1736 aMask.Invert();
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 );
1747 break;
1748 case 0x6 :
1749 case 0x9 :
1751 SetRasterOp( R2_XORPEN );
1752 ImplDrawBitmap( aPos, aSize, aBitmap );
1753 if ( nOperation == 0x9 )
1755 SetRasterOp( R2_NOT );
1756 DrawRect( aRect, false );
1759 break;
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 ) );
1765 UpdateFillStyle();
1766 DrawRect( aRect, false );
1768 break;
1770 case 0x3 : // only source is used
1771 case 0xc :
1773 if ( nRasterOperation == 0x33 )
1774 aBitmap.Invert();
1775 ImplDrawBitmap( aPos, aSize, aBitmap );
1777 break;
1779 case 0x5 : // only destination is used
1781 SetRasterOp( R2_NOT );
1782 DrawRect( aRect, false );
1784 case 0xa : // no operation
1785 break;
1787 SetRasterOp( nOldRop );
1788 Pop();
1792 nObjectsLeft -= nObjectsOfSameSize;
1795 for( size_t i = 0, n = rSaveList.size(); i < n; ++i )
1796 delete rSaveList[ i ];
1797 rSaveList.clear();
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 )
1808 mnDevOrgX += nXAdd;
1809 mnDevOrgY += nYAdd;
1812 void WinMtfOutput::SetDevExt( const Size& rSize ,bool regular)
1814 if ( rSize.Width() && rSize.Height() )
1816 switch( mnMapMode )
1818 case MM_ISOTROPIC :
1819 case MM_ANISOTROPIC :
1821 mnDevWidth = rSize.Width();
1822 mnDevHeight = rSize.Height();
1825 if (regular)
1827 mbIsMapDevSet=true;
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();
1842 if (bIsEMF)
1844 SetDevByWin();
1846 mbIsMapWinSet=true;
1849 void WinMtfOutput::SetWinOrgOffset( sal_Int32 nXAdd, sal_Int32 nYAdd )
1851 mnWinOrgX += nXAdd;
1852 mnWinOrgY += nYAdd;
1855 void WinMtfOutput::SetDevByWin() //mnWinExt...-stuff has to be assigned before.
1857 if (!mbIsMapDevSet)
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())
1873 switch( mnMapMode )
1875 case MM_ISOTROPIC :
1876 case MM_ANISOTROPIC :
1878 mnWinExtX = rSize.Width();
1879 mnWinExtY = rSize.Height();
1880 if (bIsEMF)
1882 SetDevByWin();
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 )
1898 mrclBounds = rRect;
1901 void WinMtfOutput::SetrclFrame( const Rectangle& rRect )
1903 mrclFrame = 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 )
1945 switch( nMode )
1947 case MWT_IDENTITY :
1949 maXForm.eM11 = maXForm.eM22 = 1.0f;
1950 maXForm.eM12 = maXForm.eM21 = maXForm.eDx = maXForm.eDy = 0.0f;
1951 break;
1954 case MWT_RIGHTMULTIPLY :
1955 case MWT_LEFTMULTIPLY :
1957 const XForm* pLeft;
1958 const XForm* pRight;
1960 if ( nMode == MWT_LEFTMULTIPLY )
1962 pLeft = &rXForm;
1963 pRight = &maXForm;
1965 else
1967 pLeft = &maXForm;
1968 pRight = &rXForm;
1971 float aF[3][3];
1972 float bF[3][3];
1973 float cF[3][3];
1975 aF[0][0] = pLeft->eM11;
1976 aF[0][1] = pLeft->eM12;
1977 aF[0][2] = 0;
1978 aF[1][0] = pLeft->eM21;
1979 aF[1][1] = pLeft->eM22;
1980 aF[1][2] = 0;
1981 aF[2][0] = pLeft->eDx;
1982 aF[2][1] = pLeft->eDy;
1983 aF[2][2] = 1;
1985 bF[0][0] = pRight->eM11;
1986 bF[0][1] = pRight->eM12;
1987 bF[0][2] = 0;
1988 bF[1][0] = pRight->eM21;
1989 bF[1][1] = pRight->eM22;
1990 bF[1][2] = 0;
1991 bF[2][0] = pRight->eDx;
1992 bF[2][1] = pRight->eDy;
1993 bF[2][2] = 1;
1995 int i, j, k;
1996 for ( i = 0; i < 3; i++ )
1998 for ( j = 0; j < 3; j++ )
2000 cF[i][j] = 0;
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];
2011 break;
2013 case MWT_SET:
2015 SetWorldTransform(rXForm);
2016 break;
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"));
2113 SvMemoryStream mem;
2114 sal_Int32 nLeft, nRight, nTop, nBottom;
2116 nLeft = mrclFrame.Left();
2117 nTop = mrclFrame.Top();
2118 nRight = mrclFrame.Right();
2119 nBottom = mrclFrame.Bottom();
2121 // emf header info
2122 mem.WriteInt32( nLeft ).WriteInt32( nTop ).WriteInt32( nRight ).WriteInt32( nBottom );
2123 mem.WriteInt32( mnPixX ).WriteInt32( mnPixY ).WriteInt32( mnMillX ).WriteInt32( mnMillY );
2125 float one, zero;
2127 one = 1;
2128 zero = 0;
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
2136 mem.Flush();
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: */