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