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