vcl/source/control/button.cxx | 17 +++ vcl/source/outdev/map.cxx | 202 ++++++++++++++++++++++++++++++------------ 2 files changed, 163 insertions(+), 56 deletions(-)
New commits: commit 962b015696832b139a61c91bb733686f33ce8872 Author: Armin Le Grand (Allotropia) <[email protected]> AuthorDate: Mon Apr 19 19:51:27 2021 +0200 Commit: Armin Le Grand (Allotropia) <[email protected]> CommitDate: Thu Apr 22 18:48:25 2021 +0200 tdf#141761 Avoid vanishing FormControls For details see task documentaion, but BG is that a Rectangle gets not transformed in OutputDevice::LogicToPixel and corresponding methods of OutputDevice due to the given Rectangle.IsEmpty() == true. This ignores that the Rectangle has a valid position and that we have cases where a Rectangle is used to hold a Position without having a Size != 0 in X and Y. Thus I added transforming the Position in these methods in all cases - a Rectangle always has a valid position - and take care of Sizes that exist. This *may* need to be done different due to old hiccups of Rectangle itself, see explanation at OutputDevice::ImplLogicToDevicePixel Had to do it different now, see comment in map.cxx for expalantions. Also needed to adapt the ancient optical geometric paint position correctionsfor Buttons - these can get zero or negative due to using Zoom and MapMode settings. A Width shoul not get zero or negative. Adapted to work branch. Was some work, in map.cxx all the transformations have changed, even the number of parameters for ImplLogicToPixel. Also in button.cxx pretty dangerous - initial merge offers the conflict solutioin at the wrong place due to the code in question did move in master to a unified position. Change-Id: Ide085fbe74f9c0387de3c1bf6320b7e873238029 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114304 Tested-by: Jenkins Reviewed-by: Armin Le Grand <[email protected]> diff --git a/vcl/source/control/button.cxx b/vcl/source/control/button.cxx index 146b6402a7f4..b3e33a6c4203 100644 --- a/vcl/source/control/button.cxx +++ b/vcl/source/control/button.cxx @@ -855,7 +855,11 @@ void PushButton::ImplDrawPushButtonContent(OutputDevice* pDev, DrawFlags nDrawFl long nSymbolSize = pDev->GetTextHeight() / 2 + 1; nSeparatorX = aInRect.Right() - 2*nSymbolSize; - aSize.AdjustWidth( -(2*nSymbolSize) ); + + // tdf#141761 Minimum width should be (1) Pixel, see comment + // with same task number above for more info + const long nWidthAdjust(2*nSymbolSize); + aSize.setWidth(std::max(static_cast<long>(1), aSize.getWidth() - nWidthAdjust)); // center symbol rectangle in the separated area aSymbolRect.AdjustRight( -(nSymbolSize/2) ); @@ -3055,7 +3059,16 @@ void CheckBox::ImplDraw( OutputDevice* pDev, DrawFlags nDrawFlags, Size aSize( rSize ); Point aPos( rPos ); aPos.AdjustX(rImageSize.Width() + nImageSep ); - aSize.AdjustWidth( -(rImageSize.Width() + nImageSep) ); + + // tdf#141761 Old (convenience?) adjustment of width may lead to empty + // or negative(!) Size, that needs to be avoided. The coordinate context + // is pixel-oriented (all Paints of Controls are, historically), so + // the minimum width should be '1' Pixel. + // Hint: nImageSep is based on Zoom (using Window::CalcZoom) and + // MapModes (using Window::GetDrawPixel) - so potenially a wide range + // of unpredictable values is possible + const long nWidthAdjust(rImageSize.Width() + nImageSep); + aSize.setWidth(std::max(static_cast<long>(1), aSize.getWidth() - nWidthAdjust)); // if the text rect height is smaller than the height of the image // then for single lines the default should be centered text diff --git a/vcl/source/outdev/map.cxx b/vcl/source/outdev/map.cxx index 5a91bfb274c3..cd72903f0776 100644 --- a/vcl/source/outdev/map.cxx +++ b/vcl/source/outdev/map.cxx @@ -503,27 +503,56 @@ Size OutputDevice::ImplLogicToDevicePixel( const Size& rLogicSize ) const tools::Rectangle OutputDevice::ImplLogicToDevicePixel( const tools::Rectangle& rLogicRect ) const { - if ( rLogicRect.IsEmpty() ) - return rLogicRect; + // tdf#141761 IsEmpty() removed + // Even if rLogicRect.IsEmpty(), transform of the Position contained + // in the Rectangle is necessary. Due to Rectangle::Right() returning + // Left() when IsEmpty(), the code *could* stay unchanged (same for Bottom), + // but: + // The Rectangle constructor used with the four tools::Long values does not + // check for IsEmpty(), so to keep that state correct there are two possibilities: + // (1) Add a test to the Rectangle constructor in question + // (2) Do it handish here + // I have tried (1) first, but test Test::test_rectangle() claims that for + // tools::Rectangle aRect(1, 1, 1, 1); + // tools::Long(1) == aRect.GetWidth() + // tools::Long(0) == aRect.getWidth() + // (remember: this means Left == Right == 1 -> GetWidth => 1, getWidth == 0) + // so indeed tthe 1's have to go uncommened/unchecked into the data body + // of rectangle. Switching to (2) *is* needed, doing so + tools::Rectangle aRetval; if ( !mbMap ) { - return tools::Rectangle( rLogicRect.Left()+mnOutOffX, rLogicRect.Top()+mnOutOffY, - rLogicRect.Right()+mnOutOffX, rLogicRect.Bottom()+mnOutOffY ); + aRetval = tools::Rectangle( + rLogicRect.Left()+mnOutOffX, + rLogicRect.Top()+mnOutOffY, + rLogicRect.IsWidthEmpty() ? 0 : rLogicRect.Right()+mnOutOffX, + rLogicRect.IsHeightEmpty() ? 0 : rLogicRect.Bottom()+mnOutOffY ); } - - return tools::Rectangle( ImplLogicToPixel( rLogicRect.Left()+maMapRes.mnMapOfsX, mnDPIX, + else + { + aRetval = tools::Rectangle( + ImplLogicToPixel( rLogicRect.Left()+maMapRes.mnMapOfsX, mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, maThresRes.mnThresLogToPixX )+mnOutOffX+mnOutOffOrigX, - ImplLogicToPixel( rLogicRect.Top()+maMapRes.mnMapOfsY, mnDPIY, + ImplLogicToPixel( rLogicRect.Top()+maMapRes.mnMapOfsY, mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, maThresRes.mnThresLogToPixY )+mnOutOffY+mnOutOffOrigY, - ImplLogicToPixel( rLogicRect.Right()+maMapRes.mnMapOfsX, mnDPIX, + rLogicRect.IsWidthEmpty() ? 0 : ImplLogicToPixel( rLogicRect.Right()+maMapRes.mnMapOfsX, mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, maThresRes.mnThresLogToPixX )+mnOutOffX+mnOutOffOrigX, - ImplLogicToPixel( rLogicRect.Bottom()+maMapRes.mnMapOfsY, mnDPIY, + rLogicRect.IsHeightEmpty() ? 0 : ImplLogicToPixel( rLogicRect.Bottom()+maMapRes.mnMapOfsY, mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, maThresRes.mnThresLogToPixY )+mnOutOffY+mnOutOffOrigY ); + } + + if(rLogicRect.IsWidthEmpty()) + aRetval.SetWidthEmpty(); + + if(rLogicRect.IsHeightEmpty()) + aRetval.SetHeightEmpty(); + + return aRetval; } tools::Polygon OutputDevice::ImplLogicToDevicePixel( const tools::Polygon& rLogicPoly ) const @@ -611,27 +640,41 @@ LineInfo OutputDevice::ImplLogicToDevicePixel( const LineInfo& rLineInfo ) const tools::Rectangle OutputDevice::ImplDevicePixelToLogic( const tools::Rectangle& rPixelRect ) const { - if ( rPixelRect.IsEmpty() ) - return rPixelRect; + // tdf#141761 see comments above, IsEmpty() removed + tools::Rectangle aRetval; if ( !mbMap ) { - return tools::Rectangle( rPixelRect.Left()-mnOutOffX, rPixelRect.Top()-mnOutOffY, - rPixelRect.Right()-mnOutOffX, rPixelRect.Bottom()-mnOutOffY ); + aRetval = tools::Rectangle( + rPixelRect.Left()-mnOutOffX, + rPixelRect.Top()-mnOutOffY, + rPixelRect.IsWidthEmpty() ? 0 : rPixelRect.Right()-mnOutOffX, + rPixelRect.IsHeightEmpty() ? 0 : rPixelRect.Bottom()-mnOutOffY ); } - - return tools::Rectangle( ImplPixelToLogic( rPixelRect.Left()-mnOutOffX-mnOutOffOrigX, mnDPIX, + else + { + aRetval = tools::Rectangle( + ImplPixelToLogic( rPixelRect.Left()-mnOutOffX-mnOutOffOrigX, mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, maThresRes.mnThresPixToLogX )-maMapRes.mnMapOfsX, - ImplPixelToLogic( rPixelRect.Top()-mnOutOffY-mnOutOffOrigY, mnDPIY, + ImplPixelToLogic( rPixelRect.Top()-mnOutOffY-mnOutOffOrigY, mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, maThresRes.mnThresPixToLogY )-maMapRes.mnMapOfsY, - ImplPixelToLogic( rPixelRect.Right()-mnOutOffX-mnOutOffOrigX, mnDPIX, + rPixelRect.IsWidthEmpty() ? 0 : ImplPixelToLogic( rPixelRect.Right()-mnOutOffX-mnOutOffOrigX, mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, maThresRes.mnThresPixToLogX )-maMapRes.mnMapOfsX, - ImplPixelToLogic( rPixelRect.Bottom()-mnOutOffY-mnOutOffOrigY, mnDPIY, + rPixelRect.IsHeightEmpty() ? 0 : ImplPixelToLogic( rPixelRect.Bottom()-mnOutOffY-mnOutOffOrigY, mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, maThresRes.mnThresPixToLogY )-maMapRes.mnMapOfsY ); + } + + if(rPixelRect.IsWidthEmpty()) + aRetval.SetWidthEmpty(); + + if(rPixelRect.IsHeightEmpty()) + aRetval.SetHeightEmpty(); + + return aRetval; } vcl::Region OutputDevice::ImplPixelToDevicePixel( const vcl::Region& rRegion ) const @@ -967,22 +1010,31 @@ Size OutputDevice::LogicToPixel( const Size& rLogicSize ) const tools::Rectangle OutputDevice::LogicToPixel( const tools::Rectangle& rLogicRect ) const { - - if ( !mbMap || rLogicRect.IsEmpty() ) + // tdf#141761 see comments above, IsEmpty() removed + if ( !mbMap ) return rLogicRect; - return tools::Rectangle( ImplLogicToPixel( rLogicRect.Left() + maMapRes.mnMapOfsX, mnDPIX, + tools::Rectangle aRetval( + ImplLogicToPixel( rLogicRect.Left() + maMapRes.mnMapOfsX, mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, maThresRes.mnThresLogToPixX )+mnOutOffOrigX, - ImplLogicToPixel( rLogicRect.Top() + maMapRes.mnMapOfsY, mnDPIY, + ImplLogicToPixel( rLogicRect.Top() + maMapRes.mnMapOfsY, mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, maThresRes.mnThresLogToPixY )+mnOutOffOrigY, - ImplLogicToPixel( rLogicRect.Right() + maMapRes.mnMapOfsX, mnDPIX, + rLogicRect.IsWidthEmpty() ? 0 : ImplLogicToPixel( rLogicRect.Right() + maMapRes.mnMapOfsX, mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, maThresRes.mnThresLogToPixX )+mnOutOffOrigX, - ImplLogicToPixel( rLogicRect.Bottom() + maMapRes.mnMapOfsY, mnDPIY, + rLogicRect.IsHeightEmpty() ? 0 : ImplLogicToPixel( rLogicRect.Bottom() + maMapRes.mnMapOfsY, mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, maThresRes.mnThresLogToPixY )+mnOutOffOrigY ); + + if(rLogicRect.IsWidthEmpty()) + aRetval.SetWidthEmpty(); + + if(rLogicRect.IsHeightEmpty()) + aRetval.SetHeightEmpty(); + + return aRetval; } tools::Polygon OutputDevice::LogicToPixel( const tools::Polygon& rLogicPoly ) const @@ -1115,8 +1167,8 @@ Size OutputDevice::LogicToPixel( const Size& rLogicSize, tools::Rectangle OutputDevice::LogicToPixel( const tools::Rectangle& rLogicRect, const MapMode& rMapMode ) const { - - if ( rMapMode.IsDefault() || rLogicRect.IsEmpty() ) + // tdf#141761 see comments above, IsEmpty() removed + if ( rMapMode.IsDefault() ) return rLogicRect; // convert MapMode resolution and convert @@ -1124,18 +1176,27 @@ tools::Rectangle OutputDevice::LogicToPixel( const tools::Rectangle& rLogicRect, ImplThresholdRes aThresRes; ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes ); - return tools::Rectangle( ImplLogicToPixel( rLogicRect.Left() + aMapRes.mnMapOfsX, mnDPIX, + tools::Rectangle aRetval( + ImplLogicToPixel( rLogicRect.Left() + aMapRes.mnMapOfsX, mnDPIX, aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX, aThresRes.mnThresLogToPixX )+mnOutOffOrigX, - ImplLogicToPixel( rLogicRect.Top() + aMapRes.mnMapOfsY, mnDPIY, + ImplLogicToPixel( rLogicRect.Top() + aMapRes.mnMapOfsY, mnDPIY, aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY, aThresRes.mnThresLogToPixY )+mnOutOffOrigY, - ImplLogicToPixel( rLogicRect.Right() + aMapRes.mnMapOfsX, mnDPIX, + rLogicRect.IsWidthEmpty() ? 0 : ImplLogicToPixel( rLogicRect.Right() + aMapRes.mnMapOfsX, mnDPIX, aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX, aThresRes.mnThresLogToPixX )+mnOutOffOrigX, - ImplLogicToPixel( rLogicRect.Bottom() + aMapRes.mnMapOfsY, mnDPIY, + rLogicRect.IsHeightEmpty() ? 0 : ImplLogicToPixel( rLogicRect.Bottom() + aMapRes.mnMapOfsY, mnDPIY, aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY, aThresRes.mnThresLogToPixY )+mnOutOffOrigY ); + + if(rLogicRect.IsWidthEmpty()) + aRetval.SetWidthEmpty(); + + if(rLogicRect.IsHeightEmpty()) + aRetval.SetHeightEmpty(); + + return aRetval; } tools::Polygon OutputDevice::LogicToPixel( const tools::Polygon& rLogicPoly, @@ -1212,22 +1273,31 @@ Size OutputDevice::PixelToLogic( const Size& rDeviceSize ) const tools::Rectangle OutputDevice::PixelToLogic( const tools::Rectangle& rDeviceRect ) const { - - if ( !mbMap || rDeviceRect.IsEmpty() ) + // tdf#141761 see comments above, IsEmpty() removed + if ( !mbMap ) return rDeviceRect; - return tools::Rectangle( ImplPixelToLogic( rDeviceRect.Left(), mnDPIX, + tools::Rectangle aRetval( + ImplPixelToLogic( rDeviceRect.Left(), mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, maThresRes.mnThresPixToLogX ) - maMapRes.mnMapOfsX - mnOutOffLogicX, - ImplPixelToLogic( rDeviceRect.Top(), mnDPIY, + ImplPixelToLogic( rDeviceRect.Top(), mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, maThresRes.mnThresPixToLogY ) - maMapRes.mnMapOfsY - mnOutOffLogicY, - ImplPixelToLogic( rDeviceRect.Right(), mnDPIX, + rDeviceRect.IsWidthEmpty() ? 0 : ImplPixelToLogic( rDeviceRect.Right(), mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX, maThresRes.mnThresPixToLogX ) - maMapRes.mnMapOfsX - mnOutOffLogicX, - ImplPixelToLogic( rDeviceRect.Bottom(), mnDPIY, + rDeviceRect.IsHeightEmpty() ? 0 : ImplPixelToLogic( rDeviceRect.Bottom(), mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY, maThresRes.mnThresPixToLogY ) - maMapRes.mnMapOfsY - mnOutOffLogicY ); + + if(rDeviceRect.IsWidthEmpty()) + aRetval.SetWidthEmpty(); + + if(rDeviceRect.IsHeightEmpty()) + aRetval.SetHeightEmpty(); + + return aRetval; } tools::Polygon OutputDevice::PixelToLogic( const tools::Polygon& rDevicePoly ) const @@ -1362,9 +1432,9 @@ Size OutputDevice::PixelToLogic( const Size& rDeviceSize, tools::Rectangle OutputDevice::PixelToLogic( const tools::Rectangle& rDeviceRect, const MapMode& rMapMode ) const { - // calculate nothing if default-MapMode - if ( rMapMode.IsDefault() || rDeviceRect.IsEmpty() ) + // tdf#141761 see comments above, IsEmpty() removed + if ( rMapMode.IsDefault() ) return rDeviceRect; // calculate MapMode-resolution and convert @@ -1372,18 +1442,27 @@ tools::Rectangle OutputDevice::PixelToLogic( const tools::Rectangle& rDeviceRect ImplThresholdRes aThresRes; ImplCalcMapResolution( rMapMode, mnDPIX, mnDPIY, aMapRes, aThresRes ); - return tools::Rectangle( ImplPixelToLogic( rDeviceRect.Left(), mnDPIX, + tools::Rectangle aRetval( + ImplPixelToLogic( rDeviceRect.Left(), mnDPIX, aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX, aThresRes.mnThresPixToLogX ) - aMapRes.mnMapOfsX - mnOutOffLogicX, - ImplPixelToLogic( rDeviceRect.Top(), mnDPIY, + ImplPixelToLogic( rDeviceRect.Top(), mnDPIY, aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY, aThresRes.mnThresPixToLogY ) - aMapRes.mnMapOfsY - mnOutOffLogicY, - ImplPixelToLogic( rDeviceRect.Right(), mnDPIX, + rDeviceRect.IsWidthEmpty() ? 0 : ImplPixelToLogic( rDeviceRect.Right(), mnDPIX, aMapRes.mnMapScNumX, aMapRes.mnMapScDenomX, aThresRes.mnThresPixToLogX ) - aMapRes.mnMapOfsX - mnOutOffLogicX, - ImplPixelToLogic( rDeviceRect.Bottom(), mnDPIY, + rDeviceRect.IsHeightEmpty() ? 0 : ImplPixelToLogic( rDeviceRect.Bottom(), mnDPIY, aMapRes.mnMapScNumY, aMapRes.mnMapScDenomY, aThresRes.mnThresPixToLogY ) - aMapRes.mnMapOfsY - mnOutOffLogicY ); + + if(rDeviceRect.IsWidthEmpty()) + aRetval.SetWidthEmpty(); + + if(rDeviceRect.IsHeightEmpty()) + aRetval.SetHeightEmpty(); + + return aRetval; } tools::Polygon OutputDevice::PixelToLogic( const tools::Polygon& rDevicePoly, @@ -1859,40 +1938,55 @@ tools::Rectangle OutputDevice::LogicToLogic( const tools::Rectangle& rRectSource MapUnit eUnitDest = rMapModeDest.GetMapUnit(); verifyUnitSourceDest( eUnitSource, eUnitDest ); + tools::Rectangle aRetval; + if (rMapModeSource.IsSimple() && rMapModeDest.IsSimple()) { ENTER3( eUnitSource, eUnitDest ); auto left = fn3( rRectSource.Left(), nNumerator, nDenominator ); auto top = fn3( rRectSource.Top(), nNumerator, nDenominator ); - if (rRectSource.IsEmpty()) - return tools::Rectangle( left, top ); - auto right = fn3( rRectSource.Right(), nNumerator, nDenominator ); - auto bottom = fn3( rRectSource.Bottom(), nNumerator, nDenominator ); + // tdf#141761 see comments above, IsEmpty() removed + auto right = rRectSource.IsWidthEmpty() ? 0 : fn3( rRectSource.Right(), nNumerator, nDenominator ); + auto bottom = rRectSource.IsHeightEmpty() ? 0 : fn3( rRectSource.Bottom(), nNumerator, nDenominator ); + + aRetval = tools::Rectangle(left, top, right, bottom); return tools::Rectangle(left, top, right, bottom); } else { ENTER4( rMapModeSource, rMapModeDest ); - return tools::Rectangle( fn5( rRectSource.Left() + aMapResSource.mnMapOfsX, + auto left = fn5( rRectSource.Left() + aMapResSource.mnMapOfsX, aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX, aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) - - aMapResDest.mnMapOfsX, - fn5( rRectSource.Top() + aMapResSource.mnMapOfsY, + aMapResDest.mnMapOfsX; + auto top = fn5( rRectSource.Top() + aMapResSource.mnMapOfsY, aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY, aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) - - aMapResDest.mnMapOfsY, - fn5( rRectSource.Right() + aMapResSource.mnMapOfsX, + aMapResDest.mnMapOfsY; + + // tdf#141761 see comments above, IsEmpty() removed + auto right = rRectSource.IsWidthEmpty() ? 0 : fn5( rRectSource.Right() + aMapResSource.mnMapOfsX, aMapResSource.mnMapScNumX, aMapResDest.mnMapScDenomX, aMapResSource.mnMapScDenomX, aMapResDest.mnMapScNumX ) - - aMapResDest.mnMapOfsX, - fn5( rRectSource.Bottom() + aMapResSource.mnMapOfsY, + aMapResDest.mnMapOfsX; + auto bottom = rRectSource.IsHeightEmpty() ? 0 : fn5( rRectSource.Bottom() + aMapResSource.mnMapOfsY, aMapResSource.mnMapScNumY, aMapResDest.mnMapScDenomY, aMapResSource.mnMapScDenomY, aMapResDest.mnMapScNumY ) - - aMapResDest.mnMapOfsY ); + aMapResDest.mnMapOfsY; + + aRetval = tools::Rectangle(left, top, right, bottom); } + + if(rRectSource.IsWidthEmpty()) + aRetval.SetWidthEmpty(); + + if(rRectSource.IsHeightEmpty()) + aRetval.SetHeightEmpty(); + + return aRetval; } long OutputDevice::LogicToLogic( long nLongSource, _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
