diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2021-02-05 09:36:59 +0300 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2021-02-05 17:04:00 +0100 |
commit | d7e5fa3bd8f4240665f13994589f5e72d362c097 (patch) | |
tree | 5709b7600d9f3ee8bec08b87e9b52f475990e16e /include | |
parent | cb2a94a4a7ecb449d0731627ee6d58bd1b4e35f3 (diff) |
Make sanitiseMm100ToTwip simpler and more correct
The result's absolute value is always smaller than n.
Returning an uncorrected value taken from reversing
multiplication and division order when intermediate
value would overflow is better than arbitrary constant.
Also further deduplicate Twips <-> 100th-mm conversion,
and make sure they all are in a single header.
Using conversion implementation that handles negatives
correctly improves accuracy, as seen in unit tests; e.g.
in testPictureEffectPreservation (the original doc had
"dir" equal to "8100000", while we tested that it was
"8076614" after roundtrip).
Change-Id: Icd027af6238a9f45f916f53f8684506cc959e696
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/110433
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Diffstat (limited to 'include')
-rw-r--r-- | include/tools/UnitConversion.hxx | 15 | ||||
-rw-r--r-- | include/tools/helpers.hxx | 34 |
2 files changed, 15 insertions, 34 deletions
diff --git a/include/tools/UnitConversion.hxx b/include/tools/UnitConversion.hxx index e78ef315b432..57f8e39119f0 100644 --- a/include/tools/UnitConversion.hxx +++ b/include/tools/UnitConversion.hxx @@ -11,17 +11,32 @@ #pragma once #include <sal/types.h> +#include <cassert> +#include <limits> constexpr sal_Int64 convertTwipToMm100(sal_Int64 n) { + assert(n < std::numeric_limits<sal_Int64>::max() / 127 + && n > std::numeric_limits<sal_Int64>::min() / 127); return (n >= 0) ? (n * 127 + 36) / 72 : (n * 127 - 36) / 72; } constexpr sal_Int64 convertMm100ToTwip(sal_Int64 n) { + assert(n < std::numeric_limits<sal_Int64>::max() / 72 + && n > std::numeric_limits<sal_Int64>::min() / 72); return (n >= 0) ? (n * 72 + 63) / 127 : (n * 72 - 63) / 127; } +constexpr sal_Int64 sanitiseMm100ToTwip(sal_Int64 n) +{ + if (n >= std::numeric_limits<sal_Int64>::max() / 72 + || n <= std::numeric_limits<sal_Int64>::min() / 72) + return n / 127 * 72; // do without correction; can not overflow here + else + return convertMm100ToTwip(n); +} + constexpr sal_Int64 convertPointToTwip(sal_Int64 nNumber) { return nNumber * 20; } constexpr sal_Int64 convertPointToMm100(sal_Int64 nNumber) diff --git a/include/tools/helpers.hxx b/include/tools/helpers.hxx index 381ecb206d18..abce49b3d469 100644 --- a/include/tools/helpers.hxx +++ b/include/tools/helpers.hxx @@ -98,38 +98,4 @@ template <typename T> [[nodiscard]] inline T NormAngle360(T angle) return angle; } -/** Convert 100th-mm to twips - - A twip is 1/20 of a point, one inch is equal to 72 points, and - one inch is 2,540 100th-mm. - - Thus: - twips = n * 72 / 2,540 / 20 - = n * 72 / 127 - - Adding 63 (half of 127) fixes truncation issues in int arithmetic. - - This formula is (n>=0) ? (n*72+63) / 127 : (n*72-63) / 127 - */ -inline sal_Int64 sanitiseMm100ToTwip(sal_Int64 n) -{ - if (n >= 0) - { - if (o3tl::checked_multiply<sal_Int64>(n, 72, n) || o3tl::checked_add<sal_Int64>(n, 63, n)) - n = SAL_MAX_INT64; - } - else - { - if (o3tl::checked_multiply<sal_Int64>(n, 72, n) || o3tl::checked_sub<sal_Int64>(n, 63, n)) - n = SAL_MIN_INT64; - } - return n / 127; // 127 is 2,540 100th-mm divided by 20pts -} - -/** -* Convert Twips <-> 100th-mm -*/ -inline constexpr sal_Int64 TwipsToHMM(sal_Int64 nTwips) { return (nTwips * 127 + 36) / 72; } -inline constexpr sal_Int64 HMMToTwips(sal_Int64 nHMM) { return (nHMM * 72 + 63) / 127; } - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |