summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2024-04-10 12:15:55 +0500
committerAron Budea <aron.budea@collabora.com>2024-05-08 08:11:16 +0200
commit8c8704d346bc8f30e60f446afb5ee9cdc2dc9a80 (patch)
tree83e2a656b1ea1f8b9083db9244655a268dbfc9a6 /vcl
parent8f95a0806d7cf1f5ec97c2d2ecdd4964e6dc8504 (diff)
tdf#160622: Let SalLayout::GetBoundRect return basegfx::B2DRectangle
This avoids premature rounding in TextLayouterDevice::getTextBoundRect. The box in D2DWriteTextOutRenderer::performRender needs to be expanded to allow room for the line width (which now will be guaranteed on all sides; previously, the rounding could happen to give no room on some side, even prior to commit 8962141a12c966b2d891829925e6203bf8d51852). Fixes some lines partially cut off in smaller text (or zoomed out). Change-Id: I07335136021f894cf045363b4d736bfab06c64d4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166236 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com> Signed-off-by: Xisco Fauli <xiscofauli@libreoffice.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167014 (cherry picked from commit aa2df54f37926cf95261eefade1b87da3229cfd7)
Diffstat (limited to 'vcl')
-rw-r--r--vcl/skia/gdiimpl.cxx2
-rw-r--r--vcl/source/gdi/sallayout.cxx33
-rw-r--r--vcl/source/outdev/map.cxx8
-rw-r--r--vcl/source/outdev/text.cxx38
-rw-r--r--vcl/win/gdi/DWriteTextRenderer.cxx11
5 files changed, 64 insertions, 28 deletions
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
index d7028b959842..f4ad57f715b0 100644
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -2154,7 +2154,7 @@ void SkiaSalGraphicsImpl::drawGenericLayout(const GenericSalLayout& layout, Colo
preDraw();
auto getBoundRect = [&layout]() {
- tools::Rectangle rect;
+ basegfx::B2DRectangle rect;
layout.GetBoundRect(rect);
return rect;
};
diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx
index 28138c3f61fd..3b1279dd1f66 100644
--- a/vcl/source/gdi/sallayout.cxx
+++ b/vcl/source/gdi/sallayout.cxx
@@ -220,11 +220,10 @@ static double trimInsignificant(double n)
return std::abs(n) >= 0x1p53 ? n : std::round(n * 1e5) / 1e5;
}
-bool SalLayout::GetBoundRect(tools::Rectangle& rRect) const
+bool SalLayout::GetBoundRect(basegfx::B2DRectangle& rRect) const
{
bool bRet = false;
-
- basegfx::B2DRectangle aUnion;
+ rRect.reset();
basegfx::B2DRectangle aRectangle;
basegfx::B2DPoint aPos;
@@ -240,28 +239,28 @@ bool SalLayout::GetBoundRect(tools::Rectangle& rRect) const
{
aRectangle.transform(basegfx::utils::createTranslateB2DHomMatrix(aPos));
// merge rectangle
- aUnion.expand(aRectangle);
+ rRect.expand(aRectangle);
}
bRet = true;
}
}
- if (aUnion.isEmpty())
- {
- rRect = {};
- }
- else
- {
- double l = rtl::math::approxFloor(trimInsignificant(aUnion.getMinX())),
- t = rtl::math::approxFloor(trimInsignificant(aUnion.getMinY())),
- r = rtl::math::approxCeil(trimInsignificant(aUnion.getMaxX())),
- b = rtl::math::approxCeil(trimInsignificant(aUnion.getMaxY()));
- assert(std::isfinite(l) && std::isfinite(t) && std::isfinite(r) && std::isfinite(b));
- rRect = tools::Rectangle(l, t, r, b);
- }
return bRet;
}
+tools::Rectangle SalLayout::BoundRect2Rectangle(basegfx::B2DRectangle& rRect)
+{
+ if (rRect.isEmpty())
+ return {};
+
+ double l = rtl::math::approxFloor(trimInsignificant(rRect.getMinX())),
+ t = rtl::math::approxFloor(trimInsignificant(rRect.getMinY())),
+ r = rtl::math::approxCeil(trimInsignificant(rRect.getMaxX())),
+ b = rtl::math::approxCeil(trimInsignificant(rRect.getMaxY()));
+ assert(std::isfinite(l) && std::isfinite(t) && std::isfinite(r) && std::isfinite(b));
+ return tools::Rectangle(l, t, r, b);
+}
+
SalLayoutGlyphs SalLayout::GetGlyphs() const
{
return SalLayoutGlyphs(); // invalid
diff --git a/vcl/source/outdev/map.cxx b/vcl/source/outdev/map.cxx
index 23c68a238551..8707805eb1c2 100644
--- a/vcl/source/outdev/map.cxx
+++ b/vcl/source/outdev/map.cxx
@@ -1217,6 +1217,14 @@ basegfx::B2DPolyPolygon OutputDevice::PixelToLogic( const basegfx::B2DPolyPolygo
return aTransformedPoly;
}
+basegfx::B2DRectangle OutputDevice::PixelToLogic(const basegfx::B2DRectangle& rDeviceRect) const
+{
+ basegfx::B2DRectangle aTransformedRect = rDeviceRect;
+ const basegfx::B2DHomMatrix& rTransformationMatrix = GetInverseViewTransformation();
+ aTransformedRect.transform(rTransformationMatrix);
+ return aTransformedRect;
+}
+
vcl::Region OutputDevice::PixelToLogic( const vcl::Region& rDeviceRegion ) const
{
diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx
index 1b40a1b2de28..16fdf7b073d0 100644
--- a/vcl/source/outdev/text.cxx
+++ b/vcl/source/outdev/text.cxx
@@ -21,6 +21,7 @@
#include <sal/log.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <tools/lineend.hxx>
#include <tools/debug.hxx>
#include <unotools/configmgr.hxx>
@@ -214,7 +215,11 @@ bool OutputDevice::ImplDrawRotateText( SalLayout& rSalLayout )
tools::Rectangle aBoundRect;
rSalLayout.DrawBase() = basegfx::B2DPoint( 0, 0 );
rSalLayout.DrawOffset() = Point( 0, 0 );
- if (!rSalLayout.GetBoundRect(aBoundRect))
+ if (basegfx::B2DRectangle r; rSalLayout.GetBoundRect(r))
+ {
+ aBoundRect = SalLayout::BoundRect2Rectangle(r);
+ }
+ else
{
// guess vertical text extents if GetBoundRect failed
double nRight = rSalLayout.GetTextWidth();
@@ -1922,8 +1927,21 @@ bool OutputDevice::GetTextBoundRect( tools::Rectangle& rRect,
std::span<const sal_Bool> pKashidaAry,
const SalLayoutGlyphs* pGlyphs ) const
{
+ basegfx::B2DRectangle aRect;
+ bool bRet = GetTextBoundRect(aRect, rStr, nBase, nIndex, nLen, nLayoutWidth, pDXAry,
+ pKashidaAry, pGlyphs);
+ rRect = SalLayout::BoundRect2Rectangle(aRect);
+ return bRet;
+}
+
+bool OutputDevice::GetTextBoundRect(basegfx::B2DRectangle& rRect, const OUString& rStr,
+ sal_Int32 nBase, sal_Int32 nIndex, sal_Int32 nLen,
+ sal_uLong nLayoutWidth, KernArraySpan pDXAry,
+ std::span<const sal_Bool> pKashidaAry,
+ const SalLayoutGlyphs* pGlyphs) const
+{
bool bRet = false;
- rRect.SetEmpty();
+ rRect.reset();
std::unique_ptr<SalLayout> pSalLayout;
const Point aPoint;
@@ -1947,18 +1965,22 @@ bool OutputDevice::GetTextBoundRect( tools::Rectangle& rRect,
nullptr, pGlyphs);
if( pSalLayout )
{
- tools::Rectangle aPixelRect;
+ basegfx::B2DRectangle aPixelRect;
bRet = pSalLayout->GetBoundRect(aPixelRect);
if( bRet )
{
- Point aRotatedOfs( mnTextOffX, mnTextOffY );
basegfx::B2DPoint aPos = pSalLayout->GetDrawPosition(basegfx::B2DPoint(nXOffset, 0));
- aRotatedOfs -= Point(aPos.getX(), aPos.getY());
- aPixelRect += aRotatedOfs;
+ auto m = basegfx::utils::createTranslateB2DHomMatrix(mnTextOffX - aPos.getX(),
+ mnTextOffY - aPos.getY());
+ aPixelRect.transform(m);
rRect = PixelToLogic( aPixelRect );
- if( mbMap )
- rRect += Point( maMapRes.mnMapOfsX, maMapRes.mnMapOfsY );
+ if (mbMap)
+ {
+ m = basegfx::utils::createTranslateB2DHomMatrix(maMapRes.mnMapOfsX,
+ maMapRes.mnMapOfsY);
+ rRect.transform(m);
+ }
}
}
diff --git a/vcl/win/gdi/DWriteTextRenderer.cxx b/vcl/win/gdi/DWriteTextRenderer.cxx
index 3d3dac83c6dd..82508061b62a 100644
--- a/vcl/win/gdi/DWriteTextRenderer.cxx
+++ b/vcl/win/gdi/DWriteTextRenderer.cxx
@@ -225,8 +225,15 @@ bool D2DWriteTextOutRenderer::performRender(GenericSalLayout const & rLayout, Sa
if (!pFontFace)
return false;
- tools::Rectangle bounds;
- bool succeeded = rLayout.GetBoundRect(bounds);
+ auto [succeeded, bounds] = [&rLayout]()
+ {
+ basegfx::B2DRectangle r;
+ bool result = rLayout.GetBoundRect(r);
+ if (result)
+ r.grow(1); // plus 1 pixel to the tight range
+ return std::make_pair(result, SalLayout::BoundRect2Rectangle(r));
+ }();
+
if (succeeded)
{
hr = BindDC(hDC, bounds); // Update the bounding rect.