From bf588c5d9a8214a7b44cae4e49318167093e1b14 Mon Sep 17 00:00:00 2001 From: Justin Luth Date: Wed, 2 Sep 2026 14:10:26 -0400 Subject: [PATCH] tdf#162830 sc LayoutStrings: use decimal size to fit repeat into width Using the rounded integer width of a single character and using that to determine how many times to repeat it in a give space is bound to result in disaster. Instead, determine an approximation of the real size of the string. This is just layout stuff - no idea how to capture it in a unit test. Change-Id: Ie0cbc891d986357a1037b1476cb1cd4c9601e876 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/210439 Reviewed-by: Justin Luth Tested-by: Jenkins --- sc/source/ui/view/output2.cxx | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/sc/source/ui/view/output2.cxx b/sc/source/ui/view/output2.cxx index 9850ed5c6822..aaa480429dcf 100644 --- a/sc/source/ui/view/output2.cxx +++ b/sc/source/ui/view/output2.cxx @@ -1899,17 +1899,33 @@ void ScOutputData::LayoutStringsImpl(bool const bPixelToLogic, RowInfo* const pT if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip ) { tools::Long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin; - tools::Long nRepeatSize = aVars.GetTextSize().Width(); // without margin + double fRepeatSize = aVars.GetTextSize().Width(); // without margin + const OUString& aCellStr = aVars.GetString(); + + // Measuring a string containing a single copy of a short repeat string is inaccurate. + // To increase accuracy, start with a representative sample of the repeated sequence. + constexpr sal_Int32 nSampleSize = 20; + const size_t nLen = aCellStr.getLength(); + if (nLen && nLen < nSampleSize) + { + OUStringBuffer aFill(aCellStr); + aFill.ensureCapacity(nSampleSize); + while (aFill.getLength() < nSampleSize) + aFill.append(aCellStr); + fRepeatSize + = aVars.GetFmtTextWidth(aFill.copy(0, nSampleSize).makeStringAndClear()); + fRepeatSize = fRepeatSize * nLen / nSampleSize; + } + // When formatting for the printer, the text sizes don't always add up. // Round down (too few repetitions) rather than exceeding the cell size then: if ( pFmtDevice != mpRefDevice ) - ++nRepeatSize; - if ( nRepeatSize > 0 ) + ++fRepeatSize; + if (fRepeatSize > 0) { - tools::Long nRepeatCount = nAvailable / nRepeatSize; + const tools::Long nRepeatCount = nAvailable / fRepeatSize; if ( nRepeatCount > 1 ) { - OUString aCellStr = aVars.GetString(); OUStringBuffer aRepeated(aCellStr); for ( tools::Long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ ) aRepeated.append(aCellStr);