Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / emfio / source / reader / mtftools.cxx
blob89ca286a950183b875973ad5a05b99cbbc5301f0
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/graphictools.hxx>
27 #include <vcl/BitmapTools.hxx>
28 #include <vcl/metaact.hxx>
29 #include <vcl/canvastools.hxx>
30 #include <vcl/svapp.hxx>
31 #include <tools/fract.hxx>
32 #include <rtl/strbuf.hxx>
33 #include <rtl/tencinfo.h>
34 #include <vcl/virdev.hxx>
35 #include <o3tl/make_unique.hxx>
36 #include <o3tl/safeint.hxx>
37 #include <officecfg/Setup.hxx>
38 #include <officecfg/Office/Linguistic.hxx>
39 #include <unotools/configmgr.hxx>
40 #include <unotools/wincodepage.hxx>
41 #include <tools/helpers.hxx>
42 #include <vcl/bitmapaccess.hxx>
44 #if OSL_DEBUG_LEVEL > 1
45 #define EMFP_DEBUG(x) x
46 #else
47 #define EMFP_DEBUG(x)
48 #endif
50 namespace emfio
52 SvStream& operator >> (SvStream& rInStream, XForm& rXForm)
54 if (sizeof(float) != 4)
56 OSL_FAIL("EmfReader::sizeof( float ) != 4");
57 rXForm = XForm();
59 else
61 rInStream.ReadFloat(rXForm.eM11);
62 rInStream.ReadFloat(rXForm.eM12);
63 rInStream.ReadFloat(rXForm.eM21);
64 rInStream.ReadFloat(rXForm.eM22);
65 rInStream.ReadFloat(rXForm.eDx);
66 rInStream.ReadFloat(rXForm.eDy);
68 return rInStream;
71 void WinMtfClipPath::intersectClipRect( const tools::Rectangle& rRect )
73 maClip.intersectRange(
74 vcl::unotools::b2DRectangleFromRectangle(rRect));
77 void WinMtfClipPath::excludeClipRect( const tools::Rectangle& rRect )
79 maClip.subtractRange(
80 vcl::unotools::b2DRectangleFromRectangle(rRect));
83 void WinMtfClipPath::setClipPath( const tools::PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode )
85 const basegfx::B2DPolyPolygon& rB2DPoly=rPolyPolygon.getB2DPolyPolygon();
86 switch ( nClippingMode )
88 case RGN_OR :
89 maClip.unionPolyPolygon(rB2DPoly);
90 break;
91 case RGN_XOR :
92 maClip.xorPolyPolygon(rB2DPoly);
93 break;
94 case RGN_DIFF :
95 maClip.subtractPolyPolygon(rB2DPoly);
96 break;
97 case RGN_AND :
98 maClip.intersectPolyPolygon(rB2DPoly);
99 break;
100 case RGN_COPY :
101 maClip = basegfx::utils::B2DClipState(rB2DPoly);
102 break;
106 void WinMtfClipPath::moveClipRegion( const Size& rSize )
108 basegfx::B2DHomMatrix aTranslate;
109 aTranslate.translate(rSize.Width(), rSize.Height());
110 maClip.transform(aTranslate);
113 void WinMtfClipPath::setDefaultClipPath()
115 // Empty clip region - everything visible
116 maClip = basegfx::utils::B2DClipState();
119 basegfx::B2DPolyPolygon const & WinMtfClipPath::getClipPath() const
121 return maClip.getClipPoly();
124 void WinMtfPathObj::AddPoint( const Point& rPoint )
126 if ( bClosed )
127 Insert( tools::Polygon() );
128 tools::Polygon& rPoly = static_cast<tools::PolyPolygon&>(*this)[ Count() - 1 ];
129 rPoly.Insert( rPoly.GetSize(), rPoint );
130 bClosed = false;
133 void WinMtfPathObj::AddPolyLine( const tools::Polygon& rPolyLine )
135 if ( bClosed )
136 Insert( tools::Polygon() );
137 tools::Polygon& rPoly = static_cast<tools::PolyPolygon&>(*this)[ Count() - 1 ];
138 rPoly.Insert( rPoly.GetSize(), rPolyLine );
139 bClosed = false;
142 void WinMtfPathObj::AddPolygon( const tools::Polygon& rPoly )
144 Insert( rPoly );
145 bClosed = true;
148 void WinMtfPathObj::AddPolyPolygon( const tools::PolyPolygon& rPolyPoly )
150 sal_uInt16 i, nCount = rPolyPoly.Count();
151 for ( i = 0; i < nCount; i++ )
152 Insert( rPolyPoly[ i ] );
153 bClosed = true;
156 void WinMtfPathObj::ClosePath()
158 if ( Count() )
160 tools::Polygon& rPoly = static_cast<tools::PolyPolygon&>(*this)[ Count() - 1 ];
161 if ( rPoly.GetSize() > 2 )
163 Point aFirst( rPoly[ 0 ] );
164 if ( aFirst != rPoly[ rPoly.GetSize() - 1 ] )
165 rPoly.Insert( rPoly.GetSize(), aFirst );
168 bClosed = true;
171 namespace {
173 OUString getLODefaultLanguage()
175 if (utl::ConfigManager::IsFuzzing())
176 return OUString("en-US");
177 OUString result(officecfg::Office::Linguistic::General::DefaultLocale::get());
178 if (result.isEmpty())
179 result = officecfg::Setup::L10N::ooSetupSystemLocale::get();
180 return result;
185 WinMtfFontStyle::WinMtfFontStyle( LOGFONTW const & rFont )
187 rtl_TextEncoding eCharSet;
188 if ((rFont.alfFaceName == "Symbol")
189 || (rFont.alfFaceName == "MT Extra"))
190 eCharSet = RTL_TEXTENCODING_SYMBOL;
191 else if ((rFont.lfCharSet == DEFAULT_CHARSET) || (rFont.lfCharSet == OEM_CHARSET))
192 eCharSet = utl_getWinTextEncodingFromLangStr(getLODefaultLanguage().toUtf8().getStr(),
193 rFont.lfCharSet == OEM_CHARSET);
194 else
195 eCharSet = rtl_getTextEncodingFromWindowsCharset( rFont.lfCharSet );
196 if ( eCharSet == RTL_TEXTENCODING_DONTKNOW )
197 eCharSet = RTL_TEXTENCODING_MS_1252;
198 aFont.SetCharSet( eCharSet );
199 aFont.SetFamilyName( rFont.alfFaceName );
200 FontFamily eFamily;
201 switch ( rFont.lfPitchAndFamily & 0xf0 )
203 case FF_ROMAN:
204 eFamily = FAMILY_ROMAN;
205 break;
207 case FF_SWISS:
208 eFamily = FAMILY_SWISS;
209 break;
211 case FF_MODERN:
212 eFamily = FAMILY_MODERN;
213 break;
215 case FF_SCRIPT:
216 eFamily = FAMILY_SCRIPT;
217 break;
219 case FF_DECORATIVE:
220 eFamily = FAMILY_DECORATIVE;
221 break;
223 default:
224 eFamily = FAMILY_DONTKNOW;
225 break;
227 aFont.SetFamily( eFamily );
229 FontPitch ePitch;
230 switch ( rFont.lfPitchAndFamily & 0x0f )
232 case FIXED_PITCH:
233 ePitch = PITCH_FIXED;
234 break;
236 case DEFAULT_PITCH:
237 case VARIABLE_PITCH:
238 default:
239 ePitch = PITCH_VARIABLE;
240 break;
242 aFont.SetPitch( ePitch );
244 FontWeight eWeight;
245 if (rFont.lfWeight == 0) // default weight SHOULD be used
246 eWeight = WEIGHT_DONTKNOW;
247 else if (rFont.lfWeight <= FW_THIN)
248 eWeight = WEIGHT_THIN;
249 else if( rFont.lfWeight <= FW_ULTRALIGHT )
250 eWeight = WEIGHT_ULTRALIGHT;
251 else if( rFont.lfWeight <= FW_LIGHT )
252 eWeight = WEIGHT_LIGHT;
253 else if( rFont.lfWeight < FW_MEDIUM )
254 eWeight = WEIGHT_NORMAL;
255 else if( rFont.lfWeight == FW_MEDIUM )
256 eWeight = WEIGHT_MEDIUM;
257 else if( rFont.lfWeight <= FW_SEMIBOLD )
258 eWeight = WEIGHT_SEMIBOLD;
259 else if( rFont.lfWeight <= FW_BOLD )
260 eWeight = WEIGHT_BOLD;
261 else if( rFont.lfWeight <= FW_ULTRABOLD )
262 eWeight = WEIGHT_ULTRABOLD;
263 else
264 eWeight = WEIGHT_BLACK;
265 aFont.SetWeight( eWeight );
267 if( rFont.lfItalic )
268 aFont.SetItalic( ITALIC_NORMAL );
270 if( rFont.lfUnderline )
271 aFont.SetUnderline( LINESTYLE_SINGLE );
273 if( rFont.lfStrikeOut )
274 aFont.SetStrikeout( STRIKEOUT_SINGLE );
276 aFont.SetOrientation( static_cast<short>(rFont.lfEscapement) );
278 Size aFontSize( Size( rFont.lfWidth, rFont.lfHeight ) );
279 if ( rFont.lfHeight > 0 )
281 // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
282 SolarMutexGuard aGuard;
283 ScopedVclPtrInstance< VirtualDevice > pVDev;
284 // converting the cell height into a font height
285 aFont.SetFontSize( aFontSize );
286 pVDev->SetFont( aFont );
287 FontMetric aMetric( pVDev->GetFontMetric() );
288 long nHeight = aMetric.GetAscent() + aMetric.GetDescent();
289 if (nHeight)
291 double fHeight = (static_cast<double>(aFontSize.Height()) * rFont.lfHeight ) / nHeight;
292 aFontSize.setHeight( static_cast<sal_Int32>( fHeight + 0.5 ) );
296 // Convert height to positive
297 aFontSize.setHeight( std::abs(aFontSize.Height()) );
299 aFont.SetFontSize(aFontSize);
302 Color MtfTools::ReadColor()
304 sal_uInt32 nColor;
306 mpInputStream->ReadUInt32( nColor );
307 return Color( static_cast<sal_uInt8>(nColor), static_cast<sal_uInt8>( nColor >> 8 ), static_cast<sal_uInt8>( nColor >> 16 ) );
310 Point MtfTools::ImplScale(const Point& rPoint) // Hack to set varying defaults for incompletely defined files.
312 if (!mbIsMapDevSet)
313 return Point(rPoint.X() * UNDOCUMENTED_WIN_RCL_RELATION - mrclFrame.Left(),
314 rPoint.Y() * UNDOCUMENTED_WIN_RCL_RELATION - mrclFrame.Top());
315 else
316 return rPoint;
319 Point MtfTools::ImplMap( const Point& rPt )
321 if ( mnWinExtX && mnWinExtY )
323 double fX = rPt.X();
324 double fY = rPt.Y();
326 double fX2 = fX * maXForm.eM11 + fY * maXForm.eM21 + maXForm.eDx;
327 double fY2 = fX * maXForm.eM12 + fY * maXForm.eM22 + maXForm.eDy;
329 if ( mnGfxMode == GM_COMPATIBLE )
331 switch( mnMapMode )
333 case MM_LOENGLISH :
335 fX2 -= mnWinOrgX;
336 fY2 = mnWinOrgY-fY2;
337 fX2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH*10;
338 fY2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH*10;
339 fX2 += mnDevOrgX;
340 fY2 += mnDevOrgY;
342 break;
343 case MM_HIENGLISH :
345 fX2 -= mnWinOrgX;
346 fY2 = mnWinOrgY-fY2;
347 fX2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH;
348 fY2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH;
349 fX2 += mnDevOrgX;
350 fY2 += mnDevOrgY;
352 break;
353 case MM_TWIPS:
355 fX2 -= mnWinOrgX;
356 fY2 = mnWinOrgY-fY2;
357 fX2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH/MILLIINCH_PER_TWIPS;
358 fY2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH/MILLIINCH_PER_TWIPS;
359 fX2 += mnDevOrgX;
360 fY2 += mnDevOrgY;
362 break;
363 case MM_LOMETRIC :
365 fX2 -= mnWinOrgX;
366 fY2 = mnWinOrgY-fY2;
367 fX2 *= 10;
368 fY2 *= 10;
369 fX2 += mnDevOrgX;
370 fY2 += mnDevOrgY;
372 break;
373 case MM_HIMETRIC : // in hundredth of a millimeter
375 fX2 -= mnWinOrgX;
376 fY2 = mnWinOrgY-fY2;
377 fX2 += mnDevOrgX;
378 fY2 += mnDevOrgY;
380 break;
381 default :
383 if (mnPixX == 0 || mnPixY == 0)
385 SAL_WARN("emfio", "invalid scaling factor");
386 return Point();
388 else
390 fX2 -= mnWinOrgX;
391 fY2 -= mnWinOrgY;
392 fX2 /= mnWinExtX;
393 fY2 /= mnWinExtY;
394 fX2 *= mnDevWidth;
395 fY2 *= mnDevHeight;
396 fX2 += mnDevOrgX;
397 fY2 += mnDevOrgY; // fX2, fY2 now in device units
398 fX2 *= static_cast<double>(mnMillX) * 100.0 / static_cast<double>(mnPixX);
399 fY2 *= static_cast<double>(mnMillY) * 100.0 / static_cast<double>(mnPixY);
402 break;
404 fX2 -= mrclFrame.Left();
405 fY2 -= mrclFrame.Top();
407 return Point(basegfx::fround(fX2), basegfx::fround(fY2));
409 else
410 return Point();
413 Size MtfTools::ImplMap(const Size& rSz, bool bDoWorldTransform)
415 if ( mnWinExtX && mnWinExtY )
417 // #i121382# apply the whole WorldTransform, else a rotation will be misinterpreted
418 double fWidth, fHeight;
419 if (bDoWorldTransform)
421 fWidth = rSz.Width() * maXForm.eM11 + rSz.Height() * maXForm.eM21;
422 fHeight = rSz.Width() * maXForm.eM12 + rSz.Height() * maXForm.eM22;
424 else
426 //take the scale, but not the rotation
427 basegfx::B2DHomMatrix aMatrix(maXForm.eM11, maXForm.eM12, 0,
428 maXForm.eM21, maXForm.eM22, 0);
429 basegfx::B2DTuple aScale, aTranslate;
430 double fRotate, fShearX;
431 if (!aMatrix.decompose(aScale, aTranslate, fRotate, fShearX))
433 aScale.setX(1.0);
434 aScale.setY(1.0);
436 fWidth = rSz.Width() * aScale.getX();
437 fHeight = rSz.Height() * aScale.getY();
440 if ( mnGfxMode == GM_COMPATIBLE )
442 switch( mnMapMode )
444 case MM_LOENGLISH :
446 fWidth *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH*10;
447 fHeight*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH*10;
449 break;
450 case MM_HIENGLISH :
452 fWidth *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH;
453 fHeight*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH;
455 break;
456 case MM_LOMETRIC :
458 fWidth *= 10;
459 fHeight*=-10;
461 break;
462 case MM_HIMETRIC : // in hundredth of millimeters
464 fHeight *= -1;
466 break;
467 case MM_TWIPS:
469 fWidth *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH/MILLIINCH_PER_TWIPS;
470 fHeight*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH/MILLIINCH_PER_TWIPS;
472 break;
473 default :
475 if (mnPixX == 0 || mnPixY == 0)
477 SAL_WARN("emfio", "invalid scaling factor");
478 return Size();
480 else
482 fWidth /= mnWinExtX;
483 fHeight /= mnWinExtY;
484 fWidth *= mnDevWidth;
485 fHeight *= mnDevHeight;
486 fWidth *= static_cast<double>(mnMillX) * 100.0 / static_cast<double>(mnPixX);
487 fHeight *= static_cast<double>(mnMillY) * 100.0 / static_cast<double>(mnPixY);
490 break;
493 return Size(basegfx::fround(fWidth), basegfx::fround(fHeight));
495 else
496 return Size();
499 tools::Rectangle MtfTools::ImplMap( const tools::Rectangle& rRect )
501 tools::Rectangle aRect;
502 aRect.SetPos(ImplMap(rRect.TopLeft()));
503 aRect.SaturatingSetSize(ImplMap(rRect.GetSize()));
504 return aRect;
507 void MtfTools::ImplMap( vcl::Font& rFont )
509 // !!! HACK: we now always set the width to zero because the OS width is interpreted differently;
510 // must later be made portable in SV (KA 1996-02-08)
511 Size aFontSize = ImplMap (rFont.GetFontSize(), false);
513 const auto nHeight = aFontSize.Height();
514 if (nHeight < 0)
515 aFontSize.setHeight( o3tl::saturating_toggle_sign(nHeight) );
517 rFont.SetFontSize( aFontSize );
519 sal_Int32 nResult;
520 const bool bFail = o3tl::checked_multiply(mnWinExtX, mnWinExtY, nResult);
521 if (!bFail && nResult < 0)
522 rFont.SetOrientation( 3600 - rFont.GetOrientation() );
525 tools::Polygon& MtfTools::ImplMap( tools::Polygon& rPolygon )
527 sal_uInt16 nPoints = rPolygon.GetSize();
528 for ( sal_uInt16 i = 0; i < nPoints; i++ )
530 rPolygon[ i ] = ImplMap( rPolygon[ i ] );
532 return rPolygon;
535 void MtfTools::ImplScale( tools::Polygon& rPolygon )
537 sal_uInt16 nPoints = rPolygon.GetSize();
538 for ( sal_uInt16 i = 0; i < nPoints; i++ )
540 rPolygon[ i ] = ImplScale( rPolygon[ i ] );
544 tools::PolyPolygon& MtfTools::ImplScale( tools::PolyPolygon& rPolyPolygon )
546 sal_uInt16 nPolys = rPolyPolygon.Count();
547 for (sal_uInt16 i = 0; i < nPolys; ++i)
549 ImplScale(rPolyPolygon[i]);
551 return rPolyPolygon;
554 tools::PolyPolygon& MtfTools::ImplMap( tools::PolyPolygon& rPolyPolygon )
556 sal_uInt16 nPolys = rPolyPolygon.Count();
557 for ( sal_uInt16 i = 0; i < nPolys; ImplMap( rPolyPolygon[ i++ ] ) ) ;
558 return rPolyPolygon;
561 void MtfTools::SelectObject( sal_Int32 nIndex )
563 if ( nIndex & ENHMETA_STOCK_OBJECT )
565 sal_uInt16 nStockId = static_cast<sal_uInt8>(nIndex);
566 switch( nStockId )
568 case WHITE_BRUSH :
570 maFillStyle = WinMtfFillStyle( COL_WHITE );
571 mbFillStyleSelected = true;
573 break;
574 case LTGRAY_BRUSH :
576 maFillStyle = WinMtfFillStyle( COL_LIGHTGRAY );
577 mbFillStyleSelected = true;
579 break;
580 case GRAY_BRUSH :
581 case DKGRAY_BRUSH :
583 maFillStyle = WinMtfFillStyle( COL_GRAY );
584 mbFillStyleSelected = true;
586 break;
587 case BLACK_BRUSH :
589 maFillStyle = WinMtfFillStyle( COL_BLACK );
590 mbFillStyleSelected = true;
592 break;
593 case NULL_BRUSH :
595 maFillStyle = WinMtfFillStyle( COL_TRANSPARENT, true );
596 mbFillStyleSelected = true;
598 break;
599 case WHITE_PEN :
601 maLineStyle = WinMtfLineStyle( COL_WHITE );
603 break;
604 case BLACK_PEN :
606 maLineStyle = WinMtfLineStyle( COL_BLACK );
608 break;
609 case NULL_PEN :
611 maLineStyle = WinMtfLineStyle( COL_TRANSPARENT, true );
613 break;
614 default:
615 break;
618 else
620 nIndex &= 0xffff; // safety check: don't allow index to be > 65535
622 GDIObj *pGDIObj = nullptr;
624 if ( static_cast<sal_uInt32>(nIndex) < mvGDIObj.size() )
625 pGDIObj = mvGDIObj[ nIndex ].get();
627 if ( pGDIObj )
629 if (const auto pen = dynamic_cast<WinMtfLineStyle*>(pGDIObj))
630 maLineStyle = *pen;
631 else if (const auto brush = dynamic_cast<WinMtfFillStyle*>(
632 pGDIObj))
634 maFillStyle = *brush;
635 mbFillStyleSelected = true;
637 else if (const auto font = dynamic_cast<WinMtfFontStyle*>(
638 pGDIObj))
640 maFont = font->aFont;
646 void MtfTools::SetTextLayoutMode( ComplexTextLayoutFlags nTextLayoutMode )
648 mnTextLayoutMode = nTextLayoutMode;
651 void MtfTools::SetBkMode( BkMode nMode )
653 mnBkMode = nMode;
656 void MtfTools::SetBkColor( const Color& rColor )
658 maBkColor = rColor;
661 void MtfTools::SetTextColor( const Color& rColor )
663 maTextColor = rColor;
666 void MtfTools::SetTextAlign( sal_uInt32 nAlign )
668 mnTextAlign = nAlign;
671 void MtfTools::ImplResizeObjectArry( sal_uInt32 nNewEntrys )
673 mvGDIObj.resize(nNewEntrys);
676 void MtfTools::ImplDrawClippedPolyPolygon( const tools::PolyPolygon& rPolyPoly )
678 if ( rPolyPoly.Count() )
680 ImplSetNonPersistentLineColorTransparenz();
681 if ( rPolyPoly.Count() == 1 )
683 if ( rPolyPoly.IsRect() )
684 mpGDIMetaFile->AddAction( new MetaRectAction( rPolyPoly.GetBoundRect() ) );
685 else
687 tools::Polygon aPoly( rPolyPoly[ 0 ] );
688 sal_uInt16 nCount = aPoly.GetSize();
689 if ( nCount )
691 if ( aPoly[ nCount - 1 ] != aPoly[ 0 ] )
693 Point aPoint( aPoly[ 0 ] );
694 aPoly.Insert( nCount, aPoint );
696 mpGDIMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
700 else
701 mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPoly ) );
705 void MtfTools::CreateObject( std::unique_ptr<GDIObj> pObject )
707 if ( pObject )
709 const auto pLineStyle = dynamic_cast<WinMtfLineStyle*>(pObject.get());
710 const auto pFontStyle = dynamic_cast<WinMtfFontStyle*>(pObject.get());
712 if ( pFontStyle )
714 if (pFontStyle->aFont.GetFontHeight() == 0)
715 pFontStyle->aFont.SetFontHeight(423);
716 ImplMap(pFontStyle->aFont); // defaulting to 12pt
718 else if ( pLineStyle )
720 Size aSize(pLineStyle->aLineInfo.GetWidth(), 0);
721 aSize = ImplMap(aSize);
722 pLineStyle->aLineInfo.SetWidth(aSize.Width());
725 std::vector<std::unique_ptr<GDIObj>>::size_type nIndex;
726 for ( nIndex = 0; nIndex < mvGDIObj.size(); nIndex++ )
728 if ( !mvGDIObj[ nIndex ] )
729 break;
731 if ( nIndex == mvGDIObj.size() )
732 ImplResizeObjectArry( mvGDIObj.size() + 16 );
734 mvGDIObj[ nIndex ] = std::move(pObject);
737 void MtfTools::CreateObjectIndexed( sal_Int32 nIndex, std::unique_ptr<GDIObj> pObject )
739 if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 )
741 nIndex &= 0xffff; // safety check: do not allow index to be > 65535
742 if ( pObject )
744 const auto pLineStyle = dynamic_cast<WinMtfLineStyle*>(pObject.get());
745 const auto pFontStyle = dynamic_cast<WinMtfFontStyle*>(pObject.get());
746 if ( pFontStyle )
748 if (pFontStyle->aFont.GetFontHeight() == 0)
749 pFontStyle->aFont.SetFontHeight(423);
750 ImplMap(pFontStyle->aFont);
752 else if ( pLineStyle )
754 Size aSize(pLineStyle->aLineInfo.GetWidth(), 0);
755 pLineStyle->aLineInfo.SetWidth( ImplMap(aSize).Width() );
757 if ( pLineStyle->aLineInfo.GetStyle() == LineStyle::Dash )
759 aSize.AdjustWidth(1 );
760 long nDotLen = ImplMap( aSize ).Width();
761 pLineStyle->aLineInfo.SetDistance( nDotLen );
762 pLineStyle->aLineInfo.SetDotLen( nDotLen );
763 pLineStyle->aLineInfo.SetDashLen( nDotLen * 3 );
767 if ( static_cast<sal_uInt32>(nIndex) >= mvGDIObj.size() )
768 ImplResizeObjectArry( nIndex + 16 );
770 mvGDIObj[ nIndex ] = std::move(pObject);
774 void MtfTools::CreateObject()
776 CreateObject(o3tl::make_unique<GDIObj>());
779 void MtfTools::DeleteObject( sal_Int32 nIndex )
781 if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 )
783 if ( static_cast<sal_uInt32>(nIndex) < mvGDIObj.size() )
785 mvGDIObj[ nIndex ].reset();
790 void MtfTools::IntersectClipRect( const tools::Rectangle& rRect )
792 if (utl::ConfigManager::IsFuzzing())
793 return;
794 mbClipNeedsUpdate=true;
795 if ((rRect.Left()-rRect.Right()==0) && (rRect.Top()-rRect.Bottom()==0))
797 return; // empty rectangles cause trouble
799 maClipPath.intersectClipRect( ImplMap( rRect ) );
802 void MtfTools::ExcludeClipRect( const tools::Rectangle& rRect )
804 if (utl::ConfigManager::IsFuzzing())
805 return;
806 mbClipNeedsUpdate=true;
807 maClipPath.excludeClipRect( ImplMap( rRect ) );
810 void MtfTools::MoveClipRegion( const Size& rSize )
812 if (utl::ConfigManager::IsFuzzing())
813 return;
814 mbClipNeedsUpdate=true;
815 maClipPath.moveClipRegion( ImplMap( rSize ) );
818 void MtfTools::SetClipPath( const tools::PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode, bool bIsMapped )
820 if (utl::ConfigManager::IsFuzzing())
821 return;
822 mbClipNeedsUpdate = true;
823 tools::PolyPolygon aPolyPolygon(rPolyPolygon);
825 if (!bIsMapped)
827 if (!mbIsMapDevSet && (mnMapMode == MM_ISOTROPIC || mnMapMode == MM_ANISOTROPIC))
828 aPolyPolygon = ImplScale(aPolyPolygon);
829 else
830 aPolyPolygon = ImplMap(aPolyPolygon);
832 maClipPath.setClipPath(aPolyPolygon, nClippingMode);
835 void MtfTools::SetDefaultClipPath()
837 mbClipNeedsUpdate = true;
838 maClipPath.setDefaultClipPath();
841 MtfTools::MtfTools( GDIMetaFile& rGDIMetaFile, SvStream& rStreamWMF)
842 : maPathObj(),
843 maClipPath(),
844 maLatestLineStyle(),
845 maLineStyle(),
846 maNopLineStyle(),
847 maLatestFillStyle(),
848 maFillStyle(),
849 maNopFillStyle(),
850 maLatestFont(),
851 maFont(),
852 mnLatestTextAlign(90),
853 mnTextAlign(TA_LEFT | TA_TOP | TA_NOUPDATECP),
854 maLatestTextColor(),
855 maTextColor(),
856 maLatestBkColor(0x12345678),
857 maBkColor(COL_WHITE),
858 mnLatestTextLayoutMode(ComplexTextLayoutFlags::Default),
859 mnTextLayoutMode(ComplexTextLayoutFlags::Default),
860 mnLatestBkMode(BkMode::NONE),
861 mnBkMode(BkMode::OPAQUE),
862 meLatestRasterOp(RasterOp::Invert),
863 meRasterOp(RasterOp::OverPaint),
864 mvGDIObj(),
865 maActPos(),
866 mnRop(),
867 mvSaveStack(),
868 mnGfxMode(GM_COMPATIBLE),
869 mnMapMode(MM_TEXT),
870 maXForm(),
871 mnDevOrgX(0),
872 mnDevOrgY(0),
873 mnDevWidth(1),
874 mnDevHeight(1),
875 mnWinOrgX(0),
876 mnWinOrgY(0),
877 mnWinExtX(1),
878 mnWinExtY(1),
879 mnPixX(100),
880 mnPixY(100),
881 mnMillX(1),
882 mnMillY(1),
883 mrclFrame(),
884 mrclBounds(),
885 mpGDIMetaFile(&rGDIMetaFile),
886 mpInputStream(&rStreamWMF),
887 mnStartPos(0),
888 mnEndPos(0),
889 maBmpSaveList(),
890 mbNopMode(false),
891 mbFillStyleSelected(false),
892 mbClipNeedsUpdate(true),
893 mbComplexClip(false),
894 mbIsMapWinSet(false),
895 mbIsMapDevSet(false)
897 SvLockBytes *pLB = mpInputStream->GetLockBytes();
899 if (pLB)
901 pLB->SetSynchronMode();
904 mnStartPos = mpInputStream->Tell();
905 SetDevOrg(Point());
907 mpGDIMetaFile->AddAction( new MetaPushAction( PushFlags::CLIPREGION ) ); // The original clipregion has to be on top
908 // of the stack so it can always be restored
909 // this is necessary to be able to support
910 // SetClipRgn( NULL ) and similar ClipRgn actions (SJ)
912 maFont.SetFamilyName( "Arial" ); // sj: #i57205#, we do have some scaling problems if using
913 maFont.SetCharSet( RTL_TEXTENCODING_MS_1252 ); // the default font then most times a x11 font is used, we
914 maFont.SetFontHeight( 423 ); // will prevent this defining a font
916 maLatestLineStyle.aLineColor = Color( 0x12, 0x34, 0x56 );
917 maLatestFillStyle.aFillColor = Color( 0x12, 0x34, 0x56 );
919 mnRop = WMFRasterOp::Black;
920 meRasterOp = RasterOp::OverPaint;
921 mpGDIMetaFile->AddAction( new MetaRasterOpAction( RasterOp::OverPaint ) );
924 MtfTools::~MtfTools() COVERITY_NOEXCEPT_FALSE
926 mpGDIMetaFile->AddAction( new MetaPopAction() );
927 mpGDIMetaFile->SetPrefMapMode(MapMode(MapUnit::Map100thMM));
928 if ( mrclFrame.IsEmpty() )
929 mpGDIMetaFile->SetPrefSize( Size( mnDevWidth, mnDevHeight ) );
930 else
931 mpGDIMetaFile->SetPrefSize( mrclFrame.GetSize() );
934 void MtfTools::UpdateClipRegion()
936 if (mbClipNeedsUpdate)
938 mbClipNeedsUpdate = false;
939 mbComplexClip = false;
941 mpGDIMetaFile->AddAction( new MetaPopAction() ); // taking the original clipregion
942 mpGDIMetaFile->AddAction( new MetaPushAction( PushFlags::CLIPREGION ) );
944 // skip for 'no clipping at all' case
945 if( !maClipPath.isEmpty() )
947 const basegfx::B2DPolyPolygon& rClipPoly( maClipPath.getClipPath() );
949 mbComplexClip = rClipPoly.count() > 1
950 || !basegfx::utils::isRectangle(rClipPoly);
952 static bool bEnableComplexClipViaRegion = getenv("SAL_WMF_COMPLEXCLIP_VIA_REGION") != nullptr;
954 if (bEnableComplexClipViaRegion)
956 //this makes cases like tdf#45820 work in reasonable time, and I feel in theory should
957 //be just fine. In practice I see the output is different so needs work before its the
958 //default, but for file fuzzing it should be good enough
959 if (mbComplexClip)
961 mpGDIMetaFile->AddAction(
962 new MetaISectRegionClipRegionAction(
963 vcl::Region(rClipPoly)));
964 mbComplexClip = false;
966 else
968 mpGDIMetaFile->AddAction(
969 new MetaISectRectClipRegionAction(
970 vcl::unotools::rectangleFromB2DRectangle(
971 rClipPoly.getB2DRange())));
974 else
976 //normal case
977 mpGDIMetaFile->AddAction(
978 new MetaISectRectClipRegionAction(
979 vcl::unotools::rectangleFromB2DRectangle(
980 rClipPoly.getB2DRange())));
986 void MtfTools::ImplSetNonPersistentLineColorTransparenz()
988 WinMtfLineStyle aTransparentLine( COL_TRANSPARENT, true );
989 if ( ! ( maLatestLineStyle == aTransparentLine ) )
991 maLatestLineStyle = aTransparentLine;
992 mpGDIMetaFile->AddAction( new MetaLineColorAction( aTransparentLine.aLineColor, !aTransparentLine.bTransparent ) );
996 void MtfTools::UpdateLineStyle()
998 if (!( maLatestLineStyle == maLineStyle ) )
1000 maLatestLineStyle = maLineStyle;
1001 mpGDIMetaFile->AddAction( new MetaLineColorAction( maLineStyle.aLineColor, !maLineStyle.bTransparent ) );
1005 void MtfTools::UpdateFillStyle()
1007 if ( !mbFillStyleSelected ) // SJ: #i57205# taking care of bkcolor if no brush is selected
1008 maFillStyle = WinMtfFillStyle( maBkColor, mnBkMode == BkMode::Transparent );
1009 if (!( maLatestFillStyle == maFillStyle ) )
1011 maLatestFillStyle = maFillStyle;
1012 if (maFillStyle.aType == WinMtfFillStyleType::Solid)
1013 mpGDIMetaFile->AddAction( new MetaFillColorAction( maFillStyle.aFillColor, !maFillStyle.bTransparent ) );
1017 WMFRasterOp MtfTools::SetRasterOp( WMFRasterOp nRasterOp )
1019 WMFRasterOp nRetROP = mnRop;
1020 if ( nRasterOp != mnRop )
1022 mnRop = nRasterOp;
1024 if ( mbNopMode && ( nRasterOp != WMFRasterOp::Nop ) )
1025 { // changing modes from WMFRasterOp::Nop so set pen and brush
1026 maFillStyle = maNopFillStyle;
1027 maLineStyle = maNopLineStyle;
1028 mbNopMode = false;
1030 switch( nRasterOp )
1032 case WMFRasterOp::Not:
1033 meRasterOp = RasterOp::Invert;
1034 break;
1036 case WMFRasterOp::XorPen:
1037 meRasterOp = RasterOp::Xor;
1038 break;
1040 case WMFRasterOp::Nop:
1042 meRasterOp = RasterOp::OverPaint;
1043 if( !mbNopMode )
1045 maNopFillStyle = maFillStyle;
1046 maNopLineStyle = maLineStyle;
1047 maFillStyle = WinMtfFillStyle( COL_TRANSPARENT, true );
1048 maLineStyle = WinMtfLineStyle( COL_TRANSPARENT, true );
1049 mbNopMode = true;
1052 break;
1054 default:
1055 meRasterOp = RasterOp::OverPaint;
1056 break;
1059 if ( nRetROP != nRasterOp )
1060 mpGDIMetaFile->AddAction( new MetaRasterOpAction( meRasterOp ) );
1061 return nRetROP;
1064 void MtfTools::StrokeAndFillPath( bool bStroke, bool bFill )
1066 if ( maPathObj.Count() )
1068 UpdateClipRegion();
1069 UpdateLineStyle();
1070 UpdateFillStyle();
1071 if ( bFill )
1073 if ( !bStroke )
1075 mpGDIMetaFile->AddAction( new MetaPushAction( PushFlags::LINECOLOR ) );
1076 mpGDIMetaFile->AddAction( new MetaLineColorAction( Color(), false ) );
1078 if ( maPathObj.Count() == 1 )
1079 mpGDIMetaFile->AddAction( new MetaPolygonAction( maPathObj.GetObject( 0 ) ) );
1080 else
1081 mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( maPathObj ) );
1083 if ( !bStroke )
1084 mpGDIMetaFile->AddAction( new MetaPopAction() );
1086 else
1088 sal_uInt16 i, nCount = maPathObj.Count();
1089 for ( i = 0; i < nCount; i++ )
1090 mpGDIMetaFile->AddAction( new MetaPolyLineAction( maPathObj[ i ], maLineStyle.aLineInfo ) );
1092 ClearPath();
1096 void MtfTools::DrawPixel( const Point& rSource, const Color& rColor )
1098 mpGDIMetaFile->AddAction( new MetaPixelAction( ImplMap( rSource), rColor ) );
1101 void MtfTools::MoveTo( const Point& rPoint, bool bRecordPath )
1103 Point aDest( ImplMap( rPoint ) );
1104 if ( bRecordPath )
1106 // fdo#57353 create new subpath for subsequent moves
1107 if ( maPathObj.Count() )
1108 if ( maPathObj[ maPathObj.Count() - 1 ].GetSize() )
1109 maPathObj.Insert( tools::Polygon() );
1110 maPathObj.AddPoint( aDest );
1112 maActPos = aDest;
1115 void MtfTools::LineTo( const Point& rPoint, bool bRecordPath )
1117 UpdateClipRegion();
1118 Point aDest( ImplMap( rPoint ) );
1119 if ( bRecordPath )
1120 maPathObj.AddPoint( aDest );
1121 else
1123 UpdateLineStyle();
1124 mpGDIMetaFile->AddAction( new MetaLineAction( maActPos, aDest, maLineStyle.aLineInfo ) );
1126 maActPos = aDest;
1129 void MtfTools::DrawRect( const tools::Rectangle& rRect, bool bEdge )
1131 UpdateClipRegion();
1132 UpdateFillStyle();
1134 if ( mbComplexClip )
1136 tools::Polygon aPoly( ImplMap( rRect ) );
1137 tools::PolyPolygon aPolyPolyRect( aPoly );
1138 tools::PolyPolygon aDest;
1139 tools::PolyPolygon(maClipPath.getClipPath()).GetIntersection( aPolyPolyRect, aDest );
1140 ImplDrawClippedPolyPolygon( aDest );
1142 else
1144 if ( bEdge )
1146 if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LineStyle::Dash ) )
1148 ImplSetNonPersistentLineColorTransparenz();
1149 mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) );
1150 UpdateLineStyle();
1151 mpGDIMetaFile->AddAction( new MetaPolyLineAction( tools::Polygon( ImplMap( rRect ) ),maLineStyle.aLineInfo ) );
1153 else
1155 UpdateLineStyle();
1156 mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) );
1159 else
1161 ImplSetNonPersistentLineColorTransparenz();
1162 mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) );
1167 void MtfTools::DrawRoundRect( const tools::Rectangle& rRect, const Size& rSize )
1169 UpdateClipRegion();
1170 UpdateLineStyle();
1171 UpdateFillStyle();
1172 mpGDIMetaFile->AddAction( new MetaRoundRectAction( ImplMap( rRect ), labs( ImplMap( rSize ).Width() ), labs( ImplMap( rSize ).Height() ) ) );
1175 void MtfTools::DrawEllipse( const tools::Rectangle& rRect )
1177 UpdateClipRegion();
1178 UpdateFillStyle();
1180 if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LineStyle::Dash ) )
1182 Point aCenter( ImplMap( rRect.Center() ) );
1183 Size aRad( ImplMap( Size( rRect.GetWidth() / 2, rRect.GetHeight() / 2 ) ) );
1185 ImplSetNonPersistentLineColorTransparenz();
1186 mpGDIMetaFile->AddAction( new MetaEllipseAction( ImplMap( rRect ) ) );
1187 UpdateLineStyle();
1188 mpGDIMetaFile->AddAction( new MetaPolyLineAction( tools::Polygon( aCenter, aRad.Width(), aRad.Height() ), maLineStyle.aLineInfo ) );
1190 else
1192 UpdateLineStyle();
1193 mpGDIMetaFile->AddAction( new MetaEllipseAction( ImplMap( rRect ) ) );
1197 void MtfTools::DrawArc( const tools::Rectangle& rRect, const Point& rStart, const Point& rEnd, bool bTo )
1199 UpdateClipRegion();
1200 UpdateLineStyle();
1201 UpdateFillStyle();
1203 tools::Rectangle aRect( ImplMap( rRect ) );
1204 Point aStart( ImplMap( rStart ) );
1205 Point aEnd( ImplMap( rEnd ) );
1207 if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LineStyle::Dash ) )
1209 if ( aStart == aEnd )
1210 { // SJ: #i53768# if start & end is identical, then we have to draw a full ellipse
1211 Point aCenter( aRect.Center() );
1212 Size aRad( aRect.GetWidth() / 2, aRect.GetHeight() / 2 );
1214 mpGDIMetaFile->AddAction( new MetaPolyLineAction( tools::Polygon( aCenter, aRad.Width(), aRad.Height() ), maLineStyle.aLineInfo ) );
1216 else
1217 mpGDIMetaFile->AddAction( new MetaPolyLineAction( tools::Polygon( aRect, aStart, aEnd, PolyStyle::Arc ), maLineStyle.aLineInfo ) );
1219 else
1220 mpGDIMetaFile->AddAction( new MetaArcAction( aRect, aStart, aEnd ) );
1222 if ( bTo )
1223 maActPos = aEnd;
1226 void MtfTools::DrawPie( const tools::Rectangle& rRect, const Point& rStart, const Point& rEnd )
1228 UpdateClipRegion();
1229 UpdateFillStyle();
1231 tools::Rectangle aRect( ImplMap( rRect ) );
1232 Point aStart( ImplMap( rStart ) );
1233 Point aEnd( ImplMap( rEnd ) );
1235 if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LineStyle::Dash ) )
1237 ImplSetNonPersistentLineColorTransparenz();
1238 mpGDIMetaFile->AddAction( new MetaPieAction( aRect, aStart, aEnd ) );
1239 UpdateLineStyle();
1240 mpGDIMetaFile->AddAction( new MetaPolyLineAction( tools::Polygon( aRect, aStart, aEnd, PolyStyle::Pie ), maLineStyle.aLineInfo ) );
1242 else
1244 UpdateLineStyle();
1245 mpGDIMetaFile->AddAction( new MetaPieAction( aRect, aStart, aEnd ) );
1249 void MtfTools::DrawChord( const tools::Rectangle& rRect, const Point& rStart, const Point& rEnd )
1251 UpdateClipRegion();
1252 UpdateFillStyle();
1254 tools::Rectangle aRect( ImplMap( rRect ) );
1255 Point aStart( ImplMap( rStart ) );
1256 Point aEnd( ImplMap( rEnd ) );
1258 if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LineStyle::Dash ) )
1260 ImplSetNonPersistentLineColorTransparenz();
1261 mpGDIMetaFile->AddAction( new MetaChordAction( aRect, aStart, aEnd ) );
1262 UpdateLineStyle();
1263 mpGDIMetaFile->AddAction( new MetaPolyLineAction( tools::Polygon( aRect, aStart, aEnd, PolyStyle::Chord ), maLineStyle.aLineInfo ) );
1265 else
1267 UpdateLineStyle();
1268 mpGDIMetaFile->AddAction( new MetaChordAction( aRect, aStart, aEnd ) );
1272 void MtfTools::DrawPolygon( tools::Polygon rPolygon, bool bRecordPath )
1274 UpdateClipRegion();
1275 ImplMap( rPolygon );
1276 if ( bRecordPath )
1277 maPathObj.AddPolygon( rPolygon );
1278 else
1280 UpdateFillStyle();
1282 if ( mbComplexClip )
1284 tools::PolyPolygon aPolyPoly( rPolygon );
1285 tools::PolyPolygon aDest;
1286 tools::PolyPolygon(maClipPath.getClipPath()).GetIntersection( aPolyPoly, aDest );
1287 ImplDrawClippedPolyPolygon( aDest );
1289 else
1291 if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LineStyle::Dash ) )
1293 sal_uInt16 nCount = rPolygon.GetSize();
1294 if ( nCount )
1296 if ( rPolygon[ nCount - 1 ] != rPolygon[ 0 ] )
1298 Point aPoint( rPolygon[ 0 ] );
1299 rPolygon.Insert( nCount, aPoint );
1302 ImplSetNonPersistentLineColorTransparenz();
1303 mpGDIMetaFile->AddAction( new MetaPolygonAction( rPolygon ) );
1304 UpdateLineStyle();
1305 mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) );
1307 else
1309 UpdateLineStyle();
1311 if (maLatestFillStyle.aType != WinMtfFillStyleType::Pattern)
1312 mpGDIMetaFile->AddAction( new MetaPolygonAction( rPolygon ) );
1313 else {
1314 SvtGraphicFill aFill = SvtGraphicFill( tools::PolyPolygon( rPolygon ),
1315 Color(),
1316 0.0,
1317 SvtGraphicFill::fillNonZero,
1318 SvtGraphicFill::fillTexture,
1319 SvtGraphicFill::Transform(),
1320 true,
1321 SvtGraphicFill::hatchSingle,
1322 Color(),
1323 SvtGraphicFill::GradientType::Linear,
1324 Color(),
1325 Color(),
1327 Graphic (maLatestFillStyle.aBmp) );
1329 SvMemoryStream aMemStm;
1331 WriteSvtGraphicFill( aMemStm, aFill );
1333 mpGDIMetaFile->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_BEGIN", 0,
1334 static_cast<const sal_uInt8*>(aMemStm.GetData()),
1335 aMemStm.Seek( STREAM_SEEK_TO_END ) ) );
1336 mpGDIMetaFile->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_END" ) );
1344 void MtfTools::DrawPolyPolygon( tools::PolyPolygon& rPolyPolygon, bool bRecordPath )
1346 UpdateClipRegion();
1348 ImplMap( rPolyPolygon );
1350 if ( bRecordPath )
1351 maPathObj.AddPolyPolygon( rPolyPolygon );
1352 else
1354 UpdateFillStyle();
1356 if ( mbComplexClip )
1358 tools::PolyPolygon aDest;
1359 tools::PolyPolygon(maClipPath.getClipPath()).GetIntersection( rPolyPolygon, aDest );
1360 ImplDrawClippedPolyPolygon( aDest );
1362 else
1364 UpdateLineStyle();
1365 mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPolygon ) );
1366 if (maLineStyle.aLineInfo.GetWidth() > 0 || maLineStyle.aLineInfo.GetStyle() == LineStyle::Dash)
1368 for (sal_uInt16 nPoly = 0; nPoly < rPolyPolygon.Count(); ++nPoly)
1370 mpGDIMetaFile->AddAction(new MetaPolyLineAction(rPolyPolygon[nPoly], maLineStyle.aLineInfo));
1377 void MtfTools::DrawPolyLine( tools::Polygon rPolygon, bool bTo, bool bRecordPath )
1379 UpdateClipRegion();
1381 sal_uInt16 nPoints = rPolygon.GetSize();
1382 if (nPoints >= 1)
1384 ImplMap( rPolygon );
1385 if ( bTo )
1387 rPolygon[ 0 ] = maActPos;
1388 maActPos = rPolygon[ rPolygon.GetSize() - 1 ];
1390 if ( bRecordPath )
1391 maPathObj.AddPolyLine( rPolygon );
1392 else
1394 UpdateLineStyle();
1395 mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) );
1400 void MtfTools::DrawPolyBezier( tools::Polygon rPolygon, bool bTo, bool bRecordPath )
1402 sal_uInt16 nPoints = rPolygon.GetSize();
1403 if ( ( nPoints >= 4 ) && ( ( ( nPoints - 4 ) % 3 ) == 0 ) )
1405 UpdateClipRegion();
1407 ImplMap( rPolygon );
1408 if ( bTo )
1410 rPolygon[ 0 ] = maActPos;
1411 maActPos = rPolygon[ nPoints - 1 ];
1413 sal_uInt16 i;
1414 for ( i = 0; ( i + 2 ) < nPoints; )
1416 rPolygon.SetFlags( i++, PolyFlags::Normal );
1417 rPolygon.SetFlags( i++, PolyFlags::Control );
1418 rPolygon.SetFlags( i++, PolyFlags::Control );
1420 if ( bRecordPath )
1421 maPathObj.AddPolyLine( rPolygon );
1422 else
1424 UpdateLineStyle();
1425 mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) );
1430 void MtfTools::DrawText( Point& rPosition, OUString const & rText, long* pDXArry, long* pDYArry, bool bRecordPath, sal_Int32 nGfxMode )
1432 UpdateClipRegion();
1433 rPosition = ImplMap( rPosition );
1434 sal_Int32 nOldGfxMode = GetGfxMode();
1435 SetGfxMode( GM_COMPATIBLE );
1437 if (pDXArry)
1439 sal_Int32 nSumX = 0, nSumY = 0;
1440 for (sal_Int32 i = 0; i < rText.getLength(); i++ )
1442 nSumX += pDXArry[i];
1444 // #i121382# Map DXArray using WorldTransform
1445 const Size aSizeX(ImplMap(Size(nSumX, 0)));
1446 const basegfx::B2DVector aVectorX(aSizeX.Width(), aSizeX.Height());
1447 pDXArry[i] = basegfx::fround(aVectorX.getLength());
1448 pDXArry[i] *= (nSumX >= 0 ? 1 : -1);
1450 if (pDYArry)
1452 nSumY += pDYArry[i];
1454 const Size aSizeY(ImplMap(Size(0, nSumY)));
1455 const basegfx::B2DVector aVectorY(aSizeY.Width(), aSizeY.Height());
1456 // Reverse Y
1457 pDYArry[i] = basegfx::fround(aVectorY.getLength());
1458 pDYArry[i] *= (nSumY >= 0 ? -1 : 1);
1462 if ( mnLatestTextLayoutMode != mnTextLayoutMode )
1464 mnLatestTextLayoutMode = mnTextLayoutMode;
1465 mpGDIMetaFile->AddAction( new MetaLayoutModeAction( mnTextLayoutMode ) );
1467 SetGfxMode( nGfxMode );
1468 TextAlign eTextAlign;
1469 if ( ( mnTextAlign & TA_BASELINE) == TA_BASELINE )
1470 eTextAlign = ALIGN_BASELINE;
1471 else if( ( mnTextAlign & TA_BOTTOM) == TA_BOTTOM )
1472 eTextAlign = ALIGN_BOTTOM;
1473 else
1474 eTextAlign = ALIGN_TOP;
1475 bool bChangeFont = false;
1476 if ( mnLatestTextAlign != mnTextAlign )
1478 bChangeFont = true;
1479 mnLatestTextAlign = mnTextAlign;
1480 mpGDIMetaFile->AddAction( new MetaTextAlignAction( eTextAlign ) );
1482 if ( maLatestTextColor != maTextColor )
1484 bChangeFont = true;
1485 maLatestTextColor = maTextColor;
1486 mpGDIMetaFile->AddAction( new MetaTextColorAction( maTextColor ) );
1488 bool bChangeFillColor = false;
1489 if ( maLatestBkColor != maBkColor )
1491 bChangeFillColor = true;
1492 maLatestBkColor = maBkColor;
1494 if ( mnLatestBkMode != mnBkMode )
1496 bChangeFillColor = true;
1497 mnLatestBkMode = mnBkMode;
1499 if ( bChangeFillColor )
1501 bChangeFont = true;
1502 mpGDIMetaFile->AddAction( new MetaTextFillColorAction( maFont.GetFillColor(), !maFont.IsTransparent() ) );
1504 vcl::Font aTmp( maFont );
1505 aTmp.SetColor( maTextColor );
1506 aTmp.SetFillColor( maBkColor );
1508 if( mnBkMode == BkMode::Transparent )
1509 aTmp.SetTransparent( true );
1510 else
1511 aTmp.SetTransparent( false );
1513 aTmp.SetAlignment( eTextAlign );
1515 if ( nGfxMode == GM_ADVANCED )
1517 // check whether there is a font rotation applied via transformation
1518 Point aP1( ImplMap( Point() ) );
1519 Point aP2( ImplMap( Point( 0, 100 ) ) );
1520 aP2.AdjustX( -(aP1.X()) );
1521 aP2.AdjustY( -(aP1.Y()) );
1522 double fX = aP2.X();
1523 double fY = aP2.Y();
1524 if ( fX )
1526 double fOrientation = acos( fX / sqrt( fX * fX + fY * fY ) ) * 57.29577951308;
1527 if ( fY > 0 )
1528 fOrientation = 360 - fOrientation;
1529 fOrientation += 90;
1530 fOrientation *= 10;
1531 fOrientation += aTmp.GetOrientation();
1532 aTmp.SetOrientation( sal_Int16( fOrientation ) );
1536 if( mnTextAlign & ( TA_UPDATECP | TA_RIGHT_CENTER ) )
1538 // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
1539 SolarMutexGuard aGuard;
1540 ScopedVclPtrInstance< VirtualDevice > pVDev;
1541 sal_Int32 nTextWidth;
1542 Point aActPosDelta;
1543 pVDev->SetMapMode( MapMode( MapUnit::Map100thMM ) );
1544 pVDev->SetFont( maFont );
1545 const sal_uInt32 nLen = pDXArry ? rText.getLength() : 0;
1546 if (nLen)
1548 nTextWidth = pVDev->GetTextWidth( OUString(rText[ nLen - 1 ]) );
1549 if( nLen > 1 )
1550 nTextWidth += pDXArry[ nLen - 2 ];
1551 // tdf#39894: We should consider the distance to next character cell origin
1552 aActPosDelta.setX( pDXArry[ nLen - 1 ] );
1553 if ( pDYArry )
1555 aActPosDelta.setY( pDYArry[ nLen - 1 ] );
1558 else
1560 nTextWidth = pVDev->GetTextWidth( rText );
1561 aActPosDelta.setX( nTextWidth );
1564 if( mnTextAlign & TA_UPDATECP )
1565 rPosition = maActPos;
1567 if ( mnTextAlign & TA_RIGHT_CENTER )
1569 Point aDisplacement( ( ( mnTextAlign & TA_RIGHT_CENTER ) == TA_RIGHT ) ? nTextWidth : nTextWidth >> 1, 0 );
1570 Point().RotateAround(aDisplacement, maFont.GetOrientation());
1571 rPosition -= aDisplacement;
1574 if( mnTextAlign & TA_UPDATECP )
1576 Point().RotateAround(aActPosDelta, maFont.GetOrientation());
1577 maActPos = rPosition + aActPosDelta;
1580 if ( bChangeFont || ( maLatestFont != aTmp ) )
1582 maLatestFont = aTmp;
1583 mpGDIMetaFile->AddAction( new MetaFontAction( aTmp ) );
1584 mpGDIMetaFile->AddAction( new MetaTextAlignAction( aTmp.GetAlignment() ) );
1585 mpGDIMetaFile->AddAction( new MetaTextColorAction( aTmp.GetColor() ) );
1586 mpGDIMetaFile->AddAction( new MetaTextFillColorAction( aTmp.GetFillColor(), !aTmp.IsTransparent() ) );
1588 if ( bRecordPath )
1590 // TODO
1592 else
1594 if ( pDXArry && pDYArry )
1596 for (sal_Int32 i = 0; i < rText.getLength(); ++i)
1598 Point aCharDisplacement( i ? pDXArry[i-1] : 0, i ? pDYArry[i-1] : 0 );
1599 Point().RotateAround(aCharDisplacement, maFont.GetOrientation());
1600 mpGDIMetaFile->AddAction( new MetaTextArrayAction( rPosition + aCharDisplacement, OUString( rText[i] ), nullptr, 0, 1 ) );
1603 else
1605 /* because text without dx array is badly scaled, we
1606 will create such an array if necessary */
1607 long* pDX = pDXArry;
1608 if (!pDXArry)
1610 // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
1611 SolarMutexGuard aGuard;
1612 ScopedVclPtrInstance< VirtualDevice > pVDev;
1613 pDX = new long[ rText.getLength() ];
1614 pVDev->SetMapMode(MapMode(MapUnit::Map100thMM));
1615 pVDev->SetFont( maLatestFont );
1616 pVDev->GetTextArray( rText, pDX, 0, rText.getLength());
1618 mpGDIMetaFile->AddAction( new MetaTextArrayAction( rPosition, rText, pDX, 0, rText.getLength() ) );
1619 if ( !pDXArry ) // this means we have created our own array
1620 delete[] pDX; // which must be deleted
1623 SetGfxMode( nOldGfxMode );
1626 void MtfTools::ImplDrawBitmap( const Point& rPos, const Size& rSize, const BitmapEx& rBitmap )
1628 BitmapEx aBmpEx( rBitmap );
1629 if ( mbComplexClip )
1631 vcl::bitmap::DrawAndClipBitmap(rPos, rSize, rBitmap, aBmpEx, maClipPath.getClipPath());
1634 if ( aBmpEx.IsTransparent() )
1635 mpGDIMetaFile->AddAction( new MetaBmpExScaleAction( rPos, rSize, aBmpEx ) );
1636 else
1637 mpGDIMetaFile->AddAction( new MetaBmpScaleAction( rPos, rSize, aBmpEx.GetBitmap() ) );
1640 void MtfTools::ResolveBitmapActions( std::vector<std::unique_ptr<BSaveStruct>>& rSaveList )
1642 UpdateClipRegion();
1644 size_t nObjects = rSaveList.size();
1645 size_t nObjectsLeft = nObjects;
1647 while ( nObjectsLeft )
1649 size_t i;
1650 size_t nObjectsOfSameSize = 0;
1651 size_t nObjectStartIndex = nObjects - nObjectsLeft;
1653 BSaveStruct* pSave = rSaveList[nObjectStartIndex].get();
1654 tools::Rectangle aRect( pSave->aOutRect );
1656 for ( i = nObjectStartIndex; i < nObjects; )
1658 nObjectsOfSameSize++;
1659 if ( ++i < nObjects )
1661 pSave = rSaveList[i].get();
1662 if ( pSave->aOutRect != aRect )
1663 break;
1666 Point aPos( ImplMap( aRect.TopLeft() ) );
1667 Size aSize( ImplMap( aRect.GetSize() ) );
1669 for ( i = nObjectStartIndex; i < ( nObjectStartIndex + nObjectsOfSameSize ); i++ )
1671 pSave = rSaveList[i].get();
1673 sal_uInt32 nWinRop = pSave->nWinRop;
1674 sal_uInt8 nRasterOperation = static_cast<sal_uInt8>( nWinRop >> 16 );
1676 sal_uInt32 nUsed = 0;
1677 if ( ( nRasterOperation & 0xf ) != ( nRasterOperation >> 4 ) )
1678 nUsed |= 1; // pattern is used
1679 if ( ( nRasterOperation & 0x33 ) != ( ( nRasterOperation & 0xcc ) >> 2 ) )
1680 nUsed |= 2; // source is used
1681 if ( ( nRasterOperation & 0xaa ) != ( ( nRasterOperation & 0x55 ) << 1 ) )
1682 nUsed |= 4; // destination is used
1684 if ( (nUsed & 1) && (( nUsed & 2 ) == 0) && nWinRop != PATINVERT )
1685 { // patterns aren't well supported yet
1686 WMFRasterOp nOldRop = SetRasterOp( WMFRasterOp::NONE ); // in this case nRasterOperation is either 0 or 0xff
1687 UpdateFillStyle();
1688 DrawRect( aRect, false );
1689 SetRasterOp( nOldRop );
1691 else
1693 bool bDrawn = false;
1695 if ( i == nObjectStartIndex ) // optimizing, sometimes it is possible to create just one transparent bitmap
1697 if ( nObjectsOfSameSize == 2 )
1699 BSaveStruct* pSave2 = rSaveList[i + 1].get();
1700 if ( ( pSave->aBmpEx.GetPrefSize() == pSave2->aBmpEx.GetPrefSize() ) &&
1701 ( pSave->aBmpEx.GetPrefMapMode() == pSave2->aBmpEx.GetPrefMapMode() ) )
1703 // TODO: Strictly speaking, we should
1704 // check whether mask is monochrome, and
1705 // whether image is black (upper branch)
1706 // or white (lower branch). Otherwise, the
1707 // effect is not the same as a masked
1708 // bitmap.
1709 if ( ( nWinRop == SRCPAINT ) && ( pSave2->nWinRop == SRCAND ) )
1711 Bitmap aMask( pSave->aBmpEx.GetBitmap() ); aMask.Invert();
1712 BitmapEx aBmpEx( pSave2->aBmpEx.GetBitmap(), aMask );
1713 ImplDrawBitmap( aPos, aSize, aBmpEx );
1714 bDrawn = true;
1715 i++;
1717 // #i20085# This is just the other way
1718 // around as above. Only difference: mask
1719 // is inverted
1720 else if ( ( nWinRop == SRCAND ) && ( pSave2->nWinRop == SRCPAINT ) )
1722 Bitmap aMask( pSave->aBmpEx.GetBitmap() );
1723 BitmapEx aBmpEx( pSave2->aBmpEx.GetBitmap(), aMask );
1724 ImplDrawBitmap( aPos, aSize, aBmpEx );
1725 bDrawn = true;
1726 i++;
1728 // tdf#90539
1729 else if ( ( nWinRop == SRCAND ) && ( pSave2->nWinRop == SRCINVERT ) )
1731 Bitmap aMask( pSave->aBmpEx.GetBitmap() );
1732 BitmapEx aBmpEx( pSave2->aBmpEx.GetBitmap(), aMask );
1733 ImplDrawBitmap( aPos, aSize, aBmpEx );
1734 bDrawn = true;
1735 i++;
1741 if ( !bDrawn )
1743 Push();
1744 WMFRasterOp nOldRop = SetRasterOp( WMFRasterOp::CopyPen );
1745 Bitmap aBitmap( pSave->aBmpEx.GetBitmap() );
1746 sal_uInt32 nOperation = ( nRasterOperation & 0xf );
1747 switch( nOperation )
1749 case 0x1 :
1750 case 0xe :
1752 if(pSave->aBmpEx.IsAlpha())
1754 ImplDrawBitmap( aPos, aSize, pSave->aBmpEx );
1756 else
1758 SetRasterOp( WMFRasterOp::XorPen );
1759 ImplDrawBitmap( aPos, aSize, BitmapEx(aBitmap) );
1760 SetRasterOp( WMFRasterOp::CopyPen );
1761 Bitmap aMask( aBitmap );
1762 aMask.Invert();
1763 BitmapEx aBmpEx( aBitmap, aMask );
1764 ImplDrawBitmap( aPos, aSize, aBmpEx );
1765 if ( nOperation == 0x1 )
1767 SetRasterOp( WMFRasterOp::Not );
1768 DrawRect( aRect, false );
1772 break;
1773 case 0x7 :
1774 case 0x8 :
1776 Bitmap aMask( aBitmap );
1777 if ( ( nUsed & 1 ) && ( nRasterOperation & 0xb0 ) == 0xb0 ) // pattern used
1779 aBitmap.Convert( BmpConversion::N24Bit );
1780 aBitmap.Erase( maFillStyle.aFillColor );
1782 BitmapEx aBmpEx( aBitmap, aMask );
1783 ImplDrawBitmap( aPos, aSize, aBmpEx );
1784 if ( nOperation == 0x7 )
1786 SetRasterOp( WMFRasterOp::Not );
1787 DrawRect( aRect, false );
1790 break;
1792 case 0x4 :
1793 case 0xb :
1795 SetRasterOp( WMFRasterOp::Not );
1796 DrawRect( aRect, false );
1797 SetRasterOp( WMFRasterOp::CopyPen );
1798 Bitmap aMask( aBitmap );
1799 aBitmap.Invert();
1800 BitmapEx aBmpEx( aBitmap, aMask );
1801 ImplDrawBitmap( aPos, aSize, aBmpEx );
1802 SetRasterOp( WMFRasterOp::XorPen );
1803 ImplDrawBitmap( aPos, aSize, BitmapEx(aBitmap) );
1804 if ( nOperation == 0xb )
1806 SetRasterOp( WMFRasterOp::Not );
1807 DrawRect( aRect, false );
1810 break;
1812 case 0x2 :
1813 case 0xd :
1815 Bitmap aMask( aBitmap );
1816 aMask.Invert();
1817 BitmapEx aBmpEx( aBitmap, aMask );
1818 ImplDrawBitmap( aPos, aSize, aBmpEx );
1819 SetRasterOp( WMFRasterOp::XorPen );
1820 ImplDrawBitmap( aPos, aSize, BitmapEx(aBitmap) );
1821 if ( nOperation == 0xd )
1823 SetRasterOp( WMFRasterOp::Not );
1824 DrawRect( aRect, false );
1827 break;
1828 case 0x6 :
1829 case 0x9 :
1831 SetRasterOp( WMFRasterOp::XorPen );
1832 ImplDrawBitmap( aPos, aSize, BitmapEx(aBitmap) );
1833 if ( nOperation == 0x9 )
1835 SetRasterOp( WMFRasterOp::Not );
1836 DrawRect( aRect, false );
1839 break;
1841 case 0x0 : // WHITENESS
1842 case 0xf : // BLACKNESS
1843 { // in this case nRasterOperation is either 0 or 0xff
1844 maFillStyle = WinMtfFillStyle( Color( nRasterOperation, nRasterOperation, nRasterOperation ) );
1845 UpdateFillStyle();
1846 DrawRect( aRect, false );
1848 break;
1850 case 0x3 : // only source is used
1851 case 0xc :
1853 if ( nRasterOperation == 0x33 )
1854 aBitmap.Invert();
1855 ImplDrawBitmap( aPos, aSize, BitmapEx(aBitmap) );
1857 break;
1859 case 0x5 : // only destination is used
1861 SetRasterOp( WMFRasterOp::Not );
1862 DrawRect( aRect, false );
1864 break;
1866 case 0xa : // no operation
1867 break;
1869 SetRasterOp( nOldRop );
1870 Pop();
1874 nObjectsLeft -= nObjectsOfSameSize;
1877 rSaveList.clear();
1880 void MtfTools::SetDevOrg( const Point& rPoint )
1882 mnDevOrgX = rPoint.X();
1883 mnDevOrgY = rPoint.Y();
1886 void MtfTools::SetDevOrgOffset( sal_Int32 nXAdd, sal_Int32 nYAdd )
1888 mnDevOrgX += nXAdd;
1889 mnDevOrgY += nYAdd;
1892 void MtfTools::SetDevExt( const Size& rSize ,bool regular)
1894 if ( rSize.Width() && rSize.Height() )
1896 switch( mnMapMode )
1898 case MM_ISOTROPIC :
1899 case MM_ANISOTROPIC :
1901 mnDevWidth = rSize.Width();
1902 mnDevHeight = rSize.Height();
1905 if (regular)
1907 mbIsMapDevSet=true;
1912 void MtfTools::ScaleDevExt(double fX, double fY)
1914 mnDevWidth = basegfx::fround(mnDevWidth * fX);
1915 mnDevHeight = basegfx::fround(mnDevHeight * fY);
1918 void MtfTools::SetWinOrg( const Point& rPoint , bool bIsEMF)
1920 mnWinOrgX = rPoint.X();
1921 mnWinOrgY = rPoint.Y();
1922 if (bIsEMF)
1924 SetDevByWin();
1926 mbIsMapWinSet=true;
1929 void MtfTools::SetWinOrgOffset( sal_Int32 nXAdd, sal_Int32 nYAdd )
1931 mnWinOrgX += nXAdd;
1932 mnWinOrgY += nYAdd;
1935 void MtfTools::SetDevByWin() //mnWinExt...-stuff has to be assigned before.
1937 if (!mbIsMapDevSet)
1939 if ( mnMapMode == MM_ISOTROPIC ) //TODO: WHAT ABOUT ANISOTROPIC???
1941 sal_Int32 nX, nY;
1942 if (o3tl::checked_add(mnWinExtX, mnWinOrgX, nX) || o3tl::checked_sub(mnWinExtY, mnWinOrgY, nY))
1943 return;
1944 Size aSize(nX >> MS_FIXPOINT_BITCOUNT_28_4, -(nY >> MS_FIXPOINT_BITCOUNT_28_4));
1945 SetDevExt(aSize, false);
1950 void MtfTools::SetWinExt(const Size& rSize, bool bIsEMF)
1952 if (rSize.Width() && rSize.Height())
1954 switch( mnMapMode )
1956 case MM_ISOTROPIC :
1957 case MM_ANISOTROPIC :
1959 mnWinExtX = rSize.Width();
1960 mnWinExtY = rSize.Height();
1961 if (bIsEMF)
1963 SetDevByWin();
1965 mbIsMapWinSet = true;
1971 void MtfTools::ScaleWinExt(double fX, double fY)
1973 mnWinExtX = basegfx::fround(mnWinExtX * fX);
1974 mnWinExtY = basegfx::fround(mnWinExtY * fY);
1977 void MtfTools::SetrclBounds( const tools::Rectangle& rRect )
1979 mrclBounds = rRect;
1982 void MtfTools::SetrclFrame( const tools::Rectangle& rRect )
1984 mrclFrame = rRect;
1987 void MtfTools::SetRefPix( const Size& rSize )
1989 mnPixX = rSize.Width();
1990 mnPixY = rSize.Height();
1993 void MtfTools::SetRefMill( const Size& rSize )
1995 mnMillX = rSize.Width();
1996 mnMillY = rSize.Height();
1999 void MtfTools::SetMapMode( sal_uInt32 nMapMode )
2001 mnMapMode = nMapMode;
2002 if ( nMapMode == MM_TEXT && !mbIsMapWinSet )
2004 mnWinExtX = mnDevWidth;
2005 mnWinExtY = mnDevHeight;
2007 else if ( mnMapMode == MM_HIMETRIC )
2009 sal_Int32 nWinExtX, nWinExtY;
2010 if (o3tl::checked_multiply<sal_Int32>(mnMillX, 100, nWinExtX) ||
2011 o3tl::checked_multiply<sal_Int32>(mnMillY, 100, nWinExtY))
2013 return;
2015 mnWinExtX = nWinExtX;
2016 mnWinExtY = nWinExtY;
2020 void MtfTools::SetWorldTransform( const XForm& rXForm )
2022 maXForm.eM11 = rXForm.eM11;
2023 maXForm.eM12 = rXForm.eM12;
2024 maXForm.eM21 = rXForm.eM21;
2025 maXForm.eM22 = rXForm.eM22;
2026 maXForm.eDx = rXForm.eDx;
2027 maXForm.eDy = rXForm.eDy;
2030 void MtfTools::ModifyWorldTransform( const XForm& rXForm, sal_uInt32 nMode )
2032 switch( nMode )
2034 case MWT_IDENTITY :
2036 maXForm.eM11 = maXForm.eM22 = 1.0f;
2037 maXForm.eM12 = maXForm.eM21 = maXForm.eDx = maXForm.eDy = 0.0f;
2038 break;
2041 case MWT_RIGHTMULTIPLY :
2042 case MWT_LEFTMULTIPLY :
2044 const XForm* pLeft;
2045 const XForm* pRight;
2047 if ( nMode == MWT_LEFTMULTIPLY )
2049 pLeft = &rXForm;
2050 pRight = &maXForm;
2052 else
2054 pLeft = &maXForm;
2055 pRight = &rXForm;
2058 float aF[3][3];
2059 float bF[3][3];
2060 float cF[3][3];
2062 aF[0][0] = pLeft->eM11;
2063 aF[0][1] = pLeft->eM12;
2064 aF[0][2] = 0;
2065 aF[1][0] = pLeft->eM21;
2066 aF[1][1] = pLeft->eM22;
2067 aF[1][2] = 0;
2068 aF[2][0] = pLeft->eDx;
2069 aF[2][1] = pLeft->eDy;
2070 aF[2][2] = 1;
2072 bF[0][0] = pRight->eM11;
2073 bF[0][1] = pRight->eM12;
2074 bF[0][2] = 0;
2075 bF[1][0] = pRight->eM21;
2076 bF[1][1] = pRight->eM22;
2077 bF[1][2] = 0;
2078 bF[2][0] = pRight->eDx;
2079 bF[2][1] = pRight->eDy;
2080 bF[2][2] = 1;
2082 int i, j, k;
2083 for ( i = 0; i < 3; i++ )
2085 for ( j = 0; j < 3; j++ )
2087 cF[i][j] = 0;
2088 for ( k = 0; k < 3; k++ )
2089 cF[i][j] += aF[i][k] * bF[k][j];
2092 maXForm.eM11 = cF[0][0];
2093 maXForm.eM12 = cF[0][1];
2094 maXForm.eM21 = cF[1][0];
2095 maXForm.eM22 = cF[1][1];
2096 maXForm.eDx = cF[2][0];
2097 maXForm.eDy = cF[2][1];
2098 break;
2100 case MWT_SET:
2102 SetWorldTransform(rXForm);
2103 break;
2108 void MtfTools::Push() // !! to be able to access the original ClipRegion it
2109 { // is not allowed to use the MetaPushAction()
2110 UpdateClipRegion(); // (the original clip region is on top of the stack) (SJ)
2111 std::shared_ptr<SaveStruct> pSave( new SaveStruct );
2113 pSave->aLineStyle = maLineStyle;
2114 pSave->aFillStyle = maFillStyle;
2116 pSave->aFont = maFont;
2117 pSave->aTextColor = maTextColor;
2118 pSave->nTextAlign = mnTextAlign;
2119 pSave->nTextLayoutMode = mnTextLayoutMode;
2120 pSave->nMapMode = mnMapMode;
2121 pSave->nGfxMode = mnGfxMode;
2122 pSave->nBkMode = mnBkMode;
2123 pSave->aBkColor = maBkColor;
2124 pSave->bFillStyleSelected = mbFillStyleSelected;
2126 pSave->aActPos = maActPos;
2127 pSave->aXForm = maXForm;
2128 pSave->eRasterOp = meRasterOp;
2130 pSave->nWinOrgX = mnWinOrgX;
2131 pSave->nWinOrgY = mnWinOrgY;
2132 pSave->nWinExtX = mnWinExtX;
2133 pSave->nWinExtY = mnWinExtY;
2134 pSave->nDevOrgX = mnDevOrgX;
2135 pSave->nDevOrgY = mnDevOrgY;
2136 pSave->nDevWidth = mnDevWidth;
2137 pSave->nDevHeight = mnDevHeight;
2139 pSave->maPathObj = maPathObj;
2140 pSave->maClipPath = maClipPath;
2142 mvSaveStack.push_back( pSave );
2145 void MtfTools::Pop()
2147 // Get the latest data from the stack
2148 if( !mvSaveStack.empty() )
2150 // Backup the current data on the stack
2151 std::shared_ptr<SaveStruct> pSave( mvSaveStack.back() );
2153 maLineStyle = pSave->aLineStyle;
2154 maFillStyle = pSave->aFillStyle;
2156 maFont = pSave->aFont;
2157 maTextColor = pSave->aTextColor;
2158 mnTextAlign = pSave->nTextAlign;
2159 mnTextLayoutMode = pSave->nTextLayoutMode;
2160 mnBkMode = pSave->nBkMode;
2161 mnGfxMode = pSave->nGfxMode;
2162 mnMapMode = pSave->nMapMode;
2163 maBkColor = pSave->aBkColor;
2164 mbFillStyleSelected = pSave->bFillStyleSelected;
2166 maActPos = pSave->aActPos;
2167 maXForm = pSave->aXForm;
2168 meRasterOp = pSave->eRasterOp;
2170 mnWinOrgX = pSave->nWinOrgX;
2171 mnWinOrgY = pSave->nWinOrgY;
2172 mnWinExtX = pSave->nWinExtX;
2173 mnWinExtY = pSave->nWinExtY;
2174 mnDevOrgX = pSave->nDevOrgX;
2175 mnDevOrgY = pSave->nDevOrgY;
2176 mnDevWidth = pSave->nDevWidth;
2177 mnDevHeight = pSave->nDevHeight;
2179 maPathObj = pSave->maPathObj;
2180 if ( ! ( maClipPath == pSave->maClipPath ) )
2182 maClipPath = pSave->maClipPath;
2183 mbClipNeedsUpdate = true;
2185 if ( meLatestRasterOp != meRasterOp )
2186 mpGDIMetaFile->AddAction( new MetaRasterOpAction( meRasterOp ) );
2187 mvSaveStack.pop_back();
2191 void MtfTools::AddFromGDIMetaFile( GDIMetaFile& rGDIMetaFile )
2193 rGDIMetaFile.Play( *mpGDIMetaFile );
2196 void MtfTools::PassEMFPlusHeaderInfo()
2198 EMFP_DEBUG(printf ("\t\t\tadd EMF_PLUS header info\n"));
2200 SvMemoryStream mem;
2201 sal_Int32 nLeft, nRight, nTop, nBottom;
2203 nLeft = mrclFrame.Left();
2204 nTop = mrclFrame.Top();
2205 nRight = mrclFrame.Right();
2206 nBottom = mrclFrame.Bottom();
2208 // emf header info
2209 mem.WriteInt32( nLeft ).WriteInt32( nTop ).WriteInt32( nRight ).WriteInt32( nBottom );
2210 mem.WriteInt32( mnPixX ).WriteInt32( mnPixY ).WriteInt32( mnMillX ).WriteInt32( mnMillY );
2212 float one, zero;
2214 one = 1;
2215 zero = 0;
2217 // add transformation matrix to be used in vcl's metaact.cxx for
2218 // rotate and scale operations
2219 mem.WriteFloat( one ).WriteFloat( zero ).WriteFloat( zero ).WriteFloat( one ).WriteFloat( zero ).WriteFloat( zero );
2221 // need to flush the stream, otherwise GetEndOfData will return 0
2222 // on windows where the function parameters are probably resolved in reverse order
2223 mem.Flush();
2225 mpGDIMetaFile->AddAction( new MetaCommentAction( "EMF_PLUS_HEADER_INFO", 0, static_cast<const sal_uInt8*>(mem.GetData()), mem.GetEndOfData() ) );
2226 mpGDIMetaFile->UseCanvas( true );
2229 void MtfTools::PassEMFPlus( void const * pBuffer, sal_uInt32 nLength )
2231 EMFP_DEBUG(printf ("\t\t\tadd EMF_PLUS comment length %04x\n",(unsigned int) nLength));
2232 mpGDIMetaFile->AddAction( new MetaCommentAction( "EMF_PLUS", 0, static_cast<const sal_uInt8*>(pBuffer), nLength ) );
2236 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */