defer finding dialog parent until we need it
[LibreOffice.git] / vcl / source / outdev / map.cxx
blobeec697efcc53634ccb9fa4083a211974b919744a
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 <sal/config.h>
22 #include <sal/log.hxx>
23 #include <osl/diagnose.h>
24 #include <tools/bigint.hxx>
25 #include <tools/debug.hxx>
27 #include <vcl/cursor.hxx>
28 #include <vcl/lineinfo.hxx>
29 #include <vcl/metaact.hxx>
30 #include <vcl/virdev.hxx>
31 #include <vcl/wrkwin.hxx>
33 #include <ImplOutDevData.hxx>
34 #include <svdata.hxx>
35 #include <window.h>
37 #include <basegfx/matrix/b2dhommatrix.hxx>
38 #include <tools/UnitConversion.hxx>
40 static auto setMapRes(ImplMapRes& rMapRes, const o3tl::Length eUnit)
42 const auto [nNum, nDen] = o3tl::getConversionMulDiv(eUnit, o3tl::Length::in);
43 rMapRes.mnMapScNumX = rMapRes.mnMapScNumY = nNum;
44 rMapRes.mnMapScDenomX = rMapRes.mnMapScDenomY = nDen;
47 static void ImplCalcMapResolution( const MapMode& rMapMode,
48 tools::Long nDPIX, tools::Long nDPIY, ImplMapRes& rMapRes )
50 switch ( rMapMode.GetMapUnit() )
52 case MapUnit::MapRelative:
53 break;
54 case MapUnit::Map100thMM:
55 setMapRes(rMapRes, o3tl::Length::mm100);
56 break;
57 case MapUnit::Map10thMM:
58 setMapRes(rMapRes, o3tl::Length::mm10);
59 break;
60 case MapUnit::MapMM:
61 setMapRes(rMapRes, o3tl::Length::mm);
62 break;
63 case MapUnit::MapCM:
64 setMapRes(rMapRes, o3tl::Length::cm);
65 break;
66 case MapUnit::Map1000thInch:
67 setMapRes(rMapRes, o3tl::Length::in1000);
68 break;
69 case MapUnit::Map100thInch:
70 setMapRes(rMapRes, o3tl::Length::in100);
71 break;
72 case MapUnit::Map10thInch:
73 setMapRes(rMapRes, o3tl::Length::in10);
74 break;
75 case MapUnit::MapInch:
76 setMapRes(rMapRes, o3tl::Length::in);
77 break;
78 case MapUnit::MapPoint:
79 setMapRes(rMapRes, o3tl::Length::pt);
80 break;
81 case MapUnit::MapTwip:
82 setMapRes(rMapRes, o3tl::Length::twip);
83 break;
84 case MapUnit::MapPixel:
85 rMapRes.mnMapScNumX = 1;
86 rMapRes.mnMapScDenomX = nDPIX;
87 rMapRes.mnMapScNumY = 1;
88 rMapRes.mnMapScDenomY = nDPIY;
89 break;
90 case MapUnit::MapSysFont:
91 case MapUnit::MapAppFont:
93 ImplSVData* pSVData = ImplGetSVData();
94 if ( !pSVData->maGDIData.mnAppFontX )
96 if (pSVData->maFrameData.mpFirstFrame)
97 vcl::Window::ImplInitAppFontData(pSVData->maFrameData.mpFirstFrame);
98 else
100 ScopedVclPtrInstance<WorkWindow> pWin( nullptr, 0 );
101 vcl::Window::ImplInitAppFontData( pWin );
104 rMapRes.mnMapScNumX = pSVData->maGDIData.mnAppFontX;
105 rMapRes.mnMapScDenomX = nDPIX * 40;
106 rMapRes.mnMapScNumY = pSVData->maGDIData.mnAppFontY;
107 rMapRes.mnMapScDenomY = nDPIY * 80;
109 break;
110 default:
111 OSL_FAIL( "unhandled MapUnit" );
112 break;
115 const Fraction& aScaleX = rMapMode.GetScaleX();
116 const Fraction& aScaleY = rMapMode.GetScaleY();
118 // set offset according to MapMode
119 Point aOrigin = rMapMode.GetOrigin();
120 if ( rMapMode.GetMapUnit() != MapUnit::MapRelative )
122 rMapRes.mnMapOfsX = aOrigin.X();
123 rMapRes.mnMapOfsY = aOrigin.Y();
125 else
127 auto funcCalcOffset = [](const Fraction& rScale, tools::Long& rnMapOffset, tools::Long nOrigin)
129 auto nNumerator = rScale.GetNumerator();
130 assert(nNumerator != 0);
132 BigInt aX( rnMapOffset );
133 aX *= BigInt( rScale.GetDenominator() );
134 if ( rnMapOffset >= 0 )
136 if (nNumerator >= 0)
137 aX += BigInt(nNumerator / 2);
138 else
139 aX -= BigInt((nNumerator + 1) / 2);
141 else
143 if (nNumerator >= 0 )
144 aX -= BigInt((nNumerator - 1) / 2);
145 else
146 aX += BigInt(nNumerator / 2);
148 aX /= BigInt(nNumerator);
149 rnMapOffset = static_cast<tools::Long>(aX) + nOrigin;
152 funcCalcOffset(aScaleX, rMapRes.mnMapOfsX, aOrigin.X());
153 funcCalcOffset(aScaleY, rMapRes.mnMapOfsY, aOrigin.Y());
156 // calculate scaling factor according to MapMode
157 // aTemp? = rMapRes.mnMapSc? * aScale?
158 Fraction aTempX = Fraction::MakeFraction( rMapRes.mnMapScNumX,
159 aScaleX.GetNumerator(),
160 rMapRes.mnMapScDenomX,
161 aScaleX.GetDenominator() );
162 Fraction aTempY = Fraction::MakeFraction( rMapRes.mnMapScNumY,
163 aScaleY.GetNumerator(),
164 rMapRes.mnMapScDenomY,
165 aScaleY.GetDenominator() );
166 rMapRes.mnMapScNumX = aTempX.GetNumerator();
167 rMapRes.mnMapScDenomX = aTempX.GetDenominator();
168 rMapRes.mnMapScNumY = aTempY.GetNumerator();
169 rMapRes.mnMapScDenomY = aTempY.GetDenominator();
172 // #i75163#
173 void OutputDevice::ImplInvalidateViewTransform()
175 if(!mpOutDevData)
176 return;
178 if(mpOutDevData->mpViewTransform)
180 delete mpOutDevData->mpViewTransform;
181 mpOutDevData->mpViewTransform = nullptr;
184 if(mpOutDevData->mpInverseViewTransform)
186 delete mpOutDevData->mpInverseViewTransform;
187 mpOutDevData->mpInverseViewTransform = nullptr;
191 static tools::Long ImplLogicToPixel(tools::Long n, tools::Long nDPI, tools::Long nMapNum,
192 tools::Long nMapDenom)
194 assert(nDPI > 0);
195 assert(nMapDenom != 0);
196 if constexpr (sizeof(tools::Long) >= 8)
198 assert(nMapNum >= 0);
199 //detect overflows
200 assert(nMapNum == 0
201 || std::abs(n) < std::numeric_limits<tools::Long>::max() / nMapNum / nDPI);
203 sal_Int64 n64 = n;
204 n64 *= nMapNum;
205 n64 *= nDPI;
206 if (nMapDenom == 1)
207 n = static_cast<tools::Long>(n64);
208 else
210 n64 = 2 * n64 / nMapDenom;
211 if (n64 < 0)
212 --n64;
213 else
214 ++n64;
215 n = static_cast<tools::Long>(n64 / 2);
217 return n;
220 static double ImplLogicToSubPixel(tools::Long n, tools::Long nDPI, tools::Long nMapNum,
221 tools::Long nMapDenom)
223 assert(nDPI > 0);
224 assert(nMapDenom != 0);
225 return static_cast<double>(n) * nMapNum * nDPI / nMapDenom;
228 static tools::Long ImplSubPixelToLogic(double n, tools::Long nDPI, tools::Long nMapNum,
229 tools::Long nMapDenom)
231 assert(nDPI > 0);
232 assert(nMapNum != 0);
234 return std::round(n * nMapDenom / nMapNum / nDPI);
237 static tools::Long ImplPixelToLogic(tools::Long n, tools::Long nDPI, tools::Long nMapNum,
238 tools::Long nMapDenom)
240 assert(nDPI > 0);
241 if (nMapNum == 0)
242 return 0;
243 sal_Int64 nDenom = nDPI;
244 nDenom *= nMapNum;
246 sal_Int64 n64 = n;
247 n64 *= nMapDenom;
248 if (nDenom == 1)
249 n = static_cast<tools::Long>(n64);
250 else
252 n64 = 2 * n64 / nDenom;
253 if (n64 < 0)
254 --n64;
255 else
256 ++n64;
257 n = static_cast<tools::Long>(n64 / 2);
259 return n;
262 static double ImplPixelToLogicDouble(double n, tools::Long nDPI, tools::Long nMapNum,
263 tools::Long nMapDenom)
265 assert(nDPI > 0);
266 if (nMapNum == 0)
267 return 0;
269 n *= nMapDenom;
270 n /= nDPI;
271 n /= nMapNum;
272 return n;
275 tools::Long OutputDevice::ImplLogicXToDevicePixel( tools::Long nX ) const
277 if ( !mbMap )
278 return nX+mnOutOffX;
280 // coverity[ tainted_data_return : FALSE ] version 2023.12.2
281 return ImplLogicToPixel( nX + maMapRes.mnMapOfsX, mnDPIX,
282 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX )+mnOutOffX+mnOutOffOrigX;
285 tools::Long OutputDevice::ImplLogicYToDevicePixel( tools::Long nY ) const
287 if ( !mbMap )
288 return nY+mnOutOffY;
290 // coverity[ tainted_data_return : FALSE ] version 2023.12.2
291 return ImplLogicToPixel( nY + maMapRes.mnMapOfsY, mnDPIY,
292 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY )+mnOutOffY+mnOutOffOrigY;
295 tools::Long OutputDevice::ImplLogicWidthToDevicePixel( tools::Long nWidth ) const
297 if ( !mbMap )
298 return nWidth;
300 return ImplLogicToPixel(nWidth, mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX);
303 tools::Long OutputDevice::ImplLogicHeightToDevicePixel( tools::Long nHeight ) const
305 if ( !mbMap )
306 return nHeight;
308 return ImplLogicToPixel(nHeight, mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY);
311 tools::Long OutputDevice::ImplDevicePixelToLogicWidth( tools::Long nWidth ) const
313 if ( !mbMap )
314 return nWidth;
316 return ImplPixelToLogic(nWidth, mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX);
319 SAL_DLLPRIVATE double OutputDevice::ImplDevicePixelToLogicWidthDouble(double nWidth) const
321 if (!mbMap)
322 return nWidth;
324 return ImplPixelToLogicDouble(nWidth, mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX);
327 tools::Long OutputDevice::ImplDevicePixelToLogicHeight( tools::Long nHeight ) const
329 if ( !mbMap )
330 return nHeight;
332 return ImplPixelToLogic(nHeight, mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY);
335 double OutputDevice::ImplDevicePixelToLogicHeightDouble(double nHeight) const
337 if (!mbMap)
338 return nHeight;
340 return ImplPixelToLogicDouble(nHeight, mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY);
343 Point OutputDevice::ImplLogicToDevicePixel( const Point& rLogicPt ) const
345 if ( !mbMap )
346 return Point( rLogicPt.X()+mnOutOffX, rLogicPt.Y()+mnOutOffY );
348 return Point( ImplLogicToPixel( rLogicPt.X() + maMapRes.mnMapOfsX, mnDPIX,
349 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX )+mnOutOffX+mnOutOffOrigX,
350 ImplLogicToPixel( rLogicPt.Y() + maMapRes.mnMapOfsY, mnDPIY,
351 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY )+mnOutOffY+mnOutOffOrigY );
354 Size OutputDevice::ImplLogicToDevicePixel( const Size& rLogicSize ) const
356 if ( !mbMap )
357 return rLogicSize;
359 return Size( ImplLogicToPixel( rLogicSize.Width(), mnDPIX,
360 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX ),
361 ImplLogicToPixel( rLogicSize.Height(), mnDPIY,
362 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY ) );
365 tools::Rectangle OutputDevice::ImplLogicToDevicePixel( const tools::Rectangle& rLogicRect ) const
367 // tdf#141761 IsEmpty() removed
368 // Even if rLogicRect.IsEmpty(), transform of the Position contained
369 // in the Rectangle is necessary. Due to Rectangle::Right() returning
370 // Left() when IsEmpty(), the code *could* stay unchanged (same for Bottom),
371 // but:
372 // The Rectangle constructor used with the four tools::Long values does not
373 // check for IsEmpty(), so to keep that state correct there are two possibilities:
374 // (1) Add a test to the Rectangle constructor in question
375 // (2) Do it handish here
376 // I have tried (1) first, but test Test::test_rectangle() claims that for
377 // tools::Rectangle aRect(1, 1, 1, 1);
378 // tools::Long(1) == aRect.GetWidth()
379 // tools::Long(0) == aRect.getWidth()
380 // (remember: this means Left == Right == 1 -> GetWidth => 1, getWidth == 0)
381 // so indeed the 1's have to go uncommented/unchecked into the data body
382 // of rectangle. Switching to (2) *is* needed, doing so
383 tools::Rectangle aRetval;
385 if ( !mbMap )
387 aRetval = tools::Rectangle(
388 rLogicRect.Left()+mnOutOffX,
389 rLogicRect.Top()+mnOutOffY,
390 rLogicRect.IsWidthEmpty() ? 0 : rLogicRect.Right()+mnOutOffX,
391 rLogicRect.IsHeightEmpty() ? 0 : rLogicRect.Bottom()+mnOutOffY );
393 else
395 aRetval = tools::Rectangle(
396 ImplLogicToPixel( rLogicRect.Left()+maMapRes.mnMapOfsX, mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX )+mnOutOffX+mnOutOffOrigX,
397 ImplLogicToPixel( rLogicRect.Top()+maMapRes.mnMapOfsY, mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY )+mnOutOffY+mnOutOffOrigY,
398 rLogicRect.IsWidthEmpty() ? 0 : ImplLogicToPixel( rLogicRect.Right()+maMapRes.mnMapOfsX, mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX )+mnOutOffX+mnOutOffOrigX,
399 rLogicRect.IsHeightEmpty() ? 0 : ImplLogicToPixel( rLogicRect.Bottom()+maMapRes.mnMapOfsY, mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY )+mnOutOffY+mnOutOffOrigY );
402 if(rLogicRect.IsWidthEmpty())
403 aRetval.SetWidthEmpty();
405 if(rLogicRect.IsHeightEmpty())
406 aRetval.SetHeightEmpty();
408 return aRetval;
411 tools::Polygon OutputDevice::ImplLogicToDevicePixel( const tools::Polygon& rLogicPoly ) const
413 if ( !mbMap && !mnOutOffX && !mnOutOffY )
414 return rLogicPoly;
416 sal_uInt16 i;
417 sal_uInt16 nPoints = rLogicPoly.GetSize();
418 tools::Polygon aPoly( rLogicPoly );
420 // get pointer to Point-array (copy data)
421 const Point* pPointAry = aPoly.GetConstPointAry();
423 if ( mbMap )
425 for ( i = 0; i < nPoints; i++ )
427 const Point& rPt = pPointAry[i];
428 Point aPt(ImplLogicToPixel( rPt.X()+maMapRes.mnMapOfsX, mnDPIX,
429 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX )+mnOutOffX+mnOutOffOrigX,
430 ImplLogicToPixel( rPt.Y()+maMapRes.mnMapOfsY, mnDPIY,
431 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY )+mnOutOffY+mnOutOffOrigY);
432 aPoly[i] = aPt;
435 else
437 for ( i = 0; i < nPoints; i++ )
439 Point aPt = pPointAry[i];
440 aPt.AdjustX(mnOutOffX );
441 aPt.AdjustY(mnOutOffY );
442 aPoly[i] = aPt;
446 return aPoly;
449 basegfx::B2DPolygon OutputDevice::ImplLogicToDevicePixel(const basegfx::B2DPolygon& rLogicPoly) const
451 if (!mbMap && !mnOutOffX && !mnOutOffY)
452 return rLogicPoly;
454 sal_uInt32 nPoints = rLogicPoly.count();
455 basegfx::B2DPolygon aPoly(rLogicPoly);
457 basegfx::B2DPoint aC1;
458 basegfx::B2DPoint aC2;
460 if (mbMap)
462 for (sal_uInt32 i = 0; i < nPoints; ++i)
464 const basegfx::B2DPoint& rPt = aPoly.getB2DPoint(i);
465 basegfx::B2DPoint aPt(ImplLogicToPixel( rPt.getX()+maMapRes.mnMapOfsX, mnDPIX,
466 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX )+mnOutOffX+mnOutOffOrigX,
467 ImplLogicToPixel( rPt.getY()+maMapRes.mnMapOfsY, mnDPIY,
468 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY )+mnOutOffY+mnOutOffOrigY);
470 const bool bC1 = aPoly.isPrevControlPointUsed(i);
471 if (bC1)
473 const basegfx::B2DPoint aB2DC1(aPoly.getPrevControlPoint(i));
475 aC1 = basegfx::B2DPoint(ImplLogicToPixel( aB2DC1.getX()+maMapRes.mnMapOfsX, mnDPIX,
476 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX )+mnOutOffX+mnOutOffOrigX,
477 ImplLogicToPixel( aB2DC1.getY()+maMapRes.mnMapOfsY, mnDPIY,
478 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY )+mnOutOffY+mnOutOffOrigY);
481 const bool bC2 = aPoly.isNextControlPointUsed(i);
482 if (bC2)
484 const basegfx::B2DPoint aB2DC2(aPoly.getNextControlPoint(i));
486 aC2 = basegfx::B2DPoint(ImplLogicToPixel( aB2DC2.getX()+maMapRes.mnMapOfsX, mnDPIX,
487 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX )+mnOutOffX+mnOutOffOrigX,
488 ImplLogicToPixel( aB2DC2.getY()+maMapRes.mnMapOfsY, mnDPIY,
489 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY )+mnOutOffY+mnOutOffOrigY);
492 aPoly.setB2DPoint(i, aPt);
494 if (bC1)
495 aPoly.setPrevControlPoint(i, aC1);
497 if (bC2)
498 aPoly.setNextControlPoint(i, aC2);
501 else
503 for (sal_uInt32 i = 0; i < nPoints; ++i)
505 const basegfx::B2DPoint& rPt = aPoly.getB2DPoint(i);
506 basegfx::B2DPoint aPt(rPt.getX() + mnOutOffX, rPt.getY() + mnOutOffY);
508 const bool bC1 = aPoly.isPrevControlPointUsed(i);
509 if (bC1)
511 const basegfx::B2DPoint aB2DC1(aPoly.getPrevControlPoint(i));
513 aC1 = basegfx::B2DPoint(aB2DC1.getX() + mnOutOffX, aB2DC1.getY() + mnOutOffY);
516 const bool bC2 = aPoly.isNextControlPointUsed(i);
517 if (bC2)
519 const basegfx::B2DPoint aB2DC2(aPoly.getNextControlPoint(i));
521 aC1 = basegfx::B2DPoint(aB2DC2.getX() + mnOutOffX, aB2DC2.getY() + mnOutOffY);
524 aPoly.setB2DPoint(i, aPt);
526 if (bC1)
527 aPoly.setPrevControlPoint(i, aC1);
529 if (bC2)
530 aPoly.setNextControlPoint(i, aC2);
534 return aPoly;
537 tools::PolyPolygon OutputDevice::ImplLogicToDevicePixel( const tools::PolyPolygon& rLogicPolyPoly ) const
539 if ( !mbMap && !mnOutOffX && !mnOutOffY )
540 return rLogicPolyPoly;
542 tools::PolyPolygon aPolyPoly( rLogicPolyPoly );
543 sal_uInt16 nPoly = aPolyPoly.Count();
544 for( sal_uInt16 i = 0; i < nPoly; i++ )
546 tools::Polygon& rPoly = aPolyPoly[i];
547 rPoly = ImplLogicToDevicePixel( rPoly );
549 return aPolyPoly;
552 LineInfo OutputDevice::ImplLogicToDevicePixel( const LineInfo& rLineInfo ) const
554 LineInfo aInfo( rLineInfo );
556 if( aInfo.GetStyle() == LineStyle::Dash )
558 if( aInfo.GetDotCount() && aInfo.GetDotLen() )
559 aInfo.SetDotLen( std::max( ImplLogicWidthToDevicePixel( aInfo.GetDotLen() ), tools::Long(1) ) );
560 else
561 aInfo.SetDotCount( 0 );
563 if( aInfo.GetDashCount() && aInfo.GetDashLen() )
564 aInfo.SetDashLen( std::max( ImplLogicWidthToDevicePixel( aInfo.GetDashLen() ), tools::Long(1) ) );
565 else
566 aInfo.SetDashCount( 0 );
568 aInfo.SetDistance( ImplLogicWidthToDevicePixel( aInfo.GetDistance() ) );
570 if( ( !aInfo.GetDashCount() && !aInfo.GetDotCount() ) || !aInfo.GetDistance() )
571 aInfo.SetStyle( LineStyle::Solid );
574 aInfo.SetWidth( ImplLogicWidthToDevicePixel( aInfo.GetWidth() ) );
576 return aInfo;
579 tools::Rectangle OutputDevice::ImplDevicePixelToLogic( const tools::Rectangle& rPixelRect ) const
581 // tdf#141761 see comments above, IsEmpty() removed
582 tools::Rectangle aRetval;
584 if ( !mbMap )
586 aRetval = tools::Rectangle(
587 rPixelRect.Left()-mnOutOffX,
588 rPixelRect.Top()-mnOutOffY,
589 rPixelRect.IsWidthEmpty() ? 0 : rPixelRect.Right()-mnOutOffX,
590 rPixelRect.IsHeightEmpty() ? 0 : rPixelRect.Bottom()-mnOutOffY );
592 else
594 aRetval = tools::Rectangle(
595 ImplPixelToLogic( rPixelRect.Left()-mnOutOffX-mnOutOffOrigX, mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX )-maMapRes.mnMapOfsX,
596 ImplPixelToLogic( rPixelRect.Top()-mnOutOffY-mnOutOffOrigY, mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY )-maMapRes.mnMapOfsY,
597 rPixelRect.IsWidthEmpty() ? 0 : ImplPixelToLogic( rPixelRect.Right()-mnOutOffX-mnOutOffOrigX, mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX )-maMapRes.mnMapOfsX,
598 rPixelRect.IsHeightEmpty() ? 0 : ImplPixelToLogic( rPixelRect.Bottom()-mnOutOffY-mnOutOffOrigY, mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY )-maMapRes.mnMapOfsY );
601 if(rPixelRect.IsWidthEmpty())
602 aRetval.SetWidthEmpty();
604 if(rPixelRect.IsHeightEmpty())
605 aRetval.SetHeightEmpty();
607 return aRetval;
610 vcl::Region OutputDevice::ImplPixelToDevicePixel( const vcl::Region& rRegion ) const
612 if ( !mnOutOffX && !mnOutOffY )
613 return rRegion;
615 vcl::Region aRegion( rRegion );
616 aRegion.Move( mnOutOffX+mnOutOffOrigX, mnOutOffY+mnOutOffOrigY );
617 return aRegion;
620 void OutputDevice::EnableMapMode( bool bEnable )
622 mbMap = bEnable;
624 if( mpAlphaVDev )
625 mpAlphaVDev->EnableMapMode( bEnable );
628 void OutputDevice::SetMapMode()
631 if ( mpMetaFile )
632 mpMetaFile->AddAction( new MetaMapModeAction( MapMode() ) );
634 if ( mbMap || !maMapMode.IsDefault() )
636 mbMap = false;
637 maMapMode = MapMode();
639 // create new objects (clip region are not re-scaled)
640 mbNewFont = true;
641 mbInitFont = true;
642 ImplInitMapModeObjects();
644 // #106426# Adapt logical offset when changing mapmode
645 mnOutOffLogicX = mnOutOffOrigX; // no mapping -> equal offsets
646 mnOutOffLogicY = mnOutOffOrigY;
648 // #i75163#
649 ImplInvalidateViewTransform();
652 if( mpAlphaVDev )
653 mpAlphaVDev->SetMapMode();
656 void OutputDevice::SetMapMode( const MapMode& rNewMapMode )
659 bool bRelMap = (rNewMapMode.GetMapUnit() == MapUnit::MapRelative);
661 if ( mpMetaFile )
663 mpMetaFile->AddAction( new MetaMapModeAction( rNewMapMode ) );
666 // do nothing if MapMode was not changed
667 if ( maMapMode == rNewMapMode )
668 return;
670 if( mpAlphaVDev )
671 mpAlphaVDev->SetMapMode( rNewMapMode );
673 // if default MapMode calculate nothing
674 bool bOldMap = mbMap;
675 mbMap = !rNewMapMode.IsDefault();
676 if ( mbMap )
678 // if only the origin is converted, do not scale new
679 if ( (rNewMapMode.GetMapUnit() == maMapMode.GetMapUnit()) &&
680 (rNewMapMode.GetScaleX() == maMapMode.GetScaleX()) &&
681 (rNewMapMode.GetScaleY() == maMapMode.GetScaleY()) &&
682 (bOldMap == mbMap) )
684 // set offset
685 Point aOrigin = rNewMapMode.GetOrigin();
686 maMapRes.mnMapOfsX = aOrigin.X();
687 maMapRes.mnMapOfsY = aOrigin.Y();
688 maMapMode = rNewMapMode;
690 // #i75163#
691 ImplInvalidateViewTransform();
693 return;
695 if ( !bOldMap && bRelMap )
697 maMapRes.mnMapScNumX = 1;
698 maMapRes.mnMapScNumY = 1;
699 maMapRes.mnMapScDenomX = mnDPIX;
700 maMapRes.mnMapScDenomY = mnDPIY;
701 maMapRes.mnMapOfsX = 0;
702 maMapRes.mnMapOfsY = 0;
705 // calculate new MapMode-resolution
706 ImplCalcMapResolution(rNewMapMode, mnDPIX, mnDPIY, maMapRes);
709 // set new MapMode
710 if (bRelMap)
712 maMapMode.SetScaleX(Fraction::MakeFraction(
713 maMapMode.GetScaleX().GetNumerator(), rNewMapMode.GetScaleX().GetNumerator(),
714 maMapMode.GetScaleX().GetDenominator(), rNewMapMode.GetScaleX().GetDenominator()));
716 maMapMode.SetScaleY(Fraction::MakeFraction(
717 maMapMode.GetScaleY().GetNumerator(), rNewMapMode.GetScaleY().GetNumerator(),
718 maMapMode.GetScaleY().GetDenominator(), rNewMapMode.GetScaleY().GetDenominator()));
720 maMapMode.SetOrigin(Point(maMapRes.mnMapOfsX, maMapRes.mnMapOfsY));
722 else
724 maMapMode = rNewMapMode;
727 // create new objects (clip region are not re-scaled)
728 mbNewFont = true;
729 mbInitFont = true;
730 ImplInitMapModeObjects();
732 // #106426# Adapt logical offset when changing mapmode
733 mnOutOffLogicX = ImplPixelToLogic( mnOutOffOrigX, mnDPIX,
734 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX );
735 mnOutOffLogicY = ImplPixelToLogic( mnOutOffOrigY, mnDPIY,
736 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY );
738 // #i75163#
739 ImplInvalidateViewTransform();
742 void OutputDevice::SetMetafileMapMode(const MapMode& rNewMapMode, bool bIsRecord)
744 if (bIsRecord)
745 SetRelativeMapMode(rNewMapMode);
746 else
747 SetMapMode(rNewMapMode);
750 void OutputDevice::ImplInitMapModeObjects() {}
752 void OutputDevice::SetRelativeMapMode( const MapMode& rNewMapMode )
754 // do nothing if MapMode did not change
755 if ( maMapMode == rNewMapMode )
756 return;
758 MapUnit eOld = maMapMode.GetMapUnit();
759 MapUnit eNew = rNewMapMode.GetMapUnit();
761 // a?F = rNewMapMode.GetScale?() / maMapMode.GetScale?()
762 Fraction aXF = Fraction::MakeFraction( rNewMapMode.GetScaleX().GetNumerator(),
763 maMapMode.GetScaleX().GetDenominator(),
764 rNewMapMode.GetScaleX().GetDenominator(),
765 maMapMode.GetScaleX().GetNumerator() );
766 Fraction aYF = Fraction::MakeFraction( rNewMapMode.GetScaleY().GetNumerator(),
767 maMapMode.GetScaleY().GetDenominator(),
768 rNewMapMode.GetScaleY().GetDenominator(),
769 maMapMode.GetScaleY().GetNumerator() );
771 Point aPt( LogicToLogic( Point(), nullptr, &rNewMapMode ) );
772 if ( eNew != eOld )
774 if ( eOld > MapUnit::MapPixel )
776 SAL_WARN( "vcl.gdi", "Not implemented MapUnit" );
778 else if ( eNew > MapUnit::MapPixel )
780 SAL_WARN( "vcl.gdi", "Not implemented MapUnit" );
782 else
784 const auto eFrom = MapToO3tlLength(eOld, o3tl::Length::in);
785 const auto eTo = MapToO3tlLength(eNew, o3tl::Length::in);
786 const auto [mul, div] = o3tl::getConversionMulDiv(eFrom, eTo);
787 Fraction aF(div, mul);
789 // a?F = a?F * aF
790 aXF = Fraction::MakeFraction( aXF.GetNumerator(), aF.GetNumerator(),
791 aXF.GetDenominator(), aF.GetDenominator() );
792 aYF = Fraction::MakeFraction( aYF.GetNumerator(), aF.GetNumerator(),
793 aYF.GetDenominator(), aF.GetDenominator() );
794 if ( eOld == MapUnit::MapPixel )
796 aXF *= Fraction( mnDPIX, 1 );
797 aYF *= Fraction( mnDPIY, 1 );
799 else if ( eNew == MapUnit::MapPixel )
801 aXF *= Fraction( 1, mnDPIX );
802 aYF *= Fraction( 1, mnDPIY );
807 MapMode aNewMapMode( MapUnit::MapRelative, Point( -aPt.X(), -aPt.Y() ), aXF, aYF );
808 SetMapMode( aNewMapMode );
810 if ( eNew != eOld )
811 maMapMode = rNewMapMode;
813 // #106426# Adapt logical offset when changing MapMode
814 mnOutOffLogicX = ImplPixelToLogic( mnOutOffOrigX, mnDPIX,
815 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX );
816 mnOutOffLogicY = ImplPixelToLogic( mnOutOffOrigY, mnDPIY,
817 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY );
819 if( mpAlphaVDev )
820 mpAlphaVDev->SetRelativeMapMode( rNewMapMode );
823 // #i75163#
824 basegfx::B2DHomMatrix OutputDevice::GetViewTransformation() const
826 if(mbMap && mpOutDevData)
828 if(!mpOutDevData->mpViewTransform)
830 mpOutDevData->mpViewTransform = new basegfx::B2DHomMatrix;
832 const double fScaleFactorX(static_cast<double>(mnDPIX) * static_cast<double>(maMapRes.mnMapScNumX) / static_cast<double>(maMapRes.mnMapScDenomX));
833 const double fScaleFactorY(static_cast<double>(mnDPIY) * static_cast<double>(maMapRes.mnMapScNumY) / static_cast<double>(maMapRes.mnMapScDenomY));
834 const double fZeroPointX((static_cast<double>(maMapRes.mnMapOfsX) * fScaleFactorX) + static_cast<double>(mnOutOffOrigX));
835 const double fZeroPointY((static_cast<double>(maMapRes.mnMapOfsY) * fScaleFactorY) + static_cast<double>(mnOutOffOrigY));
837 mpOutDevData->mpViewTransform->set(0, 0, fScaleFactorX);
838 mpOutDevData->mpViewTransform->set(1, 1, fScaleFactorY);
839 mpOutDevData->mpViewTransform->set(0, 2, fZeroPointX);
840 mpOutDevData->mpViewTransform->set(1, 2, fZeroPointY);
843 return *mpOutDevData->mpViewTransform;
845 else
847 return basegfx::B2DHomMatrix();
851 // #i75163#
852 basegfx::B2DHomMatrix OutputDevice::GetInverseViewTransformation() const
854 if(mbMap && mpOutDevData)
856 if(!mpOutDevData->mpInverseViewTransform)
858 GetViewTransformation();
859 mpOutDevData->mpInverseViewTransform = new basegfx::B2DHomMatrix(*mpOutDevData->mpViewTransform);
860 mpOutDevData->mpInverseViewTransform->invert();
863 return *mpOutDevData->mpInverseViewTransform;
865 else
867 return basegfx::B2DHomMatrix();
871 // #i75163#
872 basegfx::B2DHomMatrix OutputDevice::GetViewTransformation( const MapMode& rMapMode ) const
874 // #i82615#
875 ImplMapRes aMapRes;
876 ImplCalcMapResolution(rMapMode, mnDPIX, mnDPIY, aMapRes);
878 basegfx::B2DHomMatrix aTransform;
880 const double fScaleFactorX(static_cast<double>(mnDPIX) * static_cast<double>(aMapRes.mnMapScNumX) / static_cast<double>(aMapRes.mnMapScDenomX));
881 const double fScaleFactorY(static_cast<double>(mnDPIY) * static_cast<double>(aMapRes.mnMapScNumY) / static_cast<double>(aMapRes.mnMapScDenomY));
882 const double fZeroPointX((static_cast<double>(aMapRes.mnMapOfsX) * fScaleFactorX) + static_cast<double>(mnOutOffOrigX));
883 const double fZeroPointY((static_cast<double>(aMapRes.mnMapOfsY) * fScaleFactorY) + static_cast<double>(mnOutOffOrigY));
885 aTransform.set(0, 0, fScaleFactorX);
886 aTransform.set(1, 1, fScaleFactorY);
887 aTransform.set(0, 2, fZeroPointX);
888 aTransform.set(1, 2, fZeroPointY);
890 return aTransform;
893 // #i75163#
894 basegfx::B2DHomMatrix OutputDevice::GetInverseViewTransformation( const MapMode& rMapMode ) const
896 basegfx::B2DHomMatrix aMatrix( GetViewTransformation( rMapMode ) );
897 aMatrix.invert();
898 return aMatrix;
901 basegfx::B2DHomMatrix OutputDevice::ImplGetDeviceTransformation() const
903 basegfx::B2DHomMatrix aTransformation = GetViewTransformation();
904 // TODO: is it worth to cache the transformed result?
905 if( mnOutOffX || mnOutOffY )
906 aTransformation.translate( mnOutOffX, mnOutOffY );
907 return aTransformation;
910 Point OutputDevice::LogicToPixel( const Point& rLogicPt ) const
913 if ( !mbMap )
914 return rLogicPt;
916 return Point( ImplLogicToPixel( rLogicPt.X() + maMapRes.mnMapOfsX, mnDPIX,
917 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX )+mnOutOffOrigX,
918 ImplLogicToPixel( rLogicPt.Y() + maMapRes.mnMapOfsY, mnDPIY,
919 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY )+mnOutOffOrigY );
922 Size OutputDevice::LogicToPixel( const Size& rLogicSize ) const
925 if ( !mbMap )
926 return rLogicSize;
928 return Size( ImplLogicToPixel( rLogicSize.Width(), mnDPIX,
929 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX ),
930 ImplLogicToPixel( rLogicSize.Height(), mnDPIY,
931 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY ) );
934 tools::Rectangle OutputDevice::LogicToPixel( const tools::Rectangle& rLogicRect ) const
936 // tdf#141761 see comments above, IsEmpty() removed
937 if ( !mbMap )
938 return rLogicRect;
940 tools::Rectangle aRetval(
941 ImplLogicToPixel( rLogicRect.Left() + maMapRes.mnMapOfsX, mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX )+mnOutOffOrigX,
942 ImplLogicToPixel( rLogicRect.Top() + maMapRes.mnMapOfsY, mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY )+mnOutOffOrigY,
943 rLogicRect.IsWidthEmpty() ? 0 : ImplLogicToPixel( rLogicRect.Right() + maMapRes.mnMapOfsX, mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX )+mnOutOffOrigX,
944 rLogicRect.IsHeightEmpty() ? 0 : ImplLogicToPixel( rLogicRect.Bottom() + maMapRes.mnMapOfsY, mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY )+mnOutOffOrigY );
946 if(rLogicRect.IsWidthEmpty())
947 aRetval.SetWidthEmpty();
949 if(rLogicRect.IsHeightEmpty())
950 aRetval.SetHeightEmpty();
952 return aRetval;
955 tools::Polygon OutputDevice::LogicToPixel( const tools::Polygon& rLogicPoly ) const
958 if ( !mbMap )
959 return rLogicPoly;
961 sal_uInt16 i;
962 sal_uInt16 nPoints = rLogicPoly.GetSize();
963 tools::Polygon aPoly( rLogicPoly );
965 // get pointer to Point-array (copy data)
966 const Point* pPointAry = aPoly.GetConstPointAry();
968 for ( i = 0; i < nPoints; i++ )
970 const Point* pPt = &(pPointAry[i]);
971 Point aPt;
972 aPt.setX( ImplLogicToPixel( pPt->X() + maMapRes.mnMapOfsX, mnDPIX,
973 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX )+mnOutOffOrigX );
974 aPt.setY( ImplLogicToPixel( pPt->Y() + maMapRes.mnMapOfsY, mnDPIY,
975 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY )+mnOutOffOrigY );
976 aPoly[i] = aPt;
979 return aPoly;
982 tools::PolyPolygon OutputDevice::LogicToPixel( const tools::PolyPolygon& rLogicPolyPoly ) const
985 if ( !mbMap )
986 return rLogicPolyPoly;
988 tools::PolyPolygon aPolyPoly( rLogicPolyPoly );
989 sal_uInt16 nPoly = aPolyPoly.Count();
990 for( sal_uInt16 i = 0; i < nPoly; i++ )
992 tools::Polygon& rPoly = aPolyPoly[i];
993 rPoly = LogicToPixel( rPoly );
995 return aPolyPoly;
998 basegfx::B2DPolyPolygon OutputDevice::LogicToPixel( const basegfx::B2DPolyPolygon& rLogicPolyPoly ) const
1000 basegfx::B2DPolyPolygon aTransformedPoly = rLogicPolyPoly;
1001 const basegfx::B2DHomMatrix aTransformationMatrix = GetViewTransformation();
1002 aTransformedPoly.transform( aTransformationMatrix );
1003 return aTransformedPoly;
1006 vcl::Region OutputDevice::LogicToPixel( const vcl::Region& rLogicRegion ) const
1009 if(!mbMap || rLogicRegion.IsNull() || rLogicRegion.IsEmpty())
1011 return rLogicRegion;
1014 vcl::Region aRegion;
1016 if(rLogicRegion.getB2DPolyPolygon())
1018 aRegion = vcl::Region(LogicToPixel(*rLogicRegion.getB2DPolyPolygon()));
1020 else if(rLogicRegion.getPolyPolygon())
1022 aRegion = vcl::Region(LogicToPixel(*rLogicRegion.getPolyPolygon()));
1024 else if(rLogicRegion.getRegionBand())
1026 RectangleVector aRectangles;
1027 rLogicRegion.GetRegionRectangles(aRectangles);
1028 const RectangleVector& rRectangles(aRectangles); // needed to make the '!=' work
1030 // make reverse run to fill new region bottom-up, this will speed it up due to the used data structuring
1031 for(RectangleVector::const_reverse_iterator aRectIter(rRectangles.rbegin()); aRectIter != rRectangles.rend(); ++aRectIter)
1033 aRegion.Union(LogicToPixel(*aRectIter));
1037 return aRegion;
1040 Point OutputDevice::LogicToPixel( const Point& rLogicPt,
1041 const MapMode& rMapMode ) const
1044 if ( rMapMode.IsDefault() )
1045 return rLogicPt;
1047 // convert MapMode resolution and convert
1048 ImplMapRes aMapRes;
1049 ImplCalcMapResolution(rMapMode, mnDPIX, mnDPIY, aMapRes);
1051 return Point( ImplLogicToPixel( rLogicPt.X() + aMapRes.mnMapOfsX, mnDPIX,
1052 aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX )+mnOutOffOrigX,
1053 ImplLogicToPixel( rLogicPt.Y() + aMapRes.mnMapOfsY, mnDPIY,
1054 aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY )+mnOutOffOrigY );
1057 Size OutputDevice::LogicToPixel( const Size& rLogicSize,
1058 const MapMode& rMapMode ) const
1061 if ( rMapMode.IsDefault() )
1062 return rLogicSize;
1064 // convert MapMode resolution and convert
1065 ImplMapRes aMapRes;
1066 ImplCalcMapResolution(rMapMode, mnDPIX, mnDPIY, aMapRes);
1068 return Size( ImplLogicToPixel( rLogicSize.Width(), mnDPIX,
1069 aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX ),
1070 ImplLogicToPixel( rLogicSize.Height(), mnDPIY,
1071 aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY ) );
1074 tools::Rectangle OutputDevice::LogicToPixel( const tools::Rectangle& rLogicRect,
1075 const MapMode& rMapMode ) const
1077 // tdf#141761 see comments above, IsEmpty() removed
1078 if ( rMapMode.IsDefault() )
1079 return rLogicRect;
1081 // convert MapMode resolution and convert
1082 ImplMapRes aMapRes;
1083 ImplCalcMapResolution(rMapMode, mnDPIX, mnDPIY, aMapRes);
1085 tools::Rectangle aRetval(
1086 ImplLogicToPixel( rLogicRect.Left() + aMapRes.mnMapOfsX, mnDPIX, aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX )+mnOutOffOrigX,
1087 ImplLogicToPixel( rLogicRect.Top() + aMapRes.mnMapOfsY, mnDPIY, aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY )+mnOutOffOrigY,
1088 rLogicRect.IsWidthEmpty() ? 0 : ImplLogicToPixel( rLogicRect.Right() + aMapRes.mnMapOfsX, mnDPIX, aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX )+mnOutOffOrigX,
1089 rLogicRect.IsHeightEmpty() ? 0 : ImplLogicToPixel( rLogicRect.Bottom() + aMapRes.mnMapOfsY, mnDPIY, aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY )+mnOutOffOrigY );
1091 if(rLogicRect.IsWidthEmpty())
1092 aRetval.SetWidthEmpty();
1094 if(rLogicRect.IsHeightEmpty())
1095 aRetval.SetHeightEmpty();
1097 return aRetval;
1100 tools::Polygon OutputDevice::LogicToPixel( const tools::Polygon& rLogicPoly,
1101 const MapMode& rMapMode ) const
1104 if ( rMapMode.IsDefault() )
1105 return rLogicPoly;
1107 // convert MapMode resolution and convert
1108 ImplMapRes aMapRes;
1109 ImplCalcMapResolution(rMapMode, mnDPIX, mnDPIY, aMapRes);
1111 sal_uInt16 i;
1112 sal_uInt16 nPoints = rLogicPoly.GetSize();
1113 tools::Polygon aPoly( rLogicPoly );
1115 // get pointer to Point-array (copy data)
1116 const Point* pPointAry = aPoly.GetConstPointAry();
1118 for ( i = 0; i < nPoints; i++ )
1120 const Point* pPt = &(pPointAry[i]);
1121 Point aPt;
1122 aPt.setX( ImplLogicToPixel( pPt->X() + aMapRes.mnMapOfsX, mnDPIX,
1123 aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX )+mnOutOffOrigX );
1124 aPt.setY( ImplLogicToPixel( pPt->Y() + aMapRes.mnMapOfsY, mnDPIY,
1125 aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY )+mnOutOffOrigY );
1126 aPoly[i] = aPt;
1129 return aPoly;
1132 basegfx::B2DPolyPolygon OutputDevice::LogicToPixel( const basegfx::B2DPolyPolygon& rLogicPolyPoly,
1133 const MapMode& rMapMode ) const
1135 basegfx::B2DPolyPolygon aTransformedPoly = rLogicPolyPoly;
1136 const basegfx::B2DHomMatrix aTransformationMatrix = GetViewTransformation( rMapMode );
1137 aTransformedPoly.transform( aTransformationMatrix );
1138 return aTransformedPoly;
1141 Point OutputDevice::PixelToLogic( const Point& rDevicePt ) const
1144 if ( !mbMap )
1145 return rDevicePt;
1147 return Point( ImplPixelToLogic( rDevicePt.X(), mnDPIX,
1148 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX ) - maMapRes.mnMapOfsX - mnOutOffLogicX,
1149 ImplPixelToLogic( rDevicePt.Y(), mnDPIY,
1150 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY ) - maMapRes.mnMapOfsY - mnOutOffLogicY );
1153 Point OutputDevice::SubPixelToLogic(const basegfx::B2DPoint& rDevicePt) const
1155 if (!mbMap)
1157 assert(floor(rDevicePt.getX() == rDevicePt.getX()) && floor(rDevicePt.getY() == rDevicePt.getY()));
1158 return Point(rDevicePt.getX(), rDevicePt.getY());
1161 return Point(ImplSubPixelToLogic(rDevicePt.getX(), mnDPIX,
1162 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX) - maMapRes.mnMapOfsX - mnOutOffLogicX,
1163 ImplSubPixelToLogic(rDevicePt.getY(), mnDPIY,
1164 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY) - maMapRes.mnMapOfsY - mnOutOffLogicY);
1167 Size OutputDevice::PixelToLogic( const Size& rDeviceSize ) const
1170 if ( !mbMap )
1171 return rDeviceSize;
1173 return Size( ImplPixelToLogic( rDeviceSize.Width(), mnDPIX,
1174 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX ),
1175 ImplPixelToLogic( rDeviceSize.Height(), mnDPIY,
1176 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY ) );
1179 tools::Rectangle OutputDevice::PixelToLogic( const tools::Rectangle& rDeviceRect ) const
1181 // tdf#141761 see comments above, IsEmpty() removed
1182 if ( !mbMap )
1183 return rDeviceRect;
1185 tools::Rectangle aRetval(
1186 ImplPixelToLogic( rDeviceRect.Left(), mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX ) - maMapRes.mnMapOfsX - mnOutOffLogicX,
1187 ImplPixelToLogic( rDeviceRect.Top(), mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY ) - maMapRes.mnMapOfsY - mnOutOffLogicY,
1188 rDeviceRect.IsWidthEmpty() ? 0 : ImplPixelToLogic( rDeviceRect.Right(), mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX ) - maMapRes.mnMapOfsX - mnOutOffLogicX,
1189 rDeviceRect.IsHeightEmpty() ? 0 : ImplPixelToLogic( rDeviceRect.Bottom(), mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY ) - maMapRes.mnMapOfsY - mnOutOffLogicY );
1191 if(rDeviceRect.IsWidthEmpty())
1192 aRetval.SetWidthEmpty();
1194 if(rDeviceRect.IsHeightEmpty())
1195 aRetval.SetHeightEmpty();
1197 return aRetval;
1200 tools::Polygon OutputDevice::PixelToLogic( const tools::Polygon& rDevicePoly ) const
1203 if ( !mbMap )
1204 return rDevicePoly;
1206 sal_uInt16 i;
1207 sal_uInt16 nPoints = rDevicePoly.GetSize();
1208 tools::Polygon aPoly( rDevicePoly );
1210 // get pointer to Point-array (copy data)
1211 const Point* pPointAry = aPoly.GetConstPointAry();
1213 for ( i = 0; i < nPoints; i++ )
1215 const Point* pPt = &(pPointAry[i]);
1216 Point aPt;
1217 aPt.setX( ImplPixelToLogic( pPt->X(), mnDPIX,
1218 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX ) - maMapRes.mnMapOfsX - mnOutOffLogicX );
1219 aPt.setY( ImplPixelToLogic( pPt->Y(), mnDPIY,
1220 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY ) - maMapRes.mnMapOfsY - mnOutOffLogicY );
1221 aPoly[i] = aPt;
1224 return aPoly;
1227 tools::PolyPolygon OutputDevice::PixelToLogic( const tools::PolyPolygon& rDevicePolyPoly ) const
1230 if ( !mbMap )
1231 return rDevicePolyPoly;
1233 tools::PolyPolygon aPolyPoly( rDevicePolyPoly );
1234 sal_uInt16 nPoly = aPolyPoly.Count();
1235 for( sal_uInt16 i = 0; i < nPoly; i++ )
1237 tools::Polygon& rPoly = aPolyPoly[i];
1238 rPoly = PixelToLogic( rPoly );
1240 return aPolyPoly;
1243 basegfx::B2DPolyPolygon OutputDevice::PixelToLogic( const basegfx::B2DPolyPolygon& rPixelPolyPoly ) const
1245 basegfx::B2DPolyPolygon aTransformedPoly = rPixelPolyPoly;
1246 const basegfx::B2DHomMatrix aTransformationMatrix = GetInverseViewTransformation();
1247 aTransformedPoly.transform( aTransformationMatrix );
1248 return aTransformedPoly;
1251 basegfx::B2DRectangle OutputDevice::PixelToLogic(const basegfx::B2DRectangle& rDeviceRect) const
1253 basegfx::B2DRectangle aTransformedRect = rDeviceRect;
1254 const basegfx::B2DHomMatrix aTransformationMatrix = GetInverseViewTransformation();
1255 aTransformedRect.transform(aTransformationMatrix);
1256 return aTransformedRect;
1259 vcl::Region OutputDevice::PixelToLogic( const vcl::Region& rDeviceRegion ) const
1262 if(!mbMap || rDeviceRegion.IsNull() || rDeviceRegion.IsEmpty())
1264 return rDeviceRegion;
1267 vcl::Region aRegion;
1269 if(rDeviceRegion.getB2DPolyPolygon())
1271 aRegion = vcl::Region(PixelToLogic(*rDeviceRegion.getB2DPolyPolygon()));
1273 else if(rDeviceRegion.getPolyPolygon())
1275 aRegion = vcl::Region(PixelToLogic(*rDeviceRegion.getPolyPolygon()));
1277 else if(rDeviceRegion.getRegionBand())
1279 RectangleVector aRectangles;
1280 rDeviceRegion.GetRegionRectangles(aRectangles);
1281 const RectangleVector& rRectangles(aRectangles); // needed to make the '!=' work
1283 // make reverse run to fill new region bottom-up, this will speed it up due to the used data structuring
1284 for(RectangleVector::const_reverse_iterator aRectIter(rRectangles.rbegin()); aRectIter != rRectangles.rend(); ++aRectIter)
1286 aRegion.Union(PixelToLogic(*aRectIter));
1290 return aRegion;
1293 Point OutputDevice::PixelToLogic( const Point& rDevicePt,
1294 const MapMode& rMapMode ) const
1297 // calculate nothing if default-MapMode
1298 if ( rMapMode.IsDefault() )
1299 return rDevicePt;
1301 // calculate MapMode-resolution and convert
1302 ImplMapRes aMapRes;
1303 ImplCalcMapResolution(rMapMode, mnDPIX, mnDPIY, aMapRes);
1305 return Point( ImplPixelToLogic( rDevicePt.X(), mnDPIX,
1306 aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX ) - aMapRes.mnMapOfsX - mnOutOffLogicX,
1307 ImplPixelToLogic( rDevicePt.Y(), mnDPIY,
1308 aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY ) - aMapRes.mnMapOfsY - mnOutOffLogicY );
1311 Size OutputDevice::PixelToLogic( const Size& rDeviceSize,
1312 const MapMode& rMapMode ) const
1315 // calculate nothing if default-MapMode
1316 if ( rMapMode.IsDefault() )
1317 return rDeviceSize;
1319 // calculate MapMode-resolution and convert
1320 ImplMapRes aMapRes;
1321 ImplCalcMapResolution(rMapMode, mnDPIX, mnDPIY, aMapRes);
1323 return Size( ImplPixelToLogic( rDeviceSize.Width(), mnDPIX,
1324 aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX ),
1325 ImplPixelToLogic( rDeviceSize.Height(), mnDPIY,
1326 aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY ) );
1329 tools::Rectangle OutputDevice::PixelToLogic( const tools::Rectangle& rDeviceRect,
1330 const MapMode& rMapMode ) const
1332 // calculate nothing if default-MapMode
1333 // tdf#141761 see comments above, IsEmpty() removed
1334 if ( rMapMode.IsDefault() )
1335 return rDeviceRect;
1337 // calculate MapMode-resolution and convert
1338 ImplMapRes aMapRes;
1339 ImplCalcMapResolution(rMapMode, mnDPIX, mnDPIY, aMapRes);
1341 tools::Rectangle aRetval(
1342 ImplPixelToLogic( rDeviceRect.Left(), mnDPIX, aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX ) - aMapRes.mnMapOfsX - mnOutOffLogicX,
1343 ImplPixelToLogic( rDeviceRect.Top(), mnDPIY, aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY ) - aMapRes.mnMapOfsY - mnOutOffLogicY,
1344 rDeviceRect.IsWidthEmpty() ? 0 : ImplPixelToLogic( rDeviceRect.Right(), mnDPIX, aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX ) - aMapRes.mnMapOfsX - mnOutOffLogicX,
1345 rDeviceRect.IsHeightEmpty() ? 0 : ImplPixelToLogic( rDeviceRect.Bottom(), mnDPIY, aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY ) - aMapRes.mnMapOfsY - mnOutOffLogicY );
1347 if(rDeviceRect.IsWidthEmpty())
1348 aRetval.SetWidthEmpty();
1350 if(rDeviceRect.IsHeightEmpty())
1351 aRetval.SetHeightEmpty();
1353 return aRetval;
1356 tools::Polygon OutputDevice::PixelToLogic( const tools::Polygon& rDevicePoly,
1357 const MapMode& rMapMode ) const
1360 // calculate nothing if default-MapMode
1361 if ( rMapMode.IsDefault() )
1362 return rDevicePoly;
1364 // calculate MapMode-resolution and convert
1365 ImplMapRes aMapRes;
1366 ImplCalcMapResolution(rMapMode, mnDPIX, mnDPIY, aMapRes);
1368 sal_uInt16 i;
1369 sal_uInt16 nPoints = rDevicePoly.GetSize();
1370 tools::Polygon aPoly( rDevicePoly );
1372 // get pointer to Point-array (copy data)
1373 const Point* pPointAry = aPoly.GetConstPointAry();
1375 for ( i = 0; i < nPoints; i++ )
1377 const Point* pPt = &(pPointAry[i]);
1378 Point aPt;
1379 aPt.setX( ImplPixelToLogic( pPt->X(), mnDPIX,
1380 aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX ) - aMapRes.mnMapOfsX - mnOutOffLogicX );
1381 aPt.setY( ImplPixelToLogic( pPt->Y(), mnDPIY,
1382 aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY ) - aMapRes.mnMapOfsY - mnOutOffLogicY );
1383 aPoly[i] = aPt;
1386 return aPoly;
1389 basegfx::B2DPolygon OutputDevice::PixelToLogic( const basegfx::B2DPolygon& rPixelPoly,
1390 const MapMode& rMapMode ) const
1392 basegfx::B2DPolygon aTransformedPoly = rPixelPoly;
1393 const basegfx::B2DHomMatrix aTransformationMatrix = GetInverseViewTransformation( rMapMode );
1394 aTransformedPoly.transform( aTransformationMatrix );
1395 return aTransformedPoly;
1398 basegfx::B2DPolyPolygon OutputDevice::PixelToLogic( const basegfx::B2DPolyPolygon& rPixelPolyPoly,
1399 const MapMode& rMapMode ) const
1401 basegfx::B2DPolyPolygon aTransformedPoly = rPixelPolyPoly;
1402 const basegfx::B2DHomMatrix aTransformationMatrix = GetInverseViewTransformation( rMapMode );
1403 aTransformedPoly.transform( aTransformationMatrix );
1404 return aTransformedPoly;
1407 #define ENTER1( rSource, pMapModeSource, pMapModeDest ) \
1408 if ( !pMapModeSource ) \
1409 pMapModeSource = &maMapMode; \
1410 if ( !pMapModeDest ) \
1411 pMapModeDest = &maMapMode; \
1412 if ( *pMapModeSource == *pMapModeDest ) \
1413 return rSource; \
1415 ImplMapRes aMapResSource; \
1416 ImplMapRes aMapResDest; \
1418 if ( !mbMap || pMapModeSource != &maMapMode ) \
1420 if ( pMapModeSource->GetMapUnit() == MapUnit::MapRelative ) \
1421 aMapResSource = maMapRes; \
1422 ImplCalcMapResolution( *pMapModeSource, \
1423 mnDPIX, mnDPIY, aMapResSource ); \
1425 else \
1426 aMapResSource = maMapRes; \
1427 if ( !mbMap || pMapModeDest != &maMapMode ) \
1429 if ( pMapModeDest->GetMapUnit() == MapUnit::MapRelative ) \
1430 aMapResDest = maMapRes; \
1431 ImplCalcMapResolution( *pMapModeDest, \
1432 mnDPIX, mnDPIY, aMapResDest ); \
1434 else \
1435 aMapResDest = maMapRes
1437 static void verifyUnitSourceDest( MapUnit eUnitSource, MapUnit eUnitDest )
1439 DBG_ASSERT( eUnitSource != MapUnit::MapSysFont
1440 && eUnitSource != MapUnit::MapAppFont
1441 && eUnitSource != MapUnit::MapRelative,
1442 "Source MapUnit is not permitted" );
1443 DBG_ASSERT( eUnitDest != MapUnit::MapSysFont
1444 && eUnitDest != MapUnit::MapAppFont
1445 && eUnitDest != MapUnit::MapRelative,
1446 "Destination MapUnit is not permitted" );
1449 namespace
1451 auto getCorrectedUnit(MapUnit eMapSrc, MapUnit eMapDst)
1453 o3tl::Length eSrc = o3tl::Length::invalid;
1454 o3tl::Length eDst = o3tl::Length::invalid;
1455 if (eMapSrc > MapUnit::MapPixel)
1456 SAL_WARN("vcl.gdi", "Invalid source map unit");
1457 else if (eMapDst > MapUnit::MapPixel)
1458 SAL_WARN("vcl.gdi", "Invalid destination map unit");
1459 else if (eMapSrc != eMapDst)
1461 // Here 72 PPI is assumed for MapPixel
1462 eSrc = MapToO3tlLength(eMapSrc, o3tl::Length::pt);
1463 eDst = MapToO3tlLength(eMapDst, o3tl::Length::pt);
1465 return std::make_pair(eSrc, eDst);
1468 std::pair<ImplMapRes, ImplMapRes> ENTER4(const MapMode& rMMSource, const MapMode& rMMDest)
1470 std::pair<ImplMapRes, ImplMapRes> result;
1471 ImplCalcMapResolution(rMMSource, 72, 72, result.first);
1472 ImplCalcMapResolution(rMMDest, 72, 72, result.second);
1473 return result;
1477 // return (n1 * n2 * n3) / (n4 * n5)
1478 static tools::Long fn5( const tools::Long n1,
1479 const tools::Long n2,
1480 const tools::Long n3,
1481 const tools::Long n4,
1482 const tools::Long n5 )
1484 if ( n1 == 0 || n2 == 0 || n3 == 0 || n4 == 0 || n5 == 0 )
1485 return 0;
1486 if (std::numeric_limits<tools::Long>::max() / std::abs(n2) < std::abs(n3))
1488 // a6 is skipped
1489 BigInt a7 = n2;
1490 a7 *= n3;
1491 a7 *= n1;
1493 if (std::numeric_limits<tools::Long>::max() / std::abs(n4) < std::abs(n5))
1495 BigInt a8 = n4;
1496 a8 *= n5;
1498 BigInt a9 = a8;
1499 a9 /= 2;
1500 if ( a7.IsNeg() )
1501 a7 -= a9;
1502 else
1503 a7 += a9;
1505 a7 /= a8;
1506 } // of if
1507 else
1509 tools::Long n8 = n4 * n5;
1511 if ( a7.IsNeg() )
1512 a7 -= n8 / 2;
1513 else
1514 a7 += n8 / 2;
1516 a7 /= n8;
1517 } // of else
1518 return static_cast<tools::Long>(a7);
1519 } // of if
1520 else
1522 tools::Long n6 = n2 * n3;
1524 if (std::numeric_limits<tools::Long>::max() / std::abs(n1) < std::abs(n6))
1526 BigInt a7 = n1;
1527 a7 *= n6;
1529 if (std::numeric_limits<tools::Long>::max() / std::abs(n4) < std::abs(n5))
1531 BigInt a8 = n4;
1532 a8 *= n5;
1534 BigInt a9 = a8;
1535 a9 /= 2;
1536 if ( a7.IsNeg() )
1537 a7 -= a9;
1538 else
1539 a7 += a9;
1541 a7 /= a8;
1542 } // of if
1543 else
1545 tools::Long n8 = n4 * n5;
1547 if ( a7.IsNeg() )
1548 a7 -= n8 / 2;
1549 else
1550 a7 += n8 / 2;
1552 a7 /= n8;
1553 } // of else
1554 return static_cast<tools::Long>(a7);
1555 } // of if
1556 else
1558 tools::Long n7 = n1 * n6;
1560 if (std::numeric_limits<tools::Long>::max() / std::abs(n4) < std::abs(n5))
1562 BigInt a7 = n7;
1563 BigInt a8 = n4;
1564 a8 *= n5;
1566 BigInt a9 = a8;
1567 a9 /= 2;
1568 if ( a7.IsNeg() )
1569 a7 -= a9;
1570 else
1571 a7 += a9;
1573 a7 /= a8;
1574 return static_cast<tools::Long>(a7);
1575 } // of if
1576 else
1578 const tools::Long n8 = n4 * n5;
1579 const tools::Long n8_2 = n8 / 2;
1581 if( n7 < 0 )
1583 if ((n7 - std::numeric_limits<tools::Long>::min()) >= n8_2)
1584 n7 -= n8_2;
1586 else if ((std::numeric_limits<tools::Long>::max() - n7) >= n8_2)
1587 n7 += n8_2;
1589 return n7 / n8;
1590 } // of else
1591 } // of else
1592 } // of else
1595 static tools::Long fn3(const tools::Long n1, const o3tl::Length eFrom, const o3tl::Length eTo)
1597 if (n1 == 0 || eFrom == o3tl::Length::invalid || eTo == o3tl::Length::invalid)
1598 return 0;
1599 bool bOverflow;
1600 const auto nResult = o3tl::convert(n1, eFrom, eTo, bOverflow);
1601 if (bOverflow)
1603 const auto [n2, n3] = o3tl::getConversionMulDiv(eFrom, eTo);
1604 BigInt a4 = n1;
1605 a4 *= n2;
1607 if ( a4.IsNeg() )
1608 a4 -= n3 / 2;
1609 else
1610 a4 += n3 / 2;
1612 a4 /= n3;
1613 return static_cast<tools::Long>(a4);
1614 } // of if
1615 else
1616 return nResult;
1619 Point OutputDevice::LogicToLogic( const Point& rPtSource,
1620 const MapMode* pMapModeSource,
1621 const MapMode* pMapModeDest ) const
1623 ENTER1( rPtSource, pMapModeSource, pMapModeDest );
1625 return Point( fn5( rPtSource.X() + aMapResSource.mnMapOfsX,
1626 aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX,
1627 aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) -
1628 aMapResDest.mnMapOfsX,
1629 fn5( rPtSource.Y() + aMapResSource.mnMapOfsY,
1630 aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY,
1631 aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) -
1632 aMapResDest.mnMapOfsY );
1635 Size OutputDevice::LogicToLogic( const Size& rSzSource,
1636 const MapMode* pMapModeSource,
1637 const MapMode* pMapModeDest ) const
1639 ENTER1( rSzSource, pMapModeSource, pMapModeDest );
1641 return Size( fn5( rSzSource.Width(),
1642 aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX,
1643 aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ),
1644 fn5( rSzSource.Height(),
1645 aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY,
1646 aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) );
1649 tools::Rectangle OutputDevice::LogicToLogic( const tools::Rectangle& rRectSource,
1650 const MapMode* pMapModeSource,
1651 const MapMode* pMapModeDest ) const
1653 ENTER1( rRectSource, pMapModeSource, pMapModeDest );
1655 return tools::Rectangle( fn5( rRectSource.Left() + aMapResSource.mnMapOfsX,
1656 aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX,
1657 aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) -
1658 aMapResDest.mnMapOfsX,
1659 fn5( rRectSource.Top() + aMapResSource.mnMapOfsY,
1660 aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY,
1661 aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) -
1662 aMapResDest.mnMapOfsY,
1663 fn5( rRectSource.Right() + aMapResSource.mnMapOfsX,
1664 aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX,
1665 aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) -
1666 aMapResDest.mnMapOfsX,
1667 fn5( rRectSource.Bottom() + aMapResSource.mnMapOfsY,
1668 aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY,
1669 aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) -
1670 aMapResDest.mnMapOfsY );
1673 Point OutputDevice::LogicToLogic( const Point& rPtSource,
1674 const MapMode& rMapModeSource,
1675 const MapMode& rMapModeDest )
1677 if ( rMapModeSource == rMapModeDest )
1678 return rPtSource;
1680 MapUnit eUnitSource = rMapModeSource.GetMapUnit();
1681 MapUnit eUnitDest = rMapModeDest.GetMapUnit();
1682 verifyUnitSourceDest( eUnitSource, eUnitDest );
1684 if (rMapModeSource.IsSimple() && rMapModeDest.IsSimple())
1686 const auto [eFrom, eTo] = getCorrectedUnit(eUnitSource, eUnitDest);
1687 return Point(fn3(rPtSource.X(), eFrom, eTo), fn3(rPtSource.Y(), eFrom, eTo));
1689 else
1691 const auto [aMapResSource, aMapResDest] = ENTER4( rMapModeSource, rMapModeDest );
1693 return Point( fn5( rPtSource.X() + aMapResSource.mnMapOfsX,
1694 aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX,
1695 aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) -
1696 aMapResDest.mnMapOfsX,
1697 fn5( rPtSource.Y() + aMapResSource.mnMapOfsY,
1698 aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY,
1699 aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) -
1700 aMapResDest.mnMapOfsY );
1704 Size OutputDevice::LogicToLogic( const Size& rSzSource,
1705 const MapMode& rMapModeSource,
1706 const MapMode& rMapModeDest )
1708 if ( rMapModeSource == rMapModeDest )
1709 return rSzSource;
1711 MapUnit eUnitSource = rMapModeSource.GetMapUnit();
1712 MapUnit eUnitDest = rMapModeDest.GetMapUnit();
1713 verifyUnitSourceDest( eUnitSource, eUnitDest );
1715 if (rMapModeSource.IsSimple() && rMapModeDest.IsSimple())
1717 const auto [eFrom, eTo] = getCorrectedUnit(eUnitSource, eUnitDest);
1718 return Size(fn3(rSzSource.Width(), eFrom, eTo), fn3(rSzSource.Height(), eFrom, eTo));
1720 else
1722 const auto [aMapResSource, aMapResDest] = ENTER4( rMapModeSource, rMapModeDest );
1724 return Size( fn5( rSzSource.Width(),
1725 aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX,
1726 aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ),
1727 fn5( rSzSource.Height(),
1728 aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY,
1729 aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) );
1733 basegfx::B2DPolygon OutputDevice::LogicToLogic( const basegfx::B2DPolygon& rPolySource,
1734 const MapMode& rMapModeSource,
1735 const MapMode& rMapModeDest )
1737 if(rMapModeSource == rMapModeDest)
1739 return rPolySource;
1742 const basegfx::B2DHomMatrix aTransform(LogicToLogic(rMapModeSource, rMapModeDest));
1743 basegfx::B2DPolygon aPoly(rPolySource);
1745 aPoly.transform(aTransform);
1746 return aPoly;
1749 basegfx::B2DHomMatrix OutputDevice::LogicToLogic(const MapMode& rMapModeSource, const MapMode& rMapModeDest)
1751 basegfx::B2DHomMatrix aTransform;
1753 if(rMapModeSource == rMapModeDest)
1755 return aTransform;
1758 MapUnit eUnitSource = rMapModeSource.GetMapUnit();
1759 MapUnit eUnitDest = rMapModeDest.GetMapUnit();
1760 verifyUnitSourceDest(eUnitSource, eUnitDest);
1762 if (rMapModeSource.IsSimple() && rMapModeDest.IsSimple())
1764 const auto [eFrom, eTo] = getCorrectedUnit(eUnitSource, eUnitDest);
1765 const double fScaleFactor(eFrom == o3tl::Length::invalid || eTo == o3tl::Length::invalid
1766 ? std::numeric_limits<double>::quiet_NaN()
1767 : o3tl::convert(1.0, eFrom, eTo));
1768 aTransform.set(0, 0, fScaleFactor);
1769 aTransform.set(1, 1, fScaleFactor);
1771 else
1773 const auto [aMapResSource, aMapResDest] = ENTER4(rMapModeSource, rMapModeDest);
1775 const double fScaleFactorX((double(aMapResSource.mnMapScNumX) * double(aMapResDest.mnMapScDenomX)) / (double(aMapResSource.mnMapScDenomX) * double(aMapResDest.mnMapScNumX)));
1776 const double fScaleFactorY((double(aMapResSource.mnMapScNumY) * double(aMapResDest.mnMapScDenomY)) / (double(aMapResSource.mnMapScDenomY) * double(aMapResDest.mnMapScNumY)));
1777 const double fZeroPointX(double(aMapResSource.mnMapOfsX) * fScaleFactorX - double(aMapResDest.mnMapOfsX));
1778 const double fZeroPointY(double(aMapResSource.mnMapOfsY) * fScaleFactorY - double(aMapResDest.mnMapOfsY));
1780 aTransform.set(0, 0, fScaleFactorX);
1781 aTransform.set(1, 1, fScaleFactorY);
1782 aTransform.set(0, 2, fZeroPointX);
1783 aTransform.set(1, 2, fZeroPointY);
1786 return aTransform;
1789 tools::Rectangle OutputDevice::LogicToLogic( const tools::Rectangle& rRectSource,
1790 const MapMode& rMapModeSource,
1791 const MapMode& rMapModeDest )
1793 if ( rMapModeSource == rMapModeDest )
1794 return rRectSource;
1796 MapUnit eUnitSource = rMapModeSource.GetMapUnit();
1797 MapUnit eUnitDest = rMapModeDest.GetMapUnit();
1798 verifyUnitSourceDest( eUnitSource, eUnitDest );
1800 tools::Rectangle aRetval;
1802 if (rMapModeSource.IsSimple() && rMapModeDest.IsSimple())
1804 const auto [eFrom, eTo] = getCorrectedUnit(eUnitSource, eUnitDest);
1806 auto left = fn3(rRectSource.Left(), eFrom, eTo);
1807 auto top = fn3(rRectSource.Top(), eFrom, eTo);
1809 // tdf#141761 see comments above, IsEmpty() removed
1810 auto right = rRectSource.IsWidthEmpty() ? 0 : fn3(rRectSource.Right(), eFrom, eTo);
1811 auto bottom = rRectSource.IsHeightEmpty() ? 0 : fn3(rRectSource.Bottom(), eFrom, eTo);
1813 aRetval = tools::Rectangle(left, top, right, bottom);
1815 else
1817 const auto [aMapResSource, aMapResDest] = ENTER4( rMapModeSource, rMapModeDest );
1819 auto left = fn5( rRectSource.Left() + aMapResSource.mnMapOfsX,
1820 aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX,
1821 aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) -
1822 aMapResDest.mnMapOfsX;
1823 auto top = fn5( rRectSource.Top() + aMapResSource.mnMapOfsY,
1824 aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY,
1825 aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) -
1826 aMapResDest.mnMapOfsY;
1828 // tdf#141761 see comments above, IsEmpty() removed
1829 auto right = rRectSource.IsWidthEmpty() ? 0 : fn5( rRectSource.Right() + aMapResSource.mnMapOfsX,
1830 aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX,
1831 aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) -
1832 aMapResDest.mnMapOfsX;
1833 auto bottom = rRectSource.IsHeightEmpty() ? 0 : fn5( rRectSource.Bottom() + aMapResSource.mnMapOfsY,
1834 aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY,
1835 aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) -
1836 aMapResDest.mnMapOfsY;
1838 aRetval = tools::Rectangle(left, top, right, bottom);
1841 if(rRectSource.IsWidthEmpty())
1842 aRetval.SetWidthEmpty();
1844 if(rRectSource.IsHeightEmpty())
1845 aRetval.SetHeightEmpty();
1847 return aRetval;
1850 tools::Long OutputDevice::LogicToLogic( tools::Long nLongSource,
1851 MapUnit eUnitSource, MapUnit eUnitDest )
1853 if ( eUnitSource == eUnitDest )
1854 return nLongSource;
1856 verifyUnitSourceDest( eUnitSource, eUnitDest );
1857 const auto [eFrom, eTo] = getCorrectedUnit(eUnitSource, eUnitDest);
1858 return fn3(nLongSource, eFrom, eTo);
1861 void OutputDevice::SetPixelOffset( const Size& rOffset )
1863 mnOutOffOrigX = rOffset.Width();
1864 mnOutOffOrigY = rOffset.Height();
1866 mnOutOffLogicX = ImplPixelToLogic( mnOutOffOrigX, mnDPIX,
1867 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX );
1868 mnOutOffLogicY = ImplPixelToLogic( mnOutOffOrigY, mnDPIY,
1869 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY );
1871 if( mpAlphaVDev )
1872 mpAlphaVDev->SetPixelOffset( rOffset );
1876 double OutputDevice::ImplLogicWidthToDeviceSubPixel(tools::Long nWidth) const
1878 if (!mbMap)
1879 return nWidth;
1881 return ImplLogicToSubPixel(nWidth, mnDPIX,
1882 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX);
1885 double OutputDevice::ImplLogicHeightToDeviceSubPixel(tools::Long nHeight) const
1887 if (!mbMap)
1888 return nHeight;
1890 return ImplLogicToSubPixel(nHeight, mnDPIY,
1891 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY);
1894 basegfx::B2DPoint OutputDevice::ImplLogicToDeviceSubPixel(const Point& rPoint) const
1896 if (!mbMap)
1897 return basegfx::B2DPoint(rPoint.X() + mnOutOffX, rPoint.Y() + mnOutOffY);
1899 return basegfx::B2DPoint(ImplLogicToSubPixel(rPoint.X() + maMapRes.mnMapOfsX, mnDPIX,
1900 maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX)
1901 + mnOutOffX + mnOutOffOrigX,
1902 ImplLogicToSubPixel(rPoint.Y() + maMapRes.mnMapOfsY, mnDPIY,
1903 maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY)
1904 + mnOutOffY + mnOutOffOrigY);
1907 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */