summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2021-02-13 13:55:22 +0300
committerMike Kaganski <mike.kaganski@collabora.com>2021-02-14 12:50:01 +0100
commitcfff893b9c82843a90aac4ecdb3a3936721b74a0 (patch)
tree2859340e329ea6dbffe5ae9c7eba0f67a88c57af
parent20305894243e24eb383ab9feefebf4a0e9f2644f (diff)
Move unit conversion code to o3tl, and unify on that in more places
This also allows to easily add more units, both of length and for other unit categories. The conversion for "Line" unit (312 twip) is questionable. Corresponding entries in aImplFactor in vcl/source/control/field.cxx were inconsistent (45/11 in; 10/13 pc; 156/10 pt). They were added without explanation in commit c85db626029fd8a5e0dfcb312937279df32339a0. I haven't found a spec of the unit (https://en.wikipedia.org/wiki/Line_(unit) is not specific). I used the definition based on "by pt", "by mm/100", "by char" (they all were consistent); "by pc" seems inverted; "by twip" was half as much. This accepted conversion makes unit test for tdf#79236 pass. Change-Id: Iae5a21d915fa8e934a1f47f8ba9f6df03b79a9fd Reviewed-on: https://gerrit.libreoffice.org/c/core/+/110839 Tested-by: Mike Kaganski <mike.kaganski@collabora.com> Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
-rw-r--r--cui/source/tabpages/chardlg.cxx8
-rw-r--r--cui/source/tabpages/grfpage.cxx17
-rw-r--r--emfio/source/reader/wmfreader.cxx5
-rw-r--r--include/o3tl/unit_conversion.hxx231
-rw-r--r--include/oox/drawingml/drawingmltypes.hxx16
-rw-r--r--include/svtools/unitconv.hxx2
-rw-r--r--include/tools/UnitConversion.hxx136
-rw-r--r--o3tl/CppunitTest_o3tl_tests.mk1
-rw-r--r--o3tl/qa/test-unit_conversion.cxx872
-rw-r--r--oox/source/drawingml/diagram/diagram.cxx11
-rw-r--r--oox/source/drawingml/diagram/diagramlayoutatoms.cxx24
-rw-r--r--oox/source/drawingml/drawingmltypes.cxx5
-rw-r--r--oox/source/drawingml/shape.cxx14
-rw-r--r--oox/source/vml/vmlformatting.cxx28
-rw-r--r--sax/source/tools/converter.cxx585
-rw-r--r--sc/source/filter/oox/unitconverter.cxx23
-rw-r--r--sc/source/ui/vba/vbarange.cxx12
-rw-r--r--sd/qa/unit/export-tests-ooxml1.cxx4
-rw-r--r--sd/qa/unit/export-tests-ooxml2.cxx4
-rw-r--r--sd/qa/unit/import-tests.cxx4
-rw-r--r--sd/source/ui/unoidl/unomodel.cxx7
-rw-r--r--sfx2/source/view/lokcharthelper.cxx5
-rw-r--r--svtools/source/misc/unitconv.cxx445
-rw-r--r--svx/source/customshapes/EnhancedCustomShape3d.cxx4
-rw-r--r--svx/source/svdraw/svdmodel.cxx98
-rw-r--r--svx/source/svdraw/svdtrans.cxx165
-rw-r--r--sw/source/core/view/viewsh.cxx6
-rw-r--r--sw/source/filter/html/css1atr.cxx81
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx9
-rw-r--r--sw/source/filter/ww8/wrtw8esh.cxx5
-rw-r--r--sw/source/filter/ww8/ww8par6.cxx7
-rw-r--r--vcl/source/control/field.cxx116
-rw-r--r--vcl/source/gdi/pdfwriter_impl2.cxx13
-rw-r--r--vcl/source/outdev/bitmap.cxx9
-rw-r--r--vcl/source/outdev/map.cxx166
35 files changed, 1641 insertions, 1497 deletions
diff --git a/cui/source/tabpages/chardlg.cxx b/cui/source/tabpages/chardlg.cxx
index a7e3dda42bc9..6a35b45ba46f 100644
--- a/cui/source/tabpages/chardlg.cxx
+++ b/cui/source/tabpages/chardlg.cxx
@@ -59,6 +59,7 @@
#include <FontFeaturesDialog.hxx>
#include <sal/log.hxx>
#include <osl/diagnose.h>
+#include <o3tl/unit_conversion.hxx>
using namespace ::com::sun::star;
@@ -441,7 +442,9 @@ namespace
// old value, scaled
tools::Long nHeight;
if ( _pFontSizeLB->IsPtRelative() )
- nHeight = rOldItem.GetHeight() + PointToTwips( static_cast<tools::Long>(_pFontSizeLB->get_value() / 10) );
+ nHeight = rOldItem.GetHeight()
+ + o3tl::convert(_pFontSizeLB->get_value(), o3tl::Length::pt,
+ o3tl::Length::twip) / 10;
else
nHeight = static_cast<tools::Long>(rOldItem.GetHeight() * _pFontSizeLB->get_value() / 100);
@@ -450,7 +453,8 @@ namespace
ItemToControl( nHeight, _pPage->GetItemSet().GetPool()->GetMetric( _nFontHeightWhich ), FieldUnit::TWIP ) );
}
else if ( !_pFontSizeLB->get_active_text().isEmpty() )
- aSize.setHeight( PointToTwips( static_cast<tools::Long>(_pFontSizeLB->get_value() / 10) ) );
+ aSize.setHeight(o3tl::convert(_pFontSizeLB->get_value(), o3tl::Length::pt,
+ o3tl::Length::twip) / 10);
else
aSize.setHeight( 200 ); // default 10pt
aFontMetrics.SetFontSize( aSize );
diff --git a/cui/source/tabpages/grfpage.cxx b/cui/source/tabpages/grfpage.cxx
index ddc47de404c2..569329e3a160 100644
--- a/cui/source/tabpages/grfpage.cxx
+++ b/cui/source/tabpages/grfpage.cxx
@@ -38,9 +38,9 @@
#include <svtools/optionsdrawinglayer.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <o3tl/unit_conversion.hxx>
-#define CM_1_TO_TWIP 567
-#define TWIP_TO_INCH 1440
+constexpr auto CM_1_TO_TWIP = o3tl::convert(1, o3tl::Length::cm, o3tl::Length::twip); // 567
static int lcl_GetValue(const weld::MetricSpinButton& rMetric, FieldUnit eUnit)
@@ -646,16 +646,17 @@ void SvxGrfCropPage::GraphicHasChanged( bool bFound )
}
if ( aOrigPixelSize.Width() && aOrigPixelSize.Height() ) {
- sal_Int32 ax = sal_Int32(floor(static_cast<float>(aOrigPixelSize.Width()) /
- (static_cast<float>(aOrigSize.Width())/TWIP_TO_INCH)+0.5));
- sal_Int32 ay = sal_Int32(floor(static_cast<float>(aOrigPixelSize.Height()) /
- (static_cast<float>(aOrigSize.Height())/TWIP_TO_INCH)+0.5));
- sTemp += " " + CuiResId( RID_SVXSTR_PPI );
+ sal_Int32 ax = 0.5 + aOrigPixelSize.Width() /
+ o3tl::convert<double>(aOrigSize.Width(), o3tl::Length::twip,
+ o3tl::Length::in);
+ sal_Int32 ay = 0.5 + aOrigPixelSize.Height() /
+ o3tl::convert<double>(aOrigSize.Height(), o3tl::Length::twip,
+ o3tl::Length::in);
OUString sPPI = OUString::number(ax);
if (abs(ax - ay) > 1) {
sPPI += u"\u00D7" + OUString::number(ay);
}
- sTemp = sTemp.replaceAll("%1", sPPI);
+ sTemp += " " + CuiResId(RID_SVXSTR_PPI).replaceAll("%1", sPPI);
}
m_xOrigSizeFT->set_label(sTemp);
}
diff --git a/emfio/source/reader/wmfreader.cxx b/emfio/source/reader/wmfreader.cxx
index 78fee922ff35..999584b02294 100644
--- a/emfio/source/reader/wmfreader.cxx
+++ b/emfio/source/reader/wmfreader.cxx
@@ -24,6 +24,7 @@
#include <memory>
#include <optional>
#include <o3tl/safeint.hxx>
+#include <o3tl/unit_conversion.hxx>
#include <rtl/crc.h>
#include <rtl/tencinfo.h>
#include <sal/log.hxx>
@@ -1291,8 +1292,8 @@ namespace emfio
{
// #n417818#: If we have an external header then overwrite the bounds!
tools::Rectangle aExtRect(0, 0,
- static_cast<double>(mpExternalHeader->xExt) * 567 * mnUnitsPerInch / 1440000,
- static_cast<double>(mpExternalHeader->yExt) * 567 * mnUnitsPerInch / 1440000);
+ o3tl::convert(mpExternalHeader->xExt, o3tl::Length::mm100, o3tl::Length::px),
+ o3tl::convert(mpExternalHeader->yExt, o3tl::Length::mm100, o3tl::Length::px));
aPlaceableBound = aExtRect;
SAL_INFO("vcl.wmf", "External header size "
diff --git a/include/o3tl/unit_conversion.hxx b/include/o3tl/unit_conversion.hxx
new file mode 100644
index 000000000000..17dd5ae12293
--- /dev/null
+++ b/include/o3tl/unit_conversion.hxx
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <o3tl/safeint.hxx>
+#include <sal/macros.h>
+#include <sal/types.h>
+
+#include <array>
+#include <cassert>
+#include <utility>
+#include <type_traits>
+
+namespace o3tl
+{
+// Length units
+enum class Length
+{
+ mm100 = 0, // 1/100th mm
+ mm10, // 1/10 mm, corresponds to MapUnit::Map10thMM
+ mm, // millimeter
+ cm, // centimeter
+ m, // meter
+ km, // kilometer
+ emu, // English Metric Unit: 1/360000 cm, 1/914400 in
+ twip, // "Twentieth of a point" aka "dxa": 1/20 pt
+ pt, // Point: 1/72 in
+ pc, // Pica: 1/6 in, corresponds to FieldUnit::PICA and MeasureUnit::PICA
+ in1000, // 1/1000 in, corresponds to MapUnit::Map1000thInch
+ in100, // 1/100 in, corresponds to MapUnit::Map100thInch
+ in10, // 1/10 in, corresponds to MapUnit::Map10thInch
+ in, // inch
+ ft, // foot
+ mi, // mile
+ master, // PPT Master Unit: 1/576 in
+ px, // "pixel" unit: 15 twip (96 ppi), corresponds to MeasureUnit::PIXEL
+ ch, // "char" unit: 210 twip (14 px), corresponds to FieldUnit::CHAR
+ line, // "line" unit: 312 twip, corresponds to FieldUnit::LINE
+ count, // <== add new units above this last entry
+ invalid = -1
+};
+
+// If other categories of units would be needed (like time), a separate scoped enum
+// should be created, respective conversion array prepared in detail namespace, and
+// respective md(NewUnit, NewUnit) overload introduced, which would allow using
+// o3tl::convert() and o3tl::convertSanitize() with the new category in a type-safe
+// way, without mixing unrelated units.
+
+namespace detail
+{
+// Common utilities
+
+// A special function to avoid compiler warning comparing signed and unsigned values
+template <typename I> constexpr bool isBetween(I n, sal_Int64 min, sal_Int64 max)
+{
+ assert(max > 0 && min < 0);
+ if constexpr (std::is_signed_v<I>)
+ return n >= min && n <= max;
+ else
+ return n <= sal_uInt64(max);
+}
+
+// Ensure correct rounding for both positive and negative integers
+template <typename I, std::enable_if_t<std::is_integral_v<I>, int> = 0>
+constexpr sal_Int64 MulDiv(I n, sal_Int64 m, sal_Int64 d)
+{
+ assert(m > 0 && d > 0);
+ assert(isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m));
+ return (n >= 0 ? (n * m + d / 2) : (n * m - d / 2)) / d;
+}
+template <typename F, std::enable_if_t<std::is_floating_point_v<F>, int> = 0>
+constexpr double MulDiv(F f, sal_Int64 m, sal_Int64 d)
+{
+ assert(m > 0 && d > 0);
+ return f * (double(m) / d);
+}
+
+template <typename I, std::enable_if_t<std::is_integral_v<I>, int> = 0>
+constexpr sal_Int64 MulDiv(I n, sal_Int64 m, sal_Int64 d, bool& bOverflow, sal_Int64 nDefault)
+{
+ if (!isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m))
+ {
+ bOverflow = true;
+ return nDefault;
+ }
+ bOverflow = false;
+ return MulDiv(n, m, d);
+}
+
+template <typename I, std::enable_if_t<std::is_integral_v<I>, int> = 0>
+constexpr sal_Int64 MulDivSaturate(I n, sal_Int64 m, sal_Int64 d)
+{
+ if (!isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m))
+ {
+ if (m > d && !isBetween(n, SAL_MIN_INT64 / m * d + d / 2, SAL_MAX_INT64 / m * d - d / 2))
+ return n > 0 ? SAL_MAX_INT64 : SAL_MIN_INT64; // saturate
+ return (n >= 0 ? n + d / 2 : n - d / 2) / d * m; // divide before multiplication
+ }
+ return MulDiv(n, m, d);
+}
+
+// Greatest common divisor
+constexpr int gcd(sal_Int64 a, sal_Int64 b) { return b == 0 ? a : gcd(b, a % b); }
+
+// Packs integral multiplier and divisor for conversion from one unit to another
+struct m_and_d
+{
+ sal_Int64 m; // multiplier
+ sal_Int64 d; // divisor
+ constexpr m_and_d(sal_Int64 _m, sal_Int64 _d)
+ : m(_m / gcd(_m, _d)) // make sure to use smallest quotients here because
+ , d(_d / gcd(_m, _d)) // they will be multiplied when building final table
+ {
+ assert(_m > 0 && _d > 0);
+ }
+};
+
+// Resulting static array N x N of all quotients to convert between all units. The
+// quotients are minimal to allow largest range of converted numbers without overflow.
+// Maybe o3tl::enumarray could be used here, but it's not constexpr yet.
+template <int N> constexpr auto prepareMDArray(const m_and_d (&mdBase)[N])
+{
+ std::array<std::array<sal_Int64, N>, N> a{};
+ for (int i = 0; i < N; ++i)
+ {
+ for (int j = 0; j <= i; ++j)
+ {
+ if (i == j)
+ a[i][j] = 1;
+ else
+ {
+ assert(mdBase[i].m < SAL_MAX_INT64 / mdBase[j].d);
+ assert(mdBase[i].d < SAL_MAX_INT64 / mdBase[j].m);
+ const sal_Int64 m = mdBase[i].m * mdBase[j].d, d = mdBase[i].d * mdBase[j].m;
+ const sal_Int64 g = gcd(m, d);
+ a[i][j] = m / g;
+ a[j][i] = d / g;
+ }
+ }
+ }
+ return a;
+}
+
+// Length units implementation
+
+// Array of conversion quotients for mm, used to build final conversion table. Entries
+// are { multiplier, divider } to convert respective unit *to* mm. Order of elements
+// corresponds to order in o3tl::Length enum (Length::count and Length::invalid omitted).
+constexpr m_and_d mdBaseLen[] = {
+ { 1, 100 }, // mm100 => mm
+ { 1, 10 }, // mm10 => mm
+ { 1, 1 }, // mm => mm
+ { 10, 1 }, // cm => mm
+ { 1000, 1 }, // m => mm
+ { 1000000, 1 }, // km => mm
+ { 1, 36000 }, // emu => mm
+ { 254, 10 * 1440 }, // twip => mm
+ { 254, 10 * 72 }, // pt => mm
+ { 254, 10 * 6 }, // pc => mm
+ { 254, 10000 }, // in1000 => mm
+ { 254, 1000 }, // in100 => mm
+ { 254, 100 }, // in10 => mm
+ { 254, 10 }, // in => mm
+ { 254 * 12, 10 }, // ft => mm
+ { 254 * 12 * 5280, 10 }, // mi => mm
+ { 254, 10 * 576 }, // master => mm
+ { 254 * 15, 10 * 1440 }, // px => mm
+ { 254 * 210, 10 * 1440 }, // ch => mm
+ { 254 * 312, 10 * 1440 }, // line => mm
+};
+static_assert(SAL_N_ELEMENTS(mdBaseLen) == static_cast<int>(Length::count),
+ "mdBaseL must have an entry for each unit in o3tl::Length");
+
+// an overload taking Length
+constexpr sal_Int64 md(Length i, Length j)
+{
+ // The resulting multipliers and divisors array
+ constexpr auto aMDArray = prepareMDArray(mdBaseLen);
+
+ const int nI = static_cast<int>(i), nJ = static_cast<int>(j);
+ assert(nI >= 0 && o3tl::make_unsigned(nI) < aMDArray.size());
+ assert(nJ >= 0 && o3tl::make_unsigned(nJ) < aMDArray.size());
+ return aMDArray[nI][nJ];
+}
+
+// here might go overloads of md() taking other units ...
+}
+
+// Unchecked conversion. Takes a number value, multiplier and divisor
+template <typename N> constexpr auto convert(N n, sal_Int64 mul, sal_Int64 div)
+{
+ return detail::MulDiv(n, mul, div);
+}
+
+// Unchecked conversion. Takes a number value and units defined in this header
+template <typename N, typename U> constexpr auto convert(N n, U from, U to)
+{
+ return convert(n, detail::md(from, to), detail::md(to, from));
+}
+
+// Returns nDefault if intermediate multiplication overflows sal_Int64 (only for integral types).
+// On return, bOverflow indicates if overflow happened.
+template <typename N, typename U>
+constexpr auto convert(N n, U from, U to, bool& bOverflow, sal_Int64 nDefault = 0)
+{
+ return detail::MulDiv(n, detail::md(from, to), detail::md(to, from), bOverflow, nDefault);
+}
+
+// Conversion with saturation (only for integral types). For too large input returns SAL_MAX_INT64.
+// When intermediate multiplication would overflow, but otherwise result in in sal_Int64 range, the
+// precision is decreased because of inversion of multiplication and division.
+template <typename N, typename U> constexpr auto convertSaturate(N n, U from, U to)
+{
+ return detail::MulDivSaturate(n, detail::md(from, to), detail::md(to, from));
+}
+
+// Return a pair { multiplier, divisor } for a given conversion
+template <typename U> constexpr std::pair<sal_Int64, sal_Int64> getConversionMulDiv(U from, U to)
+{
+ return { detail::md(from, to), detail::md(to, from) };
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/include/oox/drawingml/drawingmltypes.hxx b/include/oox/drawingml/drawingmltypes.hxx
index b8693c00fdeb..c24bff255a3e 100644
--- a/include/oox/drawingml/drawingmltypes.hxx
+++ b/include/oox/drawingml/drawingmltypes.hxx
@@ -31,6 +31,7 @@
#include <com/sun/star/style/TabAlign.hpp>
#include <com/sun/star/uno/Reference.hxx>
#include <o3tl/safeint.hxx>
+#include <o3tl/unit_conversion.hxx>
#include <oox/dllapi.h>
#include <oox/helper/helper.hxx>
#include <rtl/ustring.hxx>
@@ -171,33 +172,30 @@ inline OString calcRotationValue(sal_Int32 nRotation)
return OString::number(nRotation);
}
-const sal_Int32 EMU_PER_HMM = 360; /// 360 EMUs per 1/100 mm.
-const sal_Int32 EMU_PER_PT = 12700;
-
/** Converts the passed 32-bit integer value from 1/100 mm to EMUs. */
inline sal_Int64 convertHmmToEmu( sal_Int32 nValue )
{
- return static_cast< sal_Int64 >( nValue ) * EMU_PER_HMM;
+ return o3tl::convert(nValue, o3tl::Length::mm100, o3tl::Length::emu);
}
/** Converts the passed 64-bit integer value from EMUs to 1/100 mm. */
inline sal_Int32 convertEmuToHmm( sal_Int64 nValue )
{
- sal_Int32 nCorrection = (nValue > 0 ? 1 : -1) * EMU_PER_HMM / 2; // So that the implicit floor will round.
- return getLimitedValue<sal_Int32, sal_Int64>(o3tl::saturating_add<sal_Int64>(nValue, nCorrection) / EMU_PER_HMM, SAL_MIN_INT32, SAL_MAX_INT32);
+ return getLimitedValue<sal_Int32, sal_Int64>(
+ o3tl::convert(nValue, o3tl::Length::emu, o3tl::Length::mm100), SAL_MIN_INT32,
+ SAL_MAX_INT32);
}
/** Converts the passed 64-bit integer value from EMUs to Points. */
inline float convertEmuToPoints( sal_Int64 nValue )
{
- return static_cast<float>(nValue) / EMU_PER_PT;
+ return o3tl::convert<double>(nValue, o3tl::Length::emu, o3tl::Length::pt);
}
/** Converts the passed double value from points to mm. */
inline double convertPointToMms(double fValue)
{
- constexpr double fFactor = static_cast<double>(EMU_PER_PT) / (EMU_PER_HMM * 100);
- return fValue * fFactor;
+ return o3tl::convert(fValue, o3tl::Length::pt, o3tl::Length::mm);
}
/** A structure for a point with 64-bit integer components. */
diff --git a/include/svtools/unitconv.hxx b/include/svtools/unitconv.hxx
index 34025261e46c..88bbffc146e5 100644
--- a/include/svtools/unitconv.hxx
+++ b/include/svtools/unitconv.hxx
@@ -46,8 +46,6 @@ SVT_DLLPUBLIC FieldUnit MapToFieldUnit( const MapUnit eUnit );
SVT_DLLPUBLIC void SetMetricValue(weld::MetricSpinButton& rField, int lCoreValue, MapUnit eUnit);
SVT_DLLPUBLIC int GetCoreValue(const weld::MetricSpinButton& rField, MapUnit eUnit);
-SVT_DLLPUBLIC tools::Long PointToTwips( tools::Long nIn );
-
SVT_DLLPUBLIC tools::Long TransformMetric( tools::Long nVal, FieldUnit aOld, FieldUnit aNew );
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/tools/UnitConversion.hxx b/include/tools/UnitConversion.hxx
index 802a372a546d..7d3bdf565c1d 100644
--- a/include/tools/UnitConversion.hxx
+++ b/include/tools/UnitConversion.hxx
@@ -10,61 +10,117 @@
#pragma once
+#include <o3tl/unit_conversion.hxx>
#include <sal/types.h>
-#include <cassert>
-#include <type_traits>
+#include <tools/fldunit.hxx>
+#include <tools/fract.hxx>
+#include <tools/mapunit.hxx>
-template <typename I> constexpr bool isBetween(I n, sal_Int64 min, sal_Int64 max)
+constexpr o3tl::Length FieldToO3tlLength(FieldUnit eU, o3tl::Length ePixelValue = o3tl::Length::px)
{
- assert(max > 0 && min < 0);
- if constexpr (std::is_signed_v<I>)
- return n >= min && n <= max;
- else
- return n <= sal_uInt64(max);
+ switch (eU)
+ {
+ case FieldUnit::MM:
+ return o3tl::Length::mm;
+ case FieldUnit::CM:
+ return o3tl::Length::cm;
+ case FieldUnit::M:
+ return o3tl::Length::m;
+ case FieldUnit::KM:
+ return o3tl::Length::km;
+ case FieldUnit::TWIP:
+ return o3tl::Length::twip;
+ case FieldUnit::POINT:
+ return o3tl::Length::pt;
+ case FieldUnit::PICA:
+ return o3tl::Length::pc;
+ case FieldUnit::INCH:
+ return o3tl::Length::in;
+ case FieldUnit::FOOT:
+ return o3tl::Length::ft;
+ case FieldUnit::MILE:
+ return o3tl::Length::mi;
+ case FieldUnit::CHAR:
+ return o3tl::Length::ch;
+ case FieldUnit::LINE:
+ return o3tl::Length::line;
+ case FieldUnit::MM_100TH:
+ return o3tl::Length::mm100;
+ case FieldUnit::PIXEL:
+ return ePixelValue;
+ default:
+ return o3tl::Length::invalid;
+ }
}
-constexpr int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
-
-// Ensure correct rounding for both positive and negative integers
-template <int mul, int div, typename I, std::enable_if_t<std::is_integral_v<I>, int> = 0>
-constexpr sal_Int64 MulDiv(I n)
+constexpr o3tl::Length MapToO3tlLength(MapUnit eU, o3tl::Length ePixelValue = o3tl::Length::px)
{
- static_assert(mul > 0 && div > 0);
- constexpr int m = mul / gcd(mul, div), d = div / gcd(mul, div);
- assert(isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m));
- return (n >= 0 ? (sal_Int64(n) * m + d / 2) : (sal_Int64(n) * m - d / 2)) / d;
+ switch (eU)
+ {
+ case MapUnit::Map100thMM:
+ return o3tl::Length::mm100;
+ case MapUnit::Map10thMM:
+ return o3tl::Length::mm10;
+ case MapUnit::MapMM:
+ return o3tl::Length::mm;
+ case MapUnit::MapCM:
+ return o3tl::Length::cm;
+ case MapUnit::Map1000thInch:
+ return o3tl::Length::in1000;
+ case MapUnit::Map100thInch:
+ return o3tl::Length::in100;
+ case MapUnit::Map10thInch:
+ return o3tl::Length::in10;
+ case MapUnit::MapInch:
+ return o3tl::Length::in;
+ case MapUnit::MapPoint:
+ return o3tl::Length::pt;
+ case MapUnit::MapTwip:
+ return o3tl::Length::twip;
+ case MapUnit::MapPixel:
+ return ePixelValue;
+ default:
+ return o3tl::Length::invalid;
+ }
}
-template <int mul, int div, typename F, std::enable_if_t<std::is_floating_point_v<F>, int> = 0>
-constexpr double MulDiv(F f)
+
+inline Fraction conversionFract(o3tl::Length from, o3tl::Length to)
{
- static_assert(mul > 0 && div > 0);
- return f * (double(mul) / div);
+ const auto & [ mul, div ] = o3tl::getConversionMulDiv(from, to);
+ return { mul, div };
}
-template <int mul, int div, typename I, std::enable_if_t<std::is_integral_v<I>, int> = 0>
-constexpr sal_Int64 sanitizeMulDiv(I n)
+template <typename N> constexpr auto convertTwipToMm100(N n)
{
- constexpr int m = mul / gcd(mul, div), d = div / gcd(mul, div);
- if constexpr (m > d)
- if (!isBetween(n, SAL_MIN_INT64 / m * d + d / 2, SAL_MAX_INT64 / m * d - d / 2))
- return n > 0 ? SAL_MAX_INT64 : SAL_MIN_INT64; // saturate
- if (!isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m))
- return (n >= 0 ? n + d / 2 : n - d / 2) / d * m; // divide before multiplication
- return MulDiv<mul, div>(n);
+ return o3tl::convert(n, o3tl::Length::twip, o3tl::Length::mm100);
+}
+template <typename N> constexpr auto convertMm100ToTwip(N n)
+{
+ return o3tl::convert(n, o3tl::Length::mm100, o3tl::Length::twip);
}
-template <typename N> constexpr auto convertTwipToMm100(N n) { return MulDiv<127, 72>(n); }
-template <typename N> constexpr auto convertMm100ToTwip(N n) { return MulDiv<72, 127>(n); }
-
-constexpr sal_Int64 sanitiseMm100ToTwip(sal_Int64 n) { return sanitizeMulDiv<72, 127>(n); }
-
-template <typename N> constexpr auto convertPointToTwip(N n) { return MulDiv<20, 1>(n); }
+constexpr sal_Int64 sanitiseMm100ToTwip(sal_Int64 n)
+{
+ return o3tl::convertSaturate(n, o3tl::Length::mm100, o3tl::Length::twip);
+}
-template <typename N> constexpr auto convertPointToMm100(N n) { return MulDiv<2540, 72>(n); }
-template <typename N> constexpr auto convertMm100ToPoint(N n) { return MulDiv<72, 2540>(n); }
+template <typename N> constexpr auto convertPointToMm100(N n)
+{
+ return o3tl::convert(n, o3tl::Length::pt, o3tl::Length::mm100);
+}
+template <typename N> constexpr auto convertMm100ToPoint(N n)
+{
+ return o3tl::convert(n, o3tl::Length::mm100, o3tl::Length::pt);
+}
// PPT's "master unit" (1/576 inch) <=> mm/100
-template <typename N> constexpr auto convertMasterUnitToMm100(N n) { return MulDiv<2540, 576>(n); }
-template <typename N> constexpr auto convertMm100ToMasterUnit(N n) { return MulDiv<576, 2540>(n); }
+template <typename N> constexpr auto convertMasterUnitToMm100(N n)
+{
+ return o3tl::convert(n, o3tl::Length::master, o3tl::Length::mm100);
+}
+template <typename N> constexpr auto convertMm100ToMasterUnit(N n)
+{
+ return o3tl::convert(n, o3tl::Length::mm100, o3tl::Length::master);
+}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/o3tl/CppunitTest_o3tl_tests.mk b/o3tl/CppunitTest_o3tl_tests.mk
index 07229a9384b1..6866778f6c1a 100644
--- a/o3tl/CppunitTest_o3tl_tests.mk
+++ b/o3tl/CppunitTest_o3tl_tests.mk
@@ -35,6 +35,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,o3tl_tests,\
o3tl/qa/test-span \
o3tl/qa/test-temporary \
o3tl/qa/test-typed_flags \
+ o3tl/qa/test-unit_conversion \
o3tl/qa/test-vector_pool \
))
diff --git a/o3tl/qa/test-unit_conversion.cxx b/o3tl/qa/test-unit_conversion.cxx
new file mode 100644
index 000000000000..72a0e9b1f43c
--- /dev/null
+++ b/o3tl/qa/test-unit_conversion.cxx
@@ -0,0 +1,872 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/unit_conversion.hxx>
+
+// Just some static asserts
+
+namespace
+{
+constexpr double const_abs(double f) { return f >= 0 ? f : -f; }
+constexpr bool eq(double a, double b) { return const_abs(a - b) < 1E-6; }
+bool eq(sal_Int64, double) = delete;
+}
+
+// testing floating-point conversion
+
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm100, o3tl::Length::mm100), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm10, o3tl::Length::mm100), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm, o3tl::Length::mm100), 100));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::cm, o3tl::Length::mm100), 1000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::mm100), 100000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::mm100), 100E6));
+static_assert(eq(o3tl::convert(360.0, o3tl::Length::emu, o3tl::Length::mm100), 1));
+static_assert(eq(o3tl::convert(72.0, o3tl::Length::twip, o3tl::Length::mm100), 127));
+static_assert(eq(o3tl::convert(18.0, o3tl::Length::pt, o3tl::Length::mm100), 635));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pc, o3tl::Length::mm100), 1270));
+static_assert(eq(o3tl::convert(50.0, o3tl::Length::in1000, o3tl::Length::mm100), 127));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in100, o3tl::Length::mm100), 127));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::mm100), 254));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::mm100), 2540));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::mm100), 30480));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::mm100), 160934400));
+static_assert(eq(o3tl::convert(144.0, o3tl::Length::master, o3tl::Length::mm100), 635));
+static_assert(eq(o3tl::convert(24.0, o3tl::Length::px, o3tl::Length::mm100), 635));
+static_assert(eq(o3tl::convert(12.0, o3tl::Length::ch, o3tl::Length::mm100), 4445));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::line, o3tl::Length::mm100), 1651));
+
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::mm100, o3tl::Length::mm10), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm10, o3tl::Length::mm10), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm, o3tl::Length::mm10), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::cm, o3tl::Length::mm10), 100));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::mm10), 10000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::mm10), 10E6));
+static_assert(eq(o3tl::convert(3600.0, o3tl::Length::emu, o3tl::Length::mm10), 1));
+static_assert(eq(o3tl::convert(720.0, o3tl::Length::twip, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(36.0, o3tl::Length::pt, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pc, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(500.0, o3tl::Length::in1000, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(50.0, o3tl::Length::in100, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in10, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::mm10), 254));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::mm10), 3048));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::mm10), 16093440));
+static_assert(eq(o3tl::convert(288.0, o3tl::Length::master, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(48.0, o3tl::Length::px, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(24.0, o3tl::Length::ch, o3tl::Length::mm10), 889));
+static_assert(eq(o3tl::convert(30.0, o3tl::Length::line, o3tl::Length::mm10), 1651));
+
+static_assert(eq(o3tl::convert(100.0, o3tl::Length::mm100, o3tl::Length::mm), 1));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::mm10, o3tl::Length::mm), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm, o3tl::Length::mm), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::cm, o3tl::Length::mm), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::mm), 1000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::mm), 1E6));
+static_assert(eq(o3tl::convert(36000.0, o3tl::Length::emu, o3tl::Length::mm), 1));
+static_assert(eq(o3tl::convert(7200.0, o3tl::Length::twip, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(360.0, o3tl::Length::pt, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(30.0, o3tl::Length::pc, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(5000.0, o3tl::Length::in1000, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(500.0, o3tl::Length::in100, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(50.0, o3tl::Length::in10, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::ft, o3tl::Length::mm), 1524));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::mm), 1609344));
+static_assert(eq(o3tl::convert(2880.0, o3tl::Length::master, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(480.0, o3tl::Length::px, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(240.0, o3tl::Length::ch, o3tl::Length::mm), 889));
+static_assert(eq(o3tl::convert(300.0, o3tl::Length::line, o3tl::Length::mm), 1651));
+
+static_assert(eq(o3tl::convert(1000.0, o3tl::Length::mm100, o3tl::Length::cm), 1));
+static_assert(eq(o3tl::convert(100.0, o3tl::Length::mm10, o3tl::Length::cm), 1));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::mm, o3tl::Length::cm), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::cm, o3tl::Length::cm), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::cm), 100));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::cm), 100000));
+static_assert(eq(o3tl::convert(360000.0, o3tl::Length::emu, o3tl::Length::cm), 1));
+static_assert(eq(o3tl::convert(72000.0, o3tl::Length::twip, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(3600.0, o3tl::Length::pt, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(300.0, o3tl::Length::pc, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(50000.0, o3tl::Length::in1000, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(5000.0, o3tl::Length::in100, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(500.0, o3tl::Length::in10, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(50.0, o3tl::Length::in, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(25.0, o3tl::Length::ft, o3tl::Length::cm), 762));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::mi, o3tl::Length::cm), 804672));
+static_assert(eq(o3tl::convert(28800.0, o3tl::Length::master, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(4800.0, o3tl::Length::px, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(2400.0, o3tl::Length::ch, o3tl::Length::cm), 889));
+static_assert(eq(o3tl::convert(3000.0, o3tl::Length::line, o3tl::Length::cm), 1651));
+
+static_assert(eq(o3tl::convert(100000.0, o3tl::Length::mm100, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(10000.0, o3tl::Length::mm10, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(1000.0, o3tl::Length::mm, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(100.0, o3tl::Length::cm, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::m), 1000));
+static_assert(eq(o3tl::convert(36E6, o3tl::Length::emu, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(7200000.0, o3tl::Length::twip, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(360000.0, o3tl::Length::pt, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(30000.0, o3tl::Length::pc, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(5000000.0, o3tl::Length::in1000, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(500000.0, o3tl::Length::in100, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(50000.0, o3tl::Length::in10, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(5000.0, o3tl::Length::in, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(1250.0, o3tl::Length::ft, o3tl::Length::m), 381));
+static_assert(eq(o3tl::convert(125.0, o3tl::Length::mi, o3tl::Length::m), 201168));
+static_assert(eq(o3tl::convert(2880000.0, o3tl::Length::master, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(480000.0, o3tl::Length::px, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(240000.0, o3tl::Length::ch, o3tl::Length::m), 889));
+static_assert(eq(o3tl::convert(300000.0, o3tl::Length::line, o3tl::Length::m), 1651));
+
+static_assert(eq(o3tl::convert(100E6, o3tl::Length::mm100, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(10E6, o3tl::Length::mm10, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(1E6, o3tl::Length::mm, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(100000.0, o3tl::Length::cm, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(1000.0, o3tl::Length::m, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(36E9, o3tl::Length::emu, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(7200E6, o3tl::Length::twip, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(360E6, o3tl::Length::pt, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(30E6, o3tl::Length::pc, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(5E9, o3tl::Length::in1000, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(500E6, o3tl::Length::in100, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(50E6, o3tl::Length::in10, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(5E6, o3tl::Length::in, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(1250000.0, o3tl::Length::ft, o3tl::Length::km), 381));
+static_assert(eq(o3tl::convert(15625.0, o3tl::Length::mi, o3tl::Length::km), 25146));
+static_assert(eq(o3tl::convert(2880E6, o3tl::Length::master, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(480E6, o3tl::Length::px, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(240E6, o3tl::Length::ch, o3tl::Length::km), 889));
+static_assert(eq(o3tl::convert(300E6, o3tl::Length::line, o3tl::Length::km), 1651));
+
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm100, o3tl::Length::emu), 360));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm10, o3tl::Length::emu), 3600));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm, o3tl::Length::emu), 36000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::cm, o3tl::Length::emu), 360000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::emu), 36E6));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::emu), 36E9));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::emu, o3tl::Length::emu), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::emu), 635));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pt, o3tl::Length::emu), 12700));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::emu), 152400));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in1000, o3tl::Length::emu), 4572));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in100, o3tl::Length::emu), 9144));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::emu), 91440));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::emu), 914400));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::emu), 10972800));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::emu), 57936384000));
+static_assert(eq(o3tl::convert(2.0, o3tl::Length::master, o3tl::Length::emu), 3175));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::px, o3tl::Length::emu), 9525));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ch, o3tl::Length::emu), 133350));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::line, o3tl::Length::emu), 198120));
+
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm100, o3tl::Length::twip), 72));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::twip), 720));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::twip), 7200));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::twip), 72000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::twip), 7200000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::twip), 7200E6));
+static_assert(eq(o3tl::convert(635.0, o3tl::Length::emu, o3tl::Length::twip), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::twip), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pt, o3tl::Length::twip), 20));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::twip), 240));
+static_assert(eq(o3tl::convert(25.0, o3tl::Length::in1000, o3tl::Length::twip), 36));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in100, o3tl::Length::twip), 72));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::twip), 144));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::twip), 1440));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::twip), 17280));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::twip), 91238400));
+static_assert(eq(o3tl::convert(2.0, o3tl::Length::master, o3tl::Length::twip), 5));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::px, o3tl::Length::twip), 15));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ch, o3tl::Length::twip), 210));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::line, o3tl::Length::twip), 312));
+
+static_assert(eq(o3tl::convert(635.0, o3tl::Length::mm100, o3tl::Length::pt), 18));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::pt), 36));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::pt), 360));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::pt), 3600));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::pt), 360000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::pt), 360E6));
+static_assert(eq(o3tl::convert(12700.0, o3tl::Length::emu, o3tl::Length::pt), 1));
+static_assert(eq(o3tl::convert(20.0, o3tl::Length::twip, o3tl::Length::pt), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pt, o3tl::Length::pt), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::pt), 12));
+static_assert(eq(o3tl::convert(125.0, o3tl::Length::in1000, o3tl::Length::pt), 9));
+static_assert(eq(o3tl::convert(25.0, o3tl::Length::in100, o3tl::Length::pt), 18));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in10, o3tl::Length::pt), 36));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::pt), 72));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::pt), 864));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::pt), 4561920));
+static_assert(eq(o3tl::convert(8.0, o3tl::Length::master, o3tl::Length::pt), 1));
+static_assert(eq(o3tl::convert(4.0, o3tl::Length::px, o3tl::Length::pt), 3));
+static_assert(eq(o3tl::convert(2.0, o3tl::Length::ch, o3tl::Length::pt), 21));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::line, o3tl::Length::pt), 78));
+
+static_assert(eq(o3tl::convert(1270.0, o3tl::Length::mm100, o3tl::Length::pc), 3));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::pc), 3));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::pc), 30));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::pc), 300));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::pc), 30000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::pc), 30E6));
+static_assert(eq(o3tl::convert(152400.0, o3tl::Length::emu, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(240.0, o3tl::Length::twip, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(12.0, o3tl::Length::pt, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(500.0, o3tl::Length::in1000, o3tl::Length::pc), 3));
+static_assert(eq(o3tl::convert(50.0, o3tl::Length::in100, o3tl::Length::pc), 3));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in10, o3tl::Length::pc), 3));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::pc), 6));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::pc), 72));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::pc), 380160));
+static_assert(eq(o3tl::convert(96.0, o3tl::Length::master, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(16.0, o3tl::Length::px, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(8.0, o3tl::Length::ch, o3tl::Length::pc), 7));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::line, o3tl::Length::pc), 13));
+
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm100, o3tl::Length::in1000), 50));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::in1000), 500));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::in1000), 5000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::in1000), 50000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::in1000), 5E6));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::in1000), 5E9));
+static_assert(eq(o3tl::convert(4572.0, o3tl::Length::emu, o3tl::Length::in1000), 5));
+static_assert(eq(o3tl::convert(36.0, o3tl::Length::twip, o3tl::Length::in1000), 25));
+static_assert(eq(o3tl::convert(9.0, o3tl::Length::pt, o3tl::Length::in1000), 125));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pc, o3tl::Length::in1000), 500));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in1000, o3tl::Length::in1000), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in100, o3tl::Length::in1000), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::in1000), 100));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::in1000), 1000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::in1000), 12000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::in1000), 63360000));
+static_assert(eq(o3tl::convert(72.0, o3tl::Length::master, o3tl::Length::in1000), 125));
+static_assert(eq(o3tl::convert(12.0, o3tl::Length::px, o3tl::Length::in1000), 125));
+static_assert(eq(o3tl::convert(6.0, o3tl::Length::ch, o3tl::Length::in1000), 875));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::line, o3tl::Length::in1000), 650));
+
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm100, o3tl::Length::in100), 5));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::in100), 50));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::in100), 500));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::in100), 5000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::in100), 500000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::in100), 500E6));
+static_assert(eq(o3tl::convert(9144.0, o3tl::Length::emu, o3tl::Length::in100), 1));
+static_assert(eq(o3tl::convert(72.0, o3tl::Length::twip, o3tl::Length::in100), 5));
+static_assert(eq(o3tl::convert(18.0, o3tl::Length::pt, o3tl::Length::in100), 25));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pc, o3tl::Length::in100), 50));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::in1000, o3tl::Length::in100), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in100, o3tl::Length::in100), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::in100), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::in100), 100));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::in100), 1200));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::in100), 6336000));
+static_assert(eq(o3tl::convert(144.0, o3tl::Length::master, o3tl::Length::in100), 25));
+static_assert(eq(o3tl::convert(24.0, o3tl::Length::px, o3tl::Length::in100), 25));
+static_assert(eq(o3tl::convert(12.0, o3tl::Length::ch, o3tl::Length::in100), 175));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::line, o3tl::Length::in100), 65));
+
+static_assert(eq(o3tl::convert(254.0, o3tl::Length::mm100, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::in10), 5));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::in10), 50));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::in10), 500));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::in10), 50000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::in10), 50E6));
+static_assert(eq(o3tl::convert(91440.0, o3tl::Length::emu, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(144.0, o3tl::Length::twip, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(36.0, o3tl::Length::pt, o3tl::Length::in10), 5));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pc, o3tl::Length::in10), 5));
+static_assert(eq(o3tl::convert(100.0, o3tl::Length::in1000, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::in100, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::in10), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::in10), 120));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::in10), 633600));
+static_assert(eq(o3tl::convert(288.0, o3tl::Length::master, o3tl::Length::in10), 5));
+static_assert(eq(o3tl::convert(48.0, o3tl::Length::px, o3tl::Length::in10), 5));
+static_assert(eq(o3tl::convert(24.0, o3tl::Length::ch, o3tl::Length::in10), 35));
+static_assert(eq(o3tl::convert(6.0, o3tl::Length::line, o3tl::Length::in10), 13));
+
+static_assert(eq(o3tl::convert(2540.0, o3tl::Length::mm100, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(254.0, o3tl::Length::mm10, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::in), 5));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::in), 50));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::in), 5000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::in), 5E6));
+static_assert(eq(o3tl::convert(914400.0, o3tl::Length::emu, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(1440.0, o3tl::Length::twip, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(72.0, o3tl::Length::pt, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(6.0, o3tl::Length::pc, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(1000.0, o3tl::Length::in1000, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(100.0, o3tl::Length::in100, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::in10, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::in), 12));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::in), 63360));
+static_assert(eq(o3tl::convert(576.0, o3tl::Length::master, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(96.0, o3tl::Length::px, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(48.0, o3tl::Length::ch, o3tl::Length::in), 7));
+static_assert(eq(o3tl::convert(60.0, o3tl::Length::line, o3tl::Length::in), 13));
+
+static_assert(eq(o3tl::convert(30480.0, o3tl::Length::mm100, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(3048.0, o3tl::Length::mm10, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(1524.0, o3tl::Length::mm, o3tl::Length::ft), 5));
+static_assert(eq(o3tl::convert(762.0, o3tl::Length::cm, o3tl::Length::ft), 25));
+static_assert(eq(o3tl::convert(381.0, o3tl::Length::m, o3tl::Length::ft), 1250));
+static_assert(eq(o3tl::convert(381.0, o3tl::Length::km, o3tl::Length::ft), 1250000));
+static_assert(eq(o3tl::convert(10972800.0, o3tl::Length::emu, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(17280.0, o3tl::Length::twip, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(864.0, o3tl::Length::pt, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(72.0, o3tl::Length::pc, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(12000.0, o3tl::Length::in1000, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(1200.0, o3tl::Length::in100, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(120.0, o3tl::Length::in10, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(12.0, o3tl::Length::in, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::ft), 5280));
+static_assert(eq(o3tl::convert(6912.0, o3tl::Length::master, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(1152.0, o3tl::Length::px, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(576.0, o3tl::Length::ch, o3tl::Length::ft), 7));
+static_assert(eq(o3tl::convert(720.0, o3tl::Length::line, o3tl::Length::ft), 13));
+
+static_assert(eq(o3tl::convert(160934400.0, o3tl::Length::mm100, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(16093440.0, o3tl::Length::mm10, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(1609344.0, o3tl::Length::mm, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(804672.0, o3tl::Length::cm, o3tl::Length::mi), 5));
+static_assert(eq(o3tl::convert(201168.0, o3tl::Length::m, o3tl::Length::mi), 125));
+static_assert(eq(o3tl::convert(25146.0, o3tl::Length::km, o3tl::Length::mi), 15625));
+static_assert(eq(o3tl::convert(57936384000.0, o3tl::Length::emu, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(91238400.0, o3tl::Length::twip, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(4561920.0, o3tl::Length::pt, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(380160.0, o3tl::Length::pc, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(63360000.0, o3tl::Length::in1000, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(6336000.0, o3tl::Length::in100, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(633600.0, o3tl::Length::in10, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(63360.0, o3tl::Length::in, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(5280.0, o3tl::Length::ft, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(36495360.0, o3tl::Length::master, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(6082560.0, o3tl::Length::px, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(3041280.0, o3tl::Length::ch, o3tl::Length::mi), 7));
+static_assert(eq(o3tl::convert(3801600.0, o3tl::Length::line, o3tl::Length::mi), 13));
+
+static_assert(eq(o3tl::convert(635.0, o3tl::Length::mm100, o3tl::Length::master), 144));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::master), 288));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::master), 2880));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::master), 28800));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::master), 2880000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::master), 2880E6));
+static_assert(eq(o3tl::convert(3175.0, o3tl::Length::emu, o3tl::Length::master), 2));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::twip, o3tl::Length::master), 2));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pt, o3tl::Length::master), 8));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::master), 96));
+static_assert(eq(o3tl::convert(125.0, o3tl::Length::in1000, o3tl::Length::master), 72));
+static_assert(eq(o3tl::convert(25.0, o3tl::Length::in100, o3tl::Length::master), 144));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in10, o3tl::Length::master), 288));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::master), 576));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::master), 6912));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::master), 36495360));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::master, o3tl::Length::master), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::px, o3tl::Length::master), 6));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ch, o3tl::Length::master), 84));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::line, o3tl::Length::master), 624));
+
+static_assert(eq(o3tl::convert(635.0, o3tl::Length::mm100, o3tl::Length::px), 24));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::px), 48));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::px), 480));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::px), 4800));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::px), 480000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::px), 480E6));
+static_assert(eq(o3tl::convert(9525.0, o3tl::Length::emu, o3tl::Length::px), 1));
+static_assert(eq(o3tl::convert(15.0, o3tl::Length::twip, o3tl::Length::px), 1));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pt, o3tl::Length::px), 4));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::px), 16));
+static_assert(eq(o3tl::convert(125.0, o3tl::Length::in1000, o3tl::Length::px), 12));
+static_assert(eq(o3tl::convert(25.0, o3tl::Length::in100, o3tl::Length::px), 24));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in10, o3tl::Length::px), 48));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::px), 96));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::px), 1152));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::px), 6082560));
+static_assert(eq(o3tl::convert(6.0, o3tl::Length::master, o3tl::Length::px), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::px, o3tl::Length::px), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ch, o3tl::Length::px), 14));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::line, o3tl::Length::px), 104));
+
+static_assert(eq(o3tl::convert(4445.0, o3tl::Length::mm100, o3tl::Length::ch), 12));
+static_assert(eq(o3tl::convert(889.0, o3tl::Length::mm10, o3tl::Length::ch), 24));
+static_assert(eq(o3tl::convert(889.0, o3tl::Length::mm, o3tl::Length::ch), 240));
+static_assert(eq(o3tl::convert(889.0, o3tl::Length::cm, o3tl::Length::ch), 2400));
+static_assert(eq(o3tl::convert(889.0, o3tl::Length::m, o3tl::Length::ch), 240000));
+static_assert(eq(o3tl::convert(889.0, o3tl::Length::km, o3tl::Length::ch), 240E6));
+static_assert(eq(o3tl::convert(133350.0, o3tl::Length::emu, o3tl::Length::ch), 1));
+static_assert(eq(o3tl::convert(210.0, o3tl::Length::twip, o3tl::Length::ch), 1));
+static_assert(eq(o3tl::convert(21.0, o3tl::Length::pt, o3tl::Length::ch), 2));
+static_assert(eq(o3tl::convert(7.0, o3tl::Length::pc, o3tl::Length::ch), 8));
+static_assert(eq(o3tl::convert(875.0, o3tl::Length::in1000, o3tl::Length::ch), 6));
+static_assert(eq(o3tl::convert(175.0, o3tl::Length::in100, o3tl::Length::ch), 12));
+static_assert(eq(o3tl::convert(35.0, o3tl::Length::in10, o3tl::Length::ch), 24));
+static_assert(eq(o3tl::convert(7.0, o3tl::Length::in, o3tl::Length::ch), 48));
+static_assert(eq(o3tl::convert(7.0, o3tl::Length::ft, o3tl::Length::ch), 576));
+static_assert(eq(o3tl::convert(7.0, o3tl::Length::mi, o3tl::Length::ch), 3041280));
+static_assert(eq(o3tl::convert(84.0, o3tl::Length::master, o3tl::Length::ch), 1));
+static_assert(eq(o3tl::convert(14.0, o3tl::Length::px, o3tl::Length::ch), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ch, o3tl::Length::ch), 1));
+static_assert(eq(o3tl::convert(35.0, o3tl::Length::line, o3tl::Length::ch), 52));
+
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::mm100, o3tl::Length::line), 3));
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::mm10, o3tl::Length::line), 30));
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::mm, o3tl::Length::line), 300));
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::cm, o3tl::Length::line), 3000));
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::m, o3tl::Length::line), 300000));
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::km, o3tl::Length::line), 300E6));
+static_assert(eq(o3tl::convert(198120.0, o3tl::Length::emu, o3tl::Length::line), 1));
+static_assert(eq(o3tl::convert(312.0, o3tl::Length::twip, o3tl::Length::line), 1));
+static_assert(eq(o3tl::convert(78.0, o3tl::Length::pt, o3tl::Length::line), 5));
+static_assert(eq(o3tl::convert(13.0, o3tl::Length::pc, o3tl::Length::line), 10));
+static_assert(eq(o3tl::convert(650.0, o3tl::Length::in1000, o3tl::Length::line), 3));
+static_assert(eq(o3tl::convert(65.0, o3tl::Length::in100, o3tl::Length::line), 3));
+static_assert(eq(o3tl::convert(13.0, o3tl::Length::in10, o3tl::Length::line), 6));
+static_assert(eq(o3tl::convert(13.0, o3tl::Length::in, o3tl::Length::line), 60));
+static_assert(eq(o3tl::convert(13.0, o3tl::Length::ft, o3tl::Length::line), 720));
+static_assert(eq(o3tl::convert(13.0, o3tl::Length::mi, o3tl::Length::line), 3801600));
+static_assert(eq(o3tl::convert(624.0, o3tl::Length::master, o3tl::Length::line), 5));
+static_assert(eq(o3tl::convert(104.0, o3tl::Length::px, o3tl::Length::line), 5));
+static_assert(eq(o3tl::convert(52.0, o3tl::Length::ch, o3tl::Length::line), 35));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::line, o3tl::Length::line), 1));
+
+// testing integral conversion
+
+static_assert(o3tl::convert(100, o3tl::Length::mm100, o3tl::Length::mm100) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mm10, o3tl::Length::mm100) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::mm, o3tl::Length::mm100) == 10000);
+static_assert(o3tl::convert(100, o3tl::Length::cm, o3tl::Length::mm100) == 100000);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::mm100) == 10000000);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::mm100) == 10000000000);
+static_assert(o3tl::convert(36000, o3tl::Length::emu, o3tl::Length::mm100) == 100);
+static_assert(o3tl::convert(7200, o3tl::Length::twip, o3tl::Length::mm100) == 12700);
+static_assert(o3tl::convert(1800, o3tl::Length::pt, o3tl::Length::mm100) == 63500);
+static_assert(o3tl::convert(300, o3tl::Length::pc, o3tl::Length::mm100) == 127000);
+static_assert(o3tl::convert(5000, o3tl::Length::in1000, o3tl::Length::mm100) == 12700);
+static_assert(o3tl::convert(500, o3tl::Length::in100, o3tl::Length::mm100) == 12700);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::mm100) == 25400);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::mm100) == 254000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::mm100) == 3048000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::mm100) == 16093440000);
+static_assert(o3tl::convert(14400, o3tl::Length::master, o3tl::Length::mm100) == 63500);
+static_assert(o3tl::convert(2400, o3tl::Length::px, o3tl::Length::mm100) == 63500);
+static_assert(o3tl::convert(1200, o3tl::Length::ch, o3tl::Length::mm100) == 444500);
+static_assert(o3tl::convert(300, o3tl::Length::line, o3tl::Length::mm100) == 165100);
+
+static_assert(o3tl::convert(1000, o3tl::Length::mm100, o3tl::Length::mm10) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mm10, o3tl::Length::mm10) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mm, o3tl::Length::mm10) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::cm, o3tl::Length::mm10) == 10000);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::mm10) == 1000000);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::mm10) == 1000000000);
+static_assert(o3tl::convert(360000, o3tl::Length::emu, o3tl::Length::mm10) == 100);
+static_assert(o3tl::convert(72000, o3tl::Length::twip, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(3600, o3tl::Length::pt, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(300, o3tl::Length::pc, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(50000, o3tl::Length::in1000, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(5000, o3tl::Length::in100, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(500, o3tl::Length::in10, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::mm10) == 25400);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::mm10) == 304800);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::mm10) == 1609344000);
+static_assert(o3tl::convert(28800, o3tl::Length::master, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(4800, o3tl::Length::px, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(2400, o3tl::Length::ch, o3tl::Length::mm10) == 88900);
+static_assert(o3tl::convert(3000, o3tl::Length::line, o3tl::Length::mm10) == 165100);
+
+static_assert(o3tl::convert(10000, o3tl::Length::mm100, o3tl::Length::mm) == 100);
+static_assert(o3tl::convert(1000, o3tl::Length::mm10, o3tl::Length::mm) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mm, o3tl::Length::mm) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::cm, o3tl::Length::mm) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::mm) == 100000);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::mm) == 100000000);
+static_assert(o3tl::convert(3600000, o3tl::Length::emu, o3tl::Length::mm) == 100);
+static_assert(o3tl::convert(720000, o3tl::Length::twip, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(36000, o3tl::Length::pt, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(3000, o3tl::Length::pc, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(500000, o3tl::Length::in1000, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(50000, o3tl::Length::in100, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(5000, o3tl::Length::in10, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(500, o3tl::Length::in, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(500, o3tl::Length::ft, o3tl::Length::mm) == 152400);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::mm) == 160934400);
+static_assert(o3tl::convert(288000, o3tl::Length::master, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(48000, o3tl::Length::px, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(24000, o3tl::Length::ch, o3tl::Length::mm) == 88900);
+static_assert(o3tl::convert(30000, o3tl::Length::line, o3tl::Length::mm) == 165100);
+
+static_assert(o3tl::convert(100000, o3tl::Length::mm100, o3tl::Length::cm) == 100);
+static_assert(o3tl::convert(10000, o3tl::Length::mm10, o3tl::Length::cm) == 100);
+static_assert(o3tl::convert(1000, o3tl::Length::mm, o3tl::Length::cm) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::cm, o3tl::Length::cm) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::cm) == 10000);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::cm) == 10000000);
+static_assert(o3tl::convert(36000000, o3tl::Length::emu, o3tl::Length::cm) == 100);
+static_assert(o3tl::convert(7200000, o3tl::Length::twip, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(360000, o3tl::Length::pt, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(30000, o3tl::Length::pc, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(5000000, o3tl::Length::in1000, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(500000, o3tl::Length::in100, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(50000, o3tl::Length::in10, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(5000, o3tl::Length::in, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(2500, o3tl::Length::ft, o3tl::Length::cm) == 76200);
+static_assert(o3tl::convert(500, o3tl::Length::mi, o3tl::Length::cm) == 80467200);
+static_assert(o3tl::convert(2880000, o3tl::Length::master, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(480000, o3tl::Length::px, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(240000, o3tl::Length::ch, o3tl::Length::cm) == 88900);
+static_assert(o3tl::convert(300000, o3tl::Length::line, o3tl::Length::cm) == 165100);
+
+static_assert(o3tl::convert(10000000, o3tl::Length::mm100, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(1000000, o3tl::Length::mm10, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(100000, o3tl::Length::mm, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(10000, o3tl::Length::cm, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::m) == 100000);
+static_assert(o3tl::convert(3600000000, o3tl::Length::emu, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(720000000, o3tl::Length::twip, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(36000000, o3tl::Length::pt, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(3000000, o3tl::Length::pc, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(500000000, o3tl::Length::in1000, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(50000000, o3tl::Length::in100, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(5000000, o3tl::Length::in10, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(500000, o3tl::Length::in, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(125000, o3tl::Length::ft, o3tl::Length::m) == 38100);
+static_assert(o3tl::convert(12500, o3tl::Length::mi, o3tl::Length::m) == 20116800);
+static_assert(o3tl::convert(288000000, o3tl::Length::master, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(48000000, o3tl::Length::px, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(24000000, o3tl::Length::ch, o3tl::Length::m) == 88900);
+static_assert(o3tl::convert(30000000, o3tl::Length::line, o3tl::Length::m) == 165100);
+
+static_assert(o3tl::convert(10000000000, o3tl::Length::mm100, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(1000000000, o3tl::Length::mm10, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(100000000, o3tl::Length::mm, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(10000000, o3tl::Length::cm, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(100000, o3tl::Length::m, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(3600000000000, o3tl::Length::emu, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(720000000000, o3tl::Length::twip, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(36000000000, o3tl::Length::pt, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(3000000000, o3tl::Length::pc, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(500000000000, o3tl::Length::in1000, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(50000000000, o3tl::Length::in100, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(5000000000, o3tl::Length::in10, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(500000000, o3tl::Length::in, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(125000000, o3tl::Length::ft, o3tl::Length::km) == 38100);
+static_assert(o3tl::convert(1562500, o3tl::Length::mi, o3tl::Length::km) == 2514600);
+static_assert(o3tl::convert(288000000000, o3tl::Length::master, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(48000000000, o3tl::Length::px, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(24000000000, o3tl::Length::ch, o3tl::Length::km) == 88900);
+static_assert(o3tl::convert(30000000000, o3tl::Length::line, o3tl::Length::km) == 165100);
+
+static_assert(o3tl::convert(100, o3tl::Length::mm100, o3tl::Length::emu) == 36000);
+static_assert(o3tl::convert(100, o3tl::Length::mm10, o3tl::Length::emu) == 360000);
+static_assert(o3tl::convert(100, o3tl::Length::mm, o3tl::Length::emu) == 3600000);
+static_assert(o3tl::convert(100, o3tl::Length::cm, o3tl::Length::emu) == 36000000);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::emu) == 3600000000);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::emu) == 3600000000000);
+static_assert(o3tl::convert(100, o3tl::Length::emu, o3tl::Length::emu) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::twip, o3tl::Length::emu) == 63500);
+static_assert(o3tl::convert(100, o3tl::Length::pt, o3tl::Length::emu) == 1270000);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::emu) == 15240000);
+static_assert(o3tl::convert(500, o3tl::Length::in1000, o3tl::Length::emu) == 457200);
+static_assert(o3tl::convert(100, o3tl::Length::in100, o3tl::Length::emu) == 914400);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::emu) == 9144000);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::emu) == 91440000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::emu) == 1097280000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::emu) == 5793638400000);
+static_assert(o3tl::convert(200, o3tl::Length::master, o3tl::Length::emu) == 317500);
+static_assert(o3tl::convert(100, o3tl::Length::px, o3tl::Length::emu) == 952500);
+static_assert(o3tl::convert(100, o3tl::Length::ch, o3tl::Length::emu) == 13335000);
+static_assert(o3tl::convert(100, o3tl::Length::line, o3tl::Length::emu) == 19812000);
+
+static_assert(o3tl::convert(12700, o3tl::Length::mm100, o3tl::Length::twip) == 7200);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::twip) == 72000);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::twip) == 720000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::twip) == 7200000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::twip) == 720000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::twip) == 720000000000);
+static_assert(o3tl::convert(63500, o3tl::Length::emu, o3tl::Length::twip) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::twip, o3tl::Length::twip) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::pt, o3tl::Length::twip) == 2000);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::twip) == 24000);
+static_assert(o3tl::convert(2500, o3tl::Length::in1000, o3tl::Length::twip) == 3600);
+static_assert(o3tl::convert(500, o3tl::Length::in100, o3tl::Length::twip) == 7200);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::twip) == 14400);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::twip) == 144000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::twip) == 1728000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::twip) == 9123840000);
+static_assert(o3tl::convert(200, o3tl::Length::master, o3tl::Length::twip) == 500);
+static_assert(o3tl::convert(100, o3tl::Length::px, o3tl::Length::twip) == 1500);
+static_assert(o3tl::convert(100, o3tl::Length::ch, o3tl::Length::twip) == 21000);
+static_assert(o3tl::convert(100, o3tl::Length::line, o3tl::Length::twip) == 31200);
+
+static_assert(o3tl::convert(63500, o3tl::Length::mm100, o3tl::Length::pt) == 1800);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::pt) == 3600);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::pt) == 36000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::pt) == 360000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::pt) == 36000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::pt) == 36000000000);
+static_assert(o3tl::convert(1270000, o3tl::Length::emu, o3tl::Length::pt) == 100);
+static_assert(o3tl::convert(2000, o3tl::Length::twip, o3tl::Length::pt) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::pt, o3tl::Length::pt) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::pt) == 1200);
+static_assert(o3tl::convert(12500, o3tl::Length::in1000, o3tl::Length::pt) == 900);
+static_assert(o3tl::convert(2500, o3tl::Length::in100, o3tl::Length::pt) == 1800);
+static_assert(o3tl::convert(500, o3tl::Length::in10, o3tl::Length::pt) == 3600);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::pt) == 7200);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::pt) == 86400);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::pt) == 456192000);
+static_assert(o3tl::convert(800, o3tl::Length::master, o3tl::Length::pt) == 100);
+static_assert(o3tl::convert(400, o3tl::Length::px, o3tl::Length::pt) == 300);
+static_assert(o3tl::convert(200, o3tl::Length::ch, o3tl::Length::pt) == 2100);
+static_assert(o3tl::convert(500, o3tl::Length::line, o3tl::Length::pt) == 7800);
+
+static_assert(o3tl::convert(127000, o3tl::Length::mm100, o3tl::Length::pc) == 300);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::pc) == 300);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::pc) == 3000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::pc) == 30000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::pc) == 3000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::pc) == 3000000000);
+static_assert(o3tl::convert(15240000, o3tl::Length::emu, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(24000, o3tl::Length::twip, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(1200, o3tl::Length::pt, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(50000, o3tl::Length::in1000, o3tl::Length::pc) == 300);
+static_assert(o3tl::convert(5000, o3tl::Length::in100, o3tl::Length::pc) == 300);
+static_assert(o3tl::convert(500, o3tl::Length::in10, o3tl::Length::pc) == 300);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::pc) == 600);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::pc) == 7200);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::pc) == 38016000);
+static_assert(o3tl::convert(9600, o3tl::Length::master, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(1600, o3tl::Length::px, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(800, o3tl::Length::ch, o3tl::Length::pc) == 700);
+static_assert(o3tl::convert(1000, o3tl::Length::line, o3tl::Length::pc) == 1300);
+
+static_assert(o3tl::convert(12700, o3tl::Length::mm100, o3tl::Length::in1000) == 5000);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::in1000) == 50000);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::in1000) == 500000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::in1000) == 5000000);
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::in1000), 5E6));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::in1000), 5E9));
+static_assert(o3tl::convert(457200, o3tl::Length::emu, o3tl::Length::in1000) == 500);
+static_assert(o3tl::convert(3600, o3tl::Length::twip, o3tl::Length::in1000) == 2500);
+static_assert(o3tl::convert(900, o3tl::Length::pt, o3tl::Length::in1000) == 12500);
+static_assert(o3tl::convert(300, o3tl::Length::pc, o3tl::Length::in1000) == 50000);
+static_assert(o3tl::convert(100, o3tl::Length::in1000, o3tl::Length::in1000) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in100, o3tl::Length::in1000) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::in1000) == 10000);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::in1000) == 100000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::in1000) == 1200000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::in1000) == 6336000000);
+static_assert(o3tl::convert(7200, o3tl::Length::master, o3tl::Length::in1000) == 12500);
+static_assert(o3tl::convert(1200, o3tl::Length::px, o3tl::Length::in1000) == 12500);
+static_assert(o3tl::convert(600, o3tl::Length::ch, o3tl::Length::in1000) == 87500);
+static_assert(o3tl::convert(300, o3tl::Length::line, o3tl::Length::in1000) == 65000);
+
+static_assert(o3tl::convert(12700, o3tl::Length::mm100, o3tl::Length::in100) == 500);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::in100) == 5000);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::in100) == 50000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::in100) == 500000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::in100) == 50000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::in100) == 50000000000);
+static_assert(o3tl::convert(914400, o3tl::Length::emu, o3tl::Length::in100) == 100);
+static_assert(o3tl::convert(7200, o3tl::Length::twip, o3tl::Length::in100) == 500);
+static_assert(o3tl::convert(1800, o3tl::Length::pt, o3tl::Length::in100) == 2500);
+static_assert(o3tl::convert(300, o3tl::Length::pc, o3tl::Length::in100) == 5000);
+static_assert(o3tl::convert(1000, o3tl::Length::in1000, o3tl::Length::in100) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in100, o3tl::Length::in100) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::in100) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::in100) == 10000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::in100) == 120000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::in100) == 633600000);
+static_assert(o3tl::convert(14400, o3tl::Length::master, o3tl::Length::in100) == 2500);
+static_assert(o3tl::convert(2400, o3tl::Length::px, o3tl::Length::in100) == 2500);
+static_assert(o3tl::convert(1200, o3tl::Length::ch, o3tl::Length::in100) == 17500);
+static_assert(o3tl::convert(300, o3tl::Length::line, o3tl::Length::in100) == 6500);
+
+static_assert(o3tl::convert(25400, o3tl::Length::mm100, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::in10) == 500);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::in10) == 5000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::in10) == 50000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::in10) == 5000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::in10) == 5000000000);
+static_assert(o3tl::convert(9144000, o3tl::Length::emu, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(14400, o3tl::Length::twip, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(3600, o3tl::Length::pt, o3tl::Length::in10) == 500);
+static_assert(o3tl::convert(300, o3tl::Length::pc, o3tl::Length::in10) == 500);
+static_assert(o3tl::convert(10000, o3tl::Length::in1000, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(1000, o3tl::Length::in100, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::in10) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::in10) == 12000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::in10) == 63360000);
+static_assert(o3tl::convert(28800, o3tl::Length::master, o3tl::Length::in10) == 500);
+static_assert(o3tl::convert(4800, o3tl::Length::px, o3tl::Length::in10) == 500);
+static_assert(o3tl::convert(2400, o3tl::Length::ch, o3tl::Length::in10) == 3500);
+static_assert(o3tl::convert(600, o3tl::Length::line, o3tl::Length::in10) == 1300);
+
+static_assert(o3tl::convert(254000, o3tl::Length::mm100, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(25400, o3tl::Length::mm10, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::in) == 500);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::in) == 5000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::in) == 500000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::in) == 500000000);
+static_assert(o3tl::convert(91440000, o3tl::Length::emu, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(144000, o3tl::Length::twip, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(7200, o3tl::Length::pt, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(600, o3tl::Length::pc, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(100000, o3tl::Length::in1000, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(10000, o3tl::Length::in100, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(1000, o3tl::Length::in10, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::in) == 1200);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::in) == 6336000);
+static_assert(o3tl::convert(57600, o3tl::Length::master, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(9600, o3tl::Length::px, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(4800, o3tl::Length::ch, o3tl::Length::in) == 700);
+static_assert(o3tl::convert(6000, o3tl::Length::line, o3tl::Length::in) == 1300);
+
+static_assert(o3tl::convert(3048000, o3tl::Length::mm100, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(304800, o3tl::Length::mm10, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(152400, o3tl::Length::mm, o3tl::Length::ft) == 500);
+static_assert(o3tl::convert(76200, o3tl::Length::cm, o3tl::Length::ft) == 2500);
+static_assert(o3tl::convert(38100, o3tl::Length::m, o3tl::Length::ft) == 125000);
+static_assert(o3tl::convert(38100, o3tl::Length::km, o3tl::Length::ft) == 125000000);
+static_assert(o3tl::convert(1097280000, o3tl::Length::emu, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(1728000, o3tl::Length::twip, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(86400, o3tl::Length::pt, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(7200, o3tl::Length::pc, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(1200000, o3tl::Length::in1000, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(120000, o3tl::Length::in100, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(12000, o3tl::Length::in10, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(1200, o3tl::Length::in, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::ft) == 528000);
+static_assert(o3tl::convert(691200, o3tl::Length::master, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(115200, o3tl::Length::px, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(57600, o3tl::Length::ch, o3tl::Length::ft) == 700);
+static_assert(o3tl::convert(72000, o3tl::Length::line, o3tl::Length::ft) == 1300);
+
+static_assert(o3tl::convert(16093440000, o3tl::Length::mm100, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(1609344000, o3tl::Length::mm10, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(160934400, o3tl::Length::mm, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(80467200, o3tl::Length::cm, o3tl::Length::mi) == 500);
+static_assert(o3tl::convert(20116800, o3tl::Length::m, o3tl::Length::mi) == 12500);
+static_assert(o3tl::convert(2514600, o3tl::Length::km, o3tl::Length::mi) == 1562500);
+static_assert(o3tl::convert(5793638400000, o3tl::Length::emu, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(9123840000, o3tl::Length::twip, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(456192000, o3tl::Length::pt, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(38016000, o3tl::Length::pc, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(6336000000, o3tl::Length::in1000, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(633600000, o3tl::Length::in100, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(63360000, o3tl::Length::in10, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(6336000, o3tl::Length::in, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(528000, o3tl::Length::ft, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(3649536000, o3tl::Length::master, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(608256000, o3tl::Length::px, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(304128000, o3tl::Length::ch, o3tl::Length::mi) == 700);
+static_assert(o3tl::convert(380160000, o3tl::Length::line, o3tl::Length::mi) == 1300);
+
+static_assert(o3tl::convert(63500, o3tl::Length::mm100, o3tl::Length::master) == 14400);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::master) == 28800);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::master) == 288000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::master) == 2880000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::master) == 288000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::master) == 288000000000);
+static_assert(o3tl::convert(317500, o3tl::Length::emu, o3tl::Length::master) == 200);
+static_assert(o3tl::convert(500, o3tl::Length::twip, o3tl::Length::master) == 200);
+static_assert(o3tl::convert(100, o3tl::Length::pt, o3tl::Length::master) == 800);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::master) == 9600);
+static_assert(o3tl::convert(12500, o3tl::Length::in1000, o3tl::Length::master) == 7200);
+static_assert(o3tl::convert(2500, o3tl::Length::in100, o3tl::Length::master) == 14400);
+static_assert(o3tl::convert(500, o3tl::Length::in10, o3tl::Length::master) == 28800);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::master) == 57600);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::master) == 691200);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::master) == 3649536000);
+static_assert(o3tl::convert(100, o3tl::Length::master, o3tl::Length::master) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::px, o3tl::Length::master) == 600);
+static_assert(o3tl::convert(100, o3tl::Length::ch, o3tl::Length::master) == 8400);
+static_assert(o3tl::convert(500, o3tl::Length::line, o3tl::Length::master) == 62400);
+
+static_assert(o3tl::convert(63500, o3tl::Length::mm100, o3tl::Length::px) == 2400);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::px) == 4800);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::px) == 48000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::px) == 480000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::px) == 48000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::px) == 48000000000);
+static_assert(o3tl::convert(952500, o3tl::Length::emu, o3tl::Length::px) == 100);
+static_assert(o3tl::convert(1500, o3tl::Length::twip, o3tl::Length::px) == 100);
+static_assert(o3tl::convert(300, o3tl::Length::pt, o3tl::Length::px) == 400);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::px) == 1600);
+static_assert(o3tl::convert(12500, o3tl::Length::in1000, o3tl::Length::px) == 1200);
+static_assert(o3tl::convert(2500, o3tl::Length::in100, o3tl::Length::px) == 2400);
+static_assert(o3tl::convert(500, o3tl::Length::in10, o3tl::Length::px) == 4800);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::px) == 9600);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::px) == 115200);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::px) == 608256000);
+static_assert(o3tl::convert(600, o3tl::Length::master, o3tl::Length::px) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::px, o3tl::Length::px) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::ch, o3tl::Length::px) == 1400);
+static_assert(o3tl::convert(500, o3tl::Length::line, o3tl::Length::px) == 10400);
+
+static_assert(o3tl::convert(444500, o3tl::Length::mm100, o3tl::Length::ch) == 1200);
+static_assert(o3tl::convert(88900, o3tl::Length::mm10, o3tl::Length::ch) == 2400);
+static_assert(o3tl::convert(88900, o3tl::Length::mm, o3tl::Length::ch) == 24000);
+static_assert(o3tl::convert(88900, o3tl::Length::cm, o3tl::Length::ch) == 240000);
+static_assert(o3tl::convert(88900, o3tl::Length::m, o3tl::Length::ch) == 24000000);
+static_assert(o3tl::convert(88900, o3tl::Length::km, o3tl::Length::ch) == 24000000000);
+static_assert(o3tl::convert(13335000, o3tl::Length::emu, o3tl::Length::ch) == 100);
+static_assert(o3tl::convert(21000, o3tl::Length::twip, o3tl::Length::ch) == 100);
+static_assert(o3tl::convert(2100, o3tl::Length::pt, o3tl::Length::ch) == 200);
+static_assert(o3tl::convert(700, o3tl::Length::pc, o3tl::Length::ch) == 800);
+static_assert(o3tl::convert(87500, o3tl::Length::in1000, o3tl::Length::ch) == 600);
+static_assert(o3tl::convert(17500, o3tl::Length::in100, o3tl::Length::ch) == 1200);
+static_assert(o3tl::convert(3500, o3tl::Length::in10, o3tl::Length::ch) == 2400);
+static_assert(o3tl::convert(700, o3tl::Length::in, o3tl::Length::ch) == 4800);
+static_assert(o3tl::convert(700, o3tl::Length::ft, o3tl::Length::ch) == 57600);
+static_assert(o3tl::convert(700, o3tl::Length::mi, o3tl::Length::ch) == 304128000);
+static_assert(o3tl::convert(8400, o3tl::Length::master, o3tl::Length::ch) == 100);
+static_assert(o3tl::convert(1400, o3tl::Length::px, o3tl::Length::ch) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::ch, o3tl::Length::ch) == 100);
+static_assert(o3tl::convert(3500, o3tl::Length::line, o3tl::Length::ch) == 5200);
+
+static_assert(o3tl::convert(165100, o3tl::Length::mm100, o3tl::Length::line) == 300);
+static_assert(o3tl::convert(165100, o3tl::Length::mm10, o3tl::Length::line) == 3000);
+static_assert(o3tl::convert(165100, o3tl::Length::mm, o3tl::Length::line) == 30000);
+static_assert(o3tl::convert(165100, o3tl::Length::cm, o3tl::Length::line) == 300000);
+static_assert(o3tl::convert(165100, o3tl::Length::m, o3tl::Length::line) == 30000000);
+static_assert(o3tl::convert(165100, o3tl::Length::km, o3tl::Length::line) == 30000000000);
+static_assert(o3tl::convert(19812000, o3tl::Length::emu, o3tl::Length::line) == 100);
+static_assert(o3tl::convert(31200, o3tl::Length::twip, o3tl::Length::line) == 100);
+static_assert(o3tl::convert(7800, o3tl::Length::pt, o3tl::Length::line) == 500);
+static_assert(o3tl::convert(1300, o3tl::Length::pc, o3tl::Length::line) == 1000);
+static_assert(o3tl::convert(65000, o3tl::Length::in1000, o3tl::Length::line) == 300);
+static_assert(o3tl::convert(6500, o3tl::Length::in100, o3tl::Length::line) == 300);
+static_assert(o3tl::convert(1300, o3tl::Length::in10, o3tl::Length::line) == 600);
+static_assert(o3tl::convert(1300, o3tl::Length::in, o3tl::Length::line) == 6000);
+static_assert(o3tl::convert(1300, o3tl::Length::ft, o3tl::Length::line) == 72000);
+static_assert(o3tl::convert(1300, o3tl::Length::mi, o3tl::Length::line) == 380160000);
+static_assert(o3tl::convert(62400, o3tl::Length::master, o3tl::Length::line) == 500);
+static_assert(o3tl::convert(10400, o3tl::Length::px, o3tl::Length::line) == 500);
+static_assert(o3tl::convert(5200, o3tl::Length::ch, o3tl::Length::line) == 3500);
+static_assert(o3tl::convert(100, o3tl::Length::line, o3tl::Length::line) == 100);
+
+// Integral rounding
+
+static_assert(o3tl::convert(49, o3tl::Length::mm100, o3tl::Length::mm) == 0);
+static_assert(o3tl::convert(50, o3tl::Length::mm100, o3tl::Length::mm) == 1);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/oox/source/drawingml/diagram/diagram.cxx b/oox/source/drawingml/diagram/diagram.cxx
index 9a8f727b9070..28c79e8cbd60 100644
--- a/oox/source/drawingml/diagram/diagram.cxx
+++ b/oox/source/drawingml/diagram/diagram.cxx
@@ -30,6 +30,7 @@
#include <editeng/unoprnms.hxx>
#include <drawingml/fillproperties.hxx>
#include <drawingml/customshapeproperties.hxx>
+#include <o3tl/unit_conversion.hxx>
#include <oox/token/namespaces.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <svx/svdpage.hxx>
@@ -439,15 +440,17 @@ void reloadDiagram(SdrObject* pObj, core::XmlFilterBase& rFilter)
ShapePtr pShape = std::make_shared<Shape>();
pShape->setDiagramType();
- pShape->setSize(awt::Size(xShape->getSize().Width * EMU_PER_HMM,
- xShape->getSize().Height * EMU_PER_HMM));
+ pShape->setSize(
+ awt::Size(o3tl::convert(xShape->getSize().Width, o3tl::Length::mm100, o3tl::Length::emu),
+ o3tl::convert(xShape->getSize().Height, o3tl::Length::mm100, o3tl::Length::emu)));
loadDiagram(pShape, pDiagramData, layoutDom, styleDom, colorDom, rFilter);
uno::Reference<drawing::XShapes> xShapes(xShape, uno::UNO_QUERY_THROW);
basegfx::B2DHomMatrix aTransformation;
- aTransformation.translate(xShape->getPosition().X * EMU_PER_HMM,
- xShape->getPosition().Y * EMU_PER_HMM);
+ aTransformation.translate(
+ o3tl::convert(xShape->getPosition().X, o3tl::Length::mm100, o3tl::Length::emu),
+ o3tl::convert(xShape->getPosition().Y, o3tl::Length::mm100, o3tl::Length::emu));
for (auto const& child : pShape->getChildren())
child->addShape(rFilter, rFilter.getCurrentTheme(), xShapes, aTransformation, pShape->getFillProperties());
}
diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
index 66df25d9ef4a..bc24b0322059 100644
--- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
+++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
@@ -26,6 +26,7 @@
#include <basegfx/numeric/ftools.hxx>
#include <sal/log.hxx>
+#include <o3tl/unit_conversion.hxx>
#include <oox/helper/attributelist.hxx>
#include <oox/token/properties.hxx>
#include <drawingml/fillproperties.hxx>
@@ -538,14 +539,11 @@ void CompositeAlg::applyConstraintToLayout(const Constraint& rConstraint,
// Reference not found, assume a fixed value.
// Values are never in EMU, while oox::drawingml::Shape position and size are always in
// EMU.
- double fUnitFactor = 0;
- if (isFontUnit(rConstraint.mnRefType))
- // Points -> EMU.
- fUnitFactor = EMU_PER_PT;
- else
- // Millimeters -> EMU.
- fUnitFactor = EMU_PER_HMM * 100;
- rProperties[rConstraint.msForName][rConstraint.mnType] = rConstraint.mfValue * fUnitFactor;
+ const double fValue = o3tl::convert(rConstraint.mfValue,
+ isFontUnit(rConstraint.mnRefType) ? o3tl::Length::pt
+ : o3tl::Length::mm,
+ o3tl::Length::emu);
+ rProperties[rConstraint.msForName][rConstraint.mnType] = fValue;
}
}
@@ -1709,7 +1707,8 @@ void AlgAtom::layoutShape(const ShapePtr& rShape, const std::vector<Constraint>&
double fFactor = convertPointToMms(rConstr.mfFactor);
// DrawingML works in EMUs, UNO API works in MM100s.
- sal_Int32 nValue = rShape->getSize().Width * fFactor / EMU_PER_HMM;
+ sal_Int32 nValue = o3tl::convert(rShape->getSize().Width * fFactor,
+ o3tl::Length::emu, o3tl::Length::mm100);
rShape->getShapeProperties().setProperty(nProperty, nValue);
}
@@ -1816,12 +1815,15 @@ void AlgAtom::layoutShape(const ShapePtr& rShape, const std::vector<Constraint>&
{
if (!aParagraph->getProperties().getParaLeftMargin().has_value())
{
- sal_Int32 nLeftMargin = 285750 * (nLevel - nStartBulletsAtLevel + 1) / EMU_PER_HMM;
+ sal_Int32 nLeftMargin
+ = o3tl::convert(285750 * (nLevel - nStartBulletsAtLevel + 1),
+ o3tl::Length::emu, o3tl::Length::mm100);
aParagraph->getProperties().getParaLeftMargin() = nLeftMargin;
}
if (!aParagraph->getProperties().getFirstLineIndentation().has_value())
- aParagraph->getProperties().getFirstLineIndentation() = -285750 / EMU_PER_HMM;
+ aParagraph->getProperties().getFirstLineIndentation()
+ = o3tl::convert(-285750, o3tl::Length::emu, o3tl::Length::mm100);
// It is not possible to change the bullet style for text.
aParagraph->getProperties().getBulletList().setBulletChar(u"•");
diff --git a/oox/source/drawingml/drawingmltypes.cxx b/oox/source/drawingml/drawingmltypes.cxx
index 645fe9ec9221..3a94a449f317 100644
--- a/oox/source/drawingml/drawingmltypes.cxx
+++ b/oox/source/drawingml/drawingmltypes.cxx
@@ -40,8 +40,7 @@ namespace oox::drawingml {
/** converts EMUs into 1/100th mmm */
sal_Int32 GetCoordinate( sal_Int32 nValue )
{
- nValue = o3tl::saturating_add<sal_Int32>(nValue, 180);
- return nValue / 360;
+ return o3tl::convert(nValue, o3tl::Length::emu, o3tl::Length::mm100);
}
/** converts an emu string into 1/100th mmm */
@@ -56,7 +55,7 @@ sal_Int32 GetCoordinate( std::u16string_view sValue )
/** converts 1/100mm to EMU */
sal_Int32 GetPointFromCoordinate( sal_Int32 nValue )
{
- return nValue * 360;
+ return o3tl::convert(nValue, o3tl::Length::mm100, o3tl::Length::emu);
}
/** converts a ST_Percentage % string into 1/1000th of % */
diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx
index b4ce27ea4df4..22cacec6eaa6 100644
--- a/oox/source/drawingml/shape.cxx
+++ b/oox/source/drawingml/shape.cxx
@@ -35,6 +35,7 @@
#include <drawingml/chart/chartspacefragment.hxx>
#include <drawingml/chart/chartspacemodel.hxx>
#include <o3tl/safeint.hxx>
+#include <o3tl/unit_conversion.hxx>
#include <oox/ppt/pptimport.hxx>
#include <oox/vml/vmldrawing.hxx>
#include <oox/vml/vmlshape.hxx>
@@ -699,7 +700,11 @@ Reference< XShape > const & Shape::createAndInsert(
}
}
- awt::Rectangle aShapeRectHmm( maPosition.X / EMU_PER_HMM, maPosition.Y / EMU_PER_HMM, maSize.Width / EMU_PER_HMM, maSize.Height / EMU_PER_HMM );
+ awt::Rectangle aShapeRectHmm(
+ o3tl::convert(maPosition.X, o3tl::Length::emu, o3tl::Length::mm100),
+ o3tl::convert(maPosition.Y, o3tl::Length::emu, o3tl::Length::mm100),
+ o3tl::convert(maSize.Width, o3tl::Length::emu, o3tl::Length::mm100),
+ o3tl::convert(maSize.Height, o3tl::Length::emu, o3tl::Length::mm100));
OUString aServiceName;
if (pMathXml)
@@ -804,14 +809,17 @@ Reference< XShape > const & Shape::createAndInsert(
{
// if global position is used, add it to transformation
if (mbWps && !bInGroup)
- aTransformation.translate( maPosition.X * EMU_PER_HMM, maPosition.Y * EMU_PER_HMM);
+ aTransformation.translate(
+ o3tl::convert(maPosition.X, o3tl::Length::mm100, o3tl::Length::emu),
+ o3tl::convert(maPosition.Y, o3tl::Length::mm100, o3tl::Length::emu));
else
aTransformation.translate( maPosition.X, maPosition.Y );
}
aTransformation = aParentTransformation*aTransformation;
aParentTransformation = aTransformation;
- aTransformation.scale(1/double(EMU_PER_HMM), 1/double(EMU_PER_HMM));
+ constexpr double fEmuToMm100 = o3tl::convert(1.0, o3tl::Length::emu, o3tl::Length::mm100);
+ aTransformation.scale(fEmuToMm100, fEmuToMm100);
if( bIsCustomShape && mbFlipH != mbFlipV )
{
diff --git a/oox/source/vml/vmlformatting.cxx b/oox/source/vml/vmlformatting.cxx
index 60ef7f900d15..96d26efe8ff8 100644
--- a/oox/source/vml/vmlformatting.cxx
+++ b/oox/source/vml/vmlformatting.cxx
@@ -29,6 +29,7 @@
#include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
#include <com/sun/star/table/ShadowFormat.hpp>
#include <com/sun/star/text/XTextRange.hpp>
+#include <o3tl/unit_conversion.hxx>
#include <rtl/strbuf.hxx>
#include <sal/log.hxx>
#include <osl/diagnose.h>
@@ -174,21 +175,20 @@ sal_Int64 ConversionHelper::decodeMeasureToEmu( const GraphicHelper& rGraphicHel
{
sal_Unicode cChar1 = aUnit[ 0 ];
sal_Unicode cChar2 = aUnit[ 1 ];
- if( (cChar1 == 'i') && (cChar2 == 'n') ) // 1 inch = 914,400 EMU
- fValue *= 914400.0;
- else if( (cChar1 == 'c') && (cChar2 == 'm') ) // 1 cm = 360,000 EMU
- fValue *= 360000.0;
- else if( (cChar1 == 'm') && (cChar2 == 'm') ) // 1 mm = 36,000 EMU
- fValue *= 36000.0;
- else if( (cChar1 == 'p') && (cChar2 == 't') ) // 1 point = 1/72 inch = 12,700 EMU
- fValue *= 12700.0;
- else if( (cChar1 == 'p') && (cChar2 == 'c') ) // 1 pica = 1/6 inch = 152,400 EMU
- fValue *= 152400.0;
+ if ((cChar1 == 'i') && (cChar2 == 'n'))
+ fValue = o3tl::convert(fValue, o3tl::Length::in, o3tl::Length::emu);
+ else if ((cChar1 == 'c') && (cChar2 == 'm'))
+ fValue = o3tl::convert(fValue, o3tl::Length::cm, o3tl::Length::emu);
+ else if ((cChar1 == 'm') && (cChar2 == 'm'))
+ fValue = o3tl::convert(fValue, o3tl::Length::mm, o3tl::Length::emu);
+ else if ((cChar1 == 'p') && (cChar2 == 't'))
+ fValue = o3tl::convert(fValue, o3tl::Length::pt, o3tl::Length::emu);
+ else if ((cChar1 == 'p') && (cChar2 == 'c'))
+ fValue = o3tl::convert(fValue, o3tl::Length::pc, o3tl::Length::emu);
else if( (cChar1 == 'p') && (cChar2 == 'x') ) // 1 pixel, dependent on output device
- fValue = static_cast< double >( ::oox::drawingml::convertHmmToEmu(
- bPixelX ?
- rGraphicHelper.convertScreenPixelXToHmm( fValue ) :
- rGraphicHelper.convertScreenPixelYToHmm( fValue ) ) );
+ fValue = o3tl::convert(bPixelX ? rGraphicHelper.convertScreenPixelXToHmm(fValue)
+ : rGraphicHelper.convertScreenPixelYToHmm(fValue),
+ o3tl::Length::mm100, o3tl::Length::emu);
}
else if( (aUnit.getLength() == 1) && (aUnit[ 0 ] == '%') )
{
diff --git a/sax/source/tools/converter.cxx b/sax/source/tools/converter.cxx
index 4f7c686a1aba..18731b45ac77 100644
--- a/sax/source/tools/converter.cxx
+++ b/sax/source/tools/converter.cxx
@@ -28,7 +28,9 @@
#include <rtl/ustrbuf.hxx>
#include <rtl/math.hxx>
+#include <rtl/character.hxx>
#include <sal/log.hxx>
+#include <o3tl/unit_conversion.hxx>
#include <osl/diagnose.h>
#include <tools/long.hxx>
@@ -43,11 +45,11 @@ using namespace ::com::sun::star::i18n;
namespace sax {
-const char* const gpsMM = "mm";
-const char* const gpsCM = "cm";
-const char* const gpsPT = "pt";
-const char* const gpsINCH = "in";
-const char* const gpsPC = "pc";
+const std::string_view gpsMM = "mm";
+const std::string_view gpsCM = "cm";
+const std::string_view gpsPT = "pt";
+const std::string_view gpsINCH = "in";
+const std::string_view gpsPC = "pc";
const sal_Int8 XML_MAXDIGITSCOUNT_TIME = 14;
@@ -60,6 +62,62 @@ static sal_Int64 toInt64_WithLength(const char * str, sal_Int16 radix, sal_Int32
return rtl_str_toInt64_WithLength(str, radix, nStrLength);
}
+namespace
+{
+o3tl::Length Measure2O3tlUnit(sal_Int16 nUnit)
+{
+ switch (nUnit)
+ {
+ case MeasureUnit::TWIP:
+ return o3tl::Length::twip;
+ case MeasureUnit::POINT:
+ return o3tl::Length::pt;
+ case MeasureUnit::MM_10TH:
+ return o3tl::Length::mm10;
+ case MeasureUnit::MM_100TH:
+ return o3tl::Length::mm100;
+ case MeasureUnit::MM:
+ return o3tl::Length::mm;
+ case MeasureUnit::CM:
+ return o3tl::Length::cm;
+ default:
+ SAL_WARN("sax", "unit not supported for length");
+ [[fallthrough]];
+ case MeasureUnit::INCH:
+ return o3tl::Length::in;
+ }
+}
+
+std::string_view Measure2UnitString(sal_Int16 nUnit)
+{
+ switch (nUnit)
+ {
+ case MeasureUnit::TWIP:
+ return gpsPC; // ??
+ case MeasureUnit::POINT:
+ return gpsPT;
+ case MeasureUnit::MM_10TH:
+ case MeasureUnit::MM_100TH:
+ return {};
+ case MeasureUnit::MM:
+ return gpsMM;
+ case MeasureUnit::CM:
+ return gpsCM;
+ case MeasureUnit::INCH:
+ default:
+ return gpsINCH;
+ }
+}
+
+template <typename V> bool wordEndsWith(V string, std::string_view expected)
+{
+ V substr = string.substr(0, expected.size());
+ return std::equal(substr.begin(), substr.end(), expected.begin(), expected.end(),
+ [](sal_uInt32 c1, sal_uInt32 c2) { return rtl::toAsciiLowerCase(c1) == c2; })
+ && (string.size() == expected.size() || string[expected.size()] == ' ');
+}
+
+}
/** convert string to measure using optional min and max values*/
template<typename V>
@@ -137,127 +195,70 @@ static bool lcl_convertMeasure( sal_Int32& rValue,
OSL_ENSURE( MeasureUnit::TWIP == nTargetUnit || MeasureUnit::POINT == nTargetUnit ||
MeasureUnit::MM_100TH == nTargetUnit || MeasureUnit::MM_10TH == nTargetUnit ||
MeasureUnit::PIXEL == nTargetUnit, "unit is not supported");
- const char *aCmpsL[3] = { nullptr, nullptr, nullptr };
- const char *aCmpsU[3] = { nullptr, nullptr, nullptr };
- double aScales[3] = { 1., 1., 1. };
+
+ o3tl::Length eFrom = o3tl::Length::invalid;
if( MeasureUnit::TWIP == nTargetUnit )
{
- switch( rString[nPos] )
+ switch (rtl::toAsciiLowerCase<sal_uInt32>(rString[nPos]))
{
case u'c':
- case u'C':
- aCmpsL[0] = "cm";
- aCmpsU[0] = "CM";
- aScales[0] = (72.*20.)/2.54; // twip
+ if (wordEndsWith(rString.substr(nPos + 1), "m"))
+ eFrom = o3tl::Length::cm;
break;
case u'i':
- case u'I':
- aCmpsL[0] = "in";
- aCmpsU[0] = "IN";
- aScales[0] = 72.*20.; // twip
+ if (wordEndsWith(rString.substr(nPos + 1), "n"))
+ eFrom = o3tl::Length::in;
break;
case u'm':
- case u'M':
- aCmpsL[0] = "mm";
- aCmpsU[0] = "MM";
- aScales[0] = (72.*20.)/25.4; // twip
+ if (wordEndsWith(rString.substr(nPos + 1), "m"))
+ eFrom = o3tl::Length::mm;
break;
case u'p':
- case u'P':
- aCmpsL[0] = "pt";
- aCmpsU[0] = "PT";
- aScales[0] = 20.; // twip
-
- aCmpsL[1] = "pc";
- aCmpsU[1] = "PC";
- aScales[1] = 12.*20.; // twip
+ if (wordEndsWith(rString.substr(nPos + 1), "t"))
+ eFrom = o3tl::Length::pt;
+ else if (wordEndsWith(rString.substr(nPos + 1), "c"))
+ eFrom = o3tl::Length::pc;
break;
}
}
else if( MeasureUnit::MM_100TH == nTargetUnit || MeasureUnit::MM_10TH == nTargetUnit )
{
- double nScaleFactor = (MeasureUnit::MM_100TH == nTargetUnit) ? 100.0 : 10.0;
- switch( rString[nPos] )
+ switch (rtl::toAsciiLowerCase<sal_uInt32>(rString[nPos]))
{
case u'c':
- case u'C':
- aCmpsL[0] = "cm";
- aCmpsU[0] = "CM";
- aScales[0] = 10.0 * nScaleFactor; // mm/100
+ if (wordEndsWith(rString.substr(nPos + 1), "m"))
+ eFrom = o3tl::Length::cm;
break;
case u'i':
- case u'I':
- aCmpsL[0] = "in";
- aCmpsU[0] = "IN";
- aScales[0] = 1000.*2.54; // mm/100
+ if (wordEndsWith(rString.substr(nPos + 1), "n"))
+ eFrom = o3tl::Length::in;
break;
case u'm':
- case u'M':
- aCmpsL[0] = "mm";
- aCmpsU[0] = "MM";
- aScales[0] = 1.0 * nScaleFactor; // mm/100
+ if (wordEndsWith(rString.substr(nPos + 1), "m"))
+ eFrom = o3tl::Length::mm;
break;
case u'p':
- case u'P':
- aCmpsL[0] = "pt";
- aCmpsU[0] = "PT";
- aScales[0] = (10.0 * nScaleFactor*2.54)/72.; // mm/100
-
- aCmpsL[1] = "pc";
- aCmpsU[1] = "PC";
- aScales[1] = (10.0 * nScaleFactor*2.54)/12.; // mm/100
-
- aCmpsL[2] = "px";
- aCmpsU[2] = "PX";
- aScales[2] = 0.28 * nScaleFactor; // mm/100
+ if (wordEndsWith(rString.substr(nPos + 1), "t"))
+ eFrom = o3tl::Length::pt;
+ else if (wordEndsWith(rString.substr(nPos + 1), "c"))
+ eFrom = o3tl::Length::pc;
+ else if (wordEndsWith(rString.substr(nPos + 1), "x"))
+ eFrom = o3tl::Length::px;
break;
}
}
else if( MeasureUnit::POINT == nTargetUnit )
{
- if( rString[nPos] == 'p' || rString[nPos] == 'P' )
- {
- aCmpsL[0] = "pt";
- aCmpsU[0] = "PT";
- aScales[0] = 1;
- }
- }
-
- if( aCmpsL[0] == nullptr )
- return false;
-
- double nScale = 0.;
- for( sal_uInt16 i= 0; i < 3; i++ )
- {
- sal_Int32 nTmp = nPos; // come back to the initial position before each iteration
- const char *pL = aCmpsL[i];
- if( pL )
- {
- const char *pU = aCmpsU[i];
- while( nTmp < nLen && *pL )
- {
- sal_Unicode c = rString[nTmp];
- if( c != *pL && c != *pU )
- break;
- pL++;
- pU++;
- nTmp++;
- }
- if( !*pL && (nTmp == nLen || ' ' == rString[nTmp]) )
- {
- nScale = aScales[i];
- break;
- }
- }
+ if (wordEndsWith(rString.substr(nPos), "pt"))
+ eFrom = o3tl::Length::pt;
}
- if( 0. == nScale )
+ if (eFrom == o3tl::Length::invalid)
return false;
// TODO: check overflow
- if( nScale != 1. )
- nVal *= nScale;
+ nVal = o3tl::convert(nVal, eFrom, Measure2O3tlUnit(nTargetUnit));
}
}
@@ -320,14 +321,13 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
rBuffer.append( '-' );
}
- // The new length is (nVal * nMul)/(nDiv*nFac*10)
- tools::Long nMul = 1000;
- tools::Long nDiv = 1;
- tools::Long nFac = 100;
- const char* psUnit = nullptr;
+ o3tl::Length eFrom = o3tl::Length::in, eTo = o3tl::Length::in;
+ int nFac = 100; // used to get specific number of decimals (2 by default)
+ std::string_view psUnit;
switch( nSourceUnit )
{
case MeasureUnit::TWIP:
+ eFrom = o3tl::Length::twip;
switch( nTargetUnit )
{
case MeasureUnit::MM_100TH:
@@ -335,25 +335,19 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,"output unit not supported for twip values" );
[[fallthrough]];
case MeasureUnit::MM:
- // 0.01mm = 0.57twip (exactly)
- nMul = 25400; // 25.4 * 1000
- nDiv = 1440; // 72 * 20;
+ eTo = o3tl::Length::mm;
nFac = 100;
psUnit = gpsMM;
break;
case MeasureUnit::CM:
- // 0.001cm = 0.57twip (exactly)
- nMul = 25400; // 2.54 * 10000
- nDiv = 1440; // 72 * 20;
+ eTo = o3tl::Length::cm;
nFac = 1000;
psUnit = gpsCM;
break;
case MeasureUnit::POINT:
- // 0.01pt = 0.2twip (exactly)
- nMul = 1000;
- nDiv = 20;
+ eTo = o3tl::Length::pt;
nFac = 100;
psUnit = gpsPT;
break;
@@ -362,9 +356,6 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
default:
OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,
"output unit not supported for twip values" );
- // 0.0001in = 0.144twip (exactly)
- nMul = 100000;
- nDiv = 1440; // 72 * 20;
nFac = 10000;
psUnit = gpsINCH;
break;
@@ -375,8 +366,7 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
// 1pt = 1pt (exactly)
OSL_ENSURE( MeasureUnit::POINT == nTargetUnit,
"output unit not supported for pt values" );
- nMul = 10;
- nDiv = 1;
+ eFrom = eTo = o3tl::Length::pt;
nFac = 1;
psUnit = gpsPT;
break;
@@ -384,6 +374,7 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
case MeasureUnit::MM_100TH:
{
int nFac2 = (MeasureUnit::MM_100TH == nSourceUnit) ? 100 : 10;
+ eFrom = Measure2O3tlUnit(nSourceUnit);
switch( nTargetUnit )
{
case MeasureUnit::MM_100TH:
@@ -392,25 +383,19 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
"output unit not supported for 1/100mm values" );
[[fallthrough]];
case MeasureUnit::MM:
- // 0.01mm = 1 mm/100 (exactly)
- nMul = 10;
- nDiv = 1;
+ eTo = o3tl::Length::mm;
nFac = nFac2;
psUnit = gpsMM;
break;
case MeasureUnit::CM:
- // 0.001mm = 1 mm/100 (exactly)
- nMul = 10;
- nDiv = 1; // 72 * 20;
+ eTo = o3tl::Length::cm;
nFac = 10*nFac2;
psUnit = gpsCM;
break;
case MeasureUnit::POINT:
- // 0.01pt = 0.35 mm/100 (exactly)
- nMul = 72000;
- nDiv = 2540;
+ eTo = o3tl::Length::pt;
nFac = nFac2;
psUnit = gpsPT;
break;
@@ -419,9 +404,6 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
default:
OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,
"output unit not supported for 1/100mm values" );
- // 0.0001in = 0.254 mm/100 (exactly)
- nMul = 100000;
- nDiv = 2540;
nFac = 100*nFac2;
psUnit = gpsINCH;
break;
@@ -434,11 +416,7 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
break;
}
- OSL_ENSURE(nValue <= SAL_MAX_INT64 / nMul, "convertMeasure: overflow");
- nValue *= nMul;
- nValue /= nDiv;
- nValue += 5;
- nValue /= 10;
+ nValue = o3tl::convert(nValue * nFac, eFrom, eTo);
rBuffer.append( static_cast<sal_Int64>(nValue / nFac) );
if (nFac > 1 && (nValue % nFac) != 0)
@@ -451,8 +429,8 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
}
}
- if( psUnit )
- rBuffer.appendAscii( psUnit );
+ if (psUnit.length() > 0)
+ rBuffer.appendAscii(psUnit.data(), psUnit.length());
}
/** convert string to boolean */
@@ -2240,349 +2218,12 @@ double Converter::GetConversionFactor(OUStringBuffer& rUnit, sal_Int16 nSourceUn
if(nSourceUnit != nTargetUnit)
{
- const char* psUnit = nullptr;
-
- switch(nSourceUnit)
- {
- case MeasureUnit::TWIP:
- {
- switch(nTargetUnit)
- {
- case MeasureUnit::MM_100TH:
- {
- // 0.01mm = 0.57twip (exactly)
- fRetval = ((25400.0 / 1440.0) / 10.0);
- break;
- }
- case MeasureUnit::MM_10TH:
- {
- // 0.01mm = 0.57twip (exactly)
- fRetval = ((25400.0 / 1440.0) / 100.0);
- break;
- }
- case MeasureUnit::MM:
- {
- // 0.01mm = 0.57twip (exactly)
- fRetval = ((25400.0 / 1440.0) / 1000.0);
- psUnit = gpsMM;
- break;
- }
- case MeasureUnit::CM:
- {
- // 0.001cm = 0.57twip (exactly)
- fRetval = ((25400.0 / 1440.0) / 10000.0);
- psUnit = gpsCM;
- break;
- }
- case MeasureUnit::POINT:
- {
- // 0.01pt = 0.2twip (exactly)
- fRetval = ((1000.0 / 20.0) / 1000.0);
- psUnit = gpsPT;
- break;
- }
- case MeasureUnit::INCH:
- default:
- {
- OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for twip values");
- // 0.0001in = 0.144twip (exactly)
- fRetval = ((100000.0 / 1440.0) / 100000.0);
- psUnit = gpsINCH;
- break;
- }
- }
- break;
- }
- case MeasureUnit::POINT:
- {
- switch(nTargetUnit)
- {
- case MeasureUnit::MM_100TH:
- {
- // 1mm = 72 / 25.4 pt (exactly)
- fRetval = ( 2540.0 / 72.0 );
- break;
- }
- case MeasureUnit::MM_10TH:
- {
- // 1mm = 72 / 25.4 pt (exactly)
- fRetval = ( 254.0 / 72.0 );
- break;
- }
- case MeasureUnit::MM:
- {
- // 1mm = 72 / 25.4 pt (exactly)
- fRetval = ( 25.4 / 72.0 );
- psUnit = gpsMM;
- break;
-
- }
- case MeasureUnit::CM:
- {
- // 1cm = 72 / 2.54 pt (exactly)
- fRetval = ( 2.54 / 72.0 );
- psUnit = gpsCM;
- break;
- }
- case MeasureUnit::TWIP:
- {
- // 1twip = 72 / 1440 pt (exactly)
- fRetval = 20.0; // 1440.0 / 72.0
- psUnit = gpsPC;
- break;
- }
- case MeasureUnit::INCH:
- default:
- {
- OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for pt values");
- // 1in = 72 pt (exactly)
- fRetval = ( 1.0 / 72.0 );
- psUnit = gpsINCH;
- break;
- }
- }
- break;
- }
- case MeasureUnit::MM_10TH:
- {
- switch(nTargetUnit)
- {
- case MeasureUnit::MM_100TH:
- {
- fRetval = 10.0;
- break;
- }
- case MeasureUnit::MM:
- {
- // 0.01mm = 1 mm/100 (exactly)
- fRetval = ((10.0 / 1.0) / 100.0);
- psUnit = gpsMM;
- break;
- }
- case MeasureUnit::CM:
- {
- fRetval = ((10.0 / 1.0) / 1000.0);
- psUnit = gpsCM;
- break;
- }
- case MeasureUnit::POINT:
- {
- // 0.01pt = 0.35 mm/100 (exactly)
- fRetval = ((72000.0 / 2540.0) / 100.0);
- psUnit = gpsPT;
- break;
- }
- case MeasureUnit::TWIP:
- {
- fRetval = ((20.0 * 72000.0 / 2540.0) / 100.0);
- psUnit = gpsPC;
- break;
- }
- case MeasureUnit::INCH:
- default:
- {
- OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for 1/10mm values");
- // 0.0001in = 0.254 mm/100 (exactly)
- fRetval = ((100000.0 / 2540.0) / 10000.0);
- psUnit = gpsINCH;
- break;
- }
- }
- break;
- }
- case MeasureUnit::MM_100TH:
- {
- switch(nTargetUnit)
- {
- case MeasureUnit::MM_10TH:
- {
- fRetval = ((10.0 / 1.0) / 100.0);
- break;
- }
- case MeasureUnit::MM:
- {
- // 0.01mm = 1 mm/100 (exactly)
- fRetval = ((10.0 / 1.0) / 1000.0);
- psUnit = gpsMM;
- break;
- }
- case MeasureUnit::CM:
- {
- fRetval = ((10.0 / 1.0) / 10000.0);
- psUnit = gpsCM;
- break;
- }
- case MeasureUnit::POINT:
- {
- // 0.01pt = 0.35 mm/100 (exactly)
- fRetval = ((72000.0 / 2540.0) / 1000.0);
- psUnit = gpsPT;
- break;
- }
- case MeasureUnit::TWIP:
- {
- fRetval = ((20.0 * 72000.0 / 2540.0) / 1000.0);
- psUnit = gpsPC;
- break;
- }
- case MeasureUnit::INCH:
- default:
- {
- OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for 1/100mm values");
- // 0.0001in = 0.254 mm/100 (exactly)
- fRetval = ((100000.0 / 2540.0) / 100000.0);
- psUnit = gpsINCH;
- break;
- }
- }
- break;
- }
- case MeasureUnit::MM:
- {
- switch(nTargetUnit)
- {
- case MeasureUnit::MM_100TH:
- {
- fRetval = 100.0;
- break;
- }
- case MeasureUnit::MM_10TH:
- {
- fRetval = 10.0;
- break;
- }
- case MeasureUnit::CM:
- {
- fRetval = 0.1;
- psUnit = gpsCM;
- break;
- }
- case MeasureUnit::POINT:
- {
- fRetval = 72.0 / (2.54 * 10);
- psUnit = gpsPT;
- break;
- }
- case MeasureUnit::TWIP:
- {
- fRetval = (20.0 * 72.0) / (2.54 * 10);
- psUnit = gpsPC;
- break;
- }
- case MeasureUnit::INCH:
- default:
- {
- OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for cm values");
- fRetval = 1 / (2.54 * 10);
- psUnit = gpsINCH;
- break;
- }
- }
- break;
- }
- case MeasureUnit::CM:
- {
- switch(nTargetUnit)
- {
- case MeasureUnit::MM_100TH:
- {
- fRetval = 1000.0;
- break;
- }
- case MeasureUnit::MM_10TH:
- {
- fRetval = 100.0;
- break;
- }
- case MeasureUnit::MM:
- {
- fRetval = 10.0;
- psUnit = gpsMM;
- break;
- }
- case MeasureUnit::CM:
- {
- break;
- }
- case MeasureUnit::POINT:
- {
- fRetval = 72.0 / 2.54;
- psUnit = gpsPT;
- break;
- }
- case MeasureUnit::TWIP:
- {
- fRetval = (20.0 * 72.0) / 2.54;
- psUnit = gpsPC;
- break;
- }
- case MeasureUnit::INCH:
- default:
- {
- OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for cm values");
- fRetval = 1 / 2.54;
- psUnit = gpsINCH;
- break;
- }
- }
- break;
- }
- case MeasureUnit::INCH:
- {
- switch (nTargetUnit)
- {
- case MeasureUnit::MM_100TH:
- {
- fRetval = 2540;
- break;
- }
- case MeasureUnit::MM_10TH:
- {
- fRetval = 254;
- break;
- }
- case MeasureUnit::MM:
- {
- fRetval = 25.4;
- psUnit = gpsMM;
- break;
- }
- case MeasureUnit::CM:
- {
- fRetval = 2.54;
- psUnit = gpsCM;
- break;
- }
- case MeasureUnit::POINT:
- {
- fRetval = 72.0;
- psUnit = gpsPT;
- break;
- }
- case MeasureUnit::TWIP:
- {
- fRetval = 72.0 * 20.0;
- psUnit = gpsPC;
- break;
- }
- default:
- {
- OSL_FAIL("output unit not supported for in values");
- fRetval = 1;
- psUnit = gpsINCH;
- break;
- }
- }
- break;
- }
- default:
- OSL_ENSURE(false, "sax::Converter::GetConversionFactor(): "
- "source unit not supported");
- break;
- }
+ const o3tl::Length eFrom = Measure2O3tlUnit(nSourceUnit);
+ const o3tl::Length eTo = Measure2O3tlUnit(nTargetUnit);
+ fRetval = o3tl::convert(1.0, eFrom, eTo);
- if( psUnit )
- rUnit.appendAscii( psUnit );
+ if (const auto sUnit = Measure2UnitString(nTargetUnit); sUnit.size() > 0)
+ rUnit.appendAscii(sUnit.data(), sUnit.size());
}
return fRetval;
diff --git a/sc/source/filter/oox/unitconverter.cxx b/sc/source/filter/oox/unitconverter.cxx
index 088121286d9e..8ca79ce78d90 100644
--- a/sc/source/filter/oox/unitconverter.cxx
+++ b/sc/source/filter/oox/unitconverter.cxx
@@ -26,6 +26,7 @@
#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
#include <com/sun/star/util/Date.hpp>
#include <com/sun/star/util/DateTime.hpp>
+#include <o3tl/unit_conversion.hxx>
#include <osl/diagnose.h>
#include <oox/core/filterbase.hxx>
#include <oox/helper/propertyset.hxx>
@@ -43,11 +44,6 @@ using namespace ::com::sun::star::uno;
namespace {
-const double MM100_PER_INCH = 2540.0;
-const double MM100_PER_POINT = MM100_PER_INCH / 72.0;
-const double MM100_PER_TWIP = MM100_PER_POINT / 20.0;
-const double MM100_PER_EMU = 1.0 / 360.0;
-
/** Returns true, if the passed year is a leap year. */
bool lclIsLeapYear( sal_Int32 nYear )
{
@@ -95,10 +91,10 @@ UnitConverter::UnitConverter( const WorkbookHelper& rHelper ) :
{
// initialize constant and default coefficients
const DeviceInfo& rDeviceInfo = getBaseFilter().getGraphicHelper().getDeviceInfo();
- maCoeffs[ Unit::Inch ] = MM100_PER_INCH;
- maCoeffs[ Unit::Point ] = MM100_PER_POINT;
- maCoeffs[ Unit::Twip ] = MM100_PER_TWIP;
- maCoeffs[ Unit::Emu ] = MM100_PER_EMU;
+ maCoeffs[Unit::Inch] = o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::mm100);
+ maCoeffs[Unit::Point] = o3tl::convert(1.0, o3tl::Length::pt, o3tl::Length::mm100);
+ maCoeffs[Unit::Twip] = o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::mm100);
+ maCoeffs[Unit::Emu] = o3tl::convert(1.0, o3tl::Length::emu, o3tl::Length::mm100);
maCoeffs[ Unit::ScreenX ] = (rDeviceInfo.PixelPerMeterX > 0) ? (100000.0 / rDeviceInfo.PixelPerMeterX) : 50.0;
maCoeffs[ Unit::ScreenY ] = (rDeviceInfo.PixelPerMeterY > 0) ? (100000.0 / rDeviceInfo.PixelPerMeterY) : 50.0;
maCoeffs[ Unit::Digit ] = 200.0; // default: 1 digit = 2 mm
@@ -133,13 +129,16 @@ void UnitConverter::finalizeImport()
return;
// get maximum width of all digits
- sal_Int32 nDigitWidth = 0;
+ sal_Int64 nDigitWidth = 0;
for( sal_Unicode cChar = '0'; cChar <= '9'; ++cChar )
- nDigitWidth = ::std::max( nDigitWidth, scaleToMm100( xFont->getCharWidth( cChar ), Unit::Twip ) );
+ nDigitWidth
+ = ::std::max(nDigitWidth, o3tl::convert(xFont->getCharWidth(cChar), o3tl::Length::twip,
+ o3tl::Length::mm100));
if( nDigitWidth > 0 )
maCoeffs[ Unit::Digit ] = nDigitWidth;
// get width of space character
- sal_Int32 nSpaceWidth = scaleToMm100( xFont->getCharWidth( ' ' ), Unit::Twip );
+ sal_Int32 nSpaceWidth
+ = o3tl::convert(xFont->getCharWidth(' '), o3tl::Length::twip, o3tl::Length::mm100);
if( nSpaceWidth > 0 )
maCoeffs[ Unit::Space ] = nSpaceWidth;
}
diff --git a/sc/source/ui/vba/vbarange.cxx b/sc/source/ui/vba/vbarange.cxx
index 1dd212e61bb2..e78088facd52 100644
--- a/sc/source/ui/vba/vbarange.cxx
+++ b/sc/source/ui/vba/vbarange.cxx
@@ -22,6 +22,7 @@
#include <comphelper/types.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <o3tl/any.hxx>
+#include <o3tl/unit_conversion.hxx>
#include <tools/diagnose_ex.h>
#include <com/sun/star/script/ArrayWrapper.hpp>
@@ -163,11 +164,6 @@ using ::std::vector;
// difference between VBA and file format width, in character units
const double fExtraWidth = 182.0 / 256.0;
-// * 1 point = 1/72 inch = 20 twips
-// * 1 inch = 72 points = 1440 twips
-// * 1 cm = 567 twips
-static double lcl_hmmToPoints( double nVal ) { return nVal / 1000 * 567 / 20; }
-
const sal_Int16 supportedIndexTable[] = { excel::XlBordersIndex::xlEdgeLeft, excel::XlBordersIndex::xlEdgeTop, excel::XlBordersIndex::xlEdgeBottom, excel::XlBordersIndex::xlEdgeRight, excel::XlBordersIndex::xlDiagonalDown, excel::XlBordersIndex::xlDiagonalUp, excel::XlBordersIndex::xlInsideVertical, excel::XlBordersIndex::xlInsideHorizontal };
static sal_uInt16 lcl_pointsToTwips( double nVal )
@@ -3747,7 +3743,7 @@ static double getDefaultCharWidth( ScDocShell* pDocShell )
pAttr->GetFont( aDefFont, SC_AUTOCOL_BLACK, pRefDevice );
pRefDevice->SetFont( aDefFont );
tools::Long nCharWidth = pRefDevice->GetTextWidth( OUString( '0' ) ); // 1/100th mm
- return lcl_hmmToPoints( nCharWidth );
+ return o3tl::convert<double>(nCharWidth, o3tl::Length::mm100, o3tl::Length::pt);
}
uno::Any SAL_CALL
@@ -4084,7 +4080,7 @@ ScVbaRange::getLeft()
if ( m_Areas->getCount() > 1 )
return getArea( 0 )->getLeft();
awt::Point aPoint = getPosition();
- return uno::makeAny( lcl_hmmToPoints( aPoint.X ) );
+ return uno::makeAny(o3tl::convert<double>(aPoint.X, o3tl::Length::mm100, o3tl::Length::pt));
}
uno::Any SAL_CALL
@@ -4094,7 +4090,7 @@ ScVbaRange::getTop()
if ( m_Areas->getCount() > 1 )
return getArea( 0 )->getTop();
awt::Point aPoint= getPosition();
- return uno::makeAny( lcl_hmmToPoints( aPoint.Y ) );
+ return uno::makeAny(o3tl::convert<double>(aPoint.Y, o3tl::Length::mm100, o3tl::Length::pt));
}
static uno::Reference< sheet::XCellRangeReferrer > getNamedRange( const uno::Reference< uno::XInterface >& xIf, const uno::Reference< table::XCellRange >& thisRange )
diff --git a/sd/qa/unit/export-tests-ooxml1.cxx b/sd/qa/unit/export-tests-ooxml1.cxx
index a740e2b2d69c..7c3739fa1a7d 100644
--- a/sd/qa/unit/export-tests-ooxml1.cxx
+++ b/sd/qa/unit/export-tests-ooxml1.cxx
@@ -746,7 +746,7 @@ void SdOOXMLExportTest1::testBulletMarginAndIndentation()
CPPUNIT_ASSERT(pNumFmt);
CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bullet's left margin is wrong!", sal_Int32(1000),pNumFmt->GetNumRule()->GetLevel(0).GetAbsLSpace() ); // left margin is 0.79 cm
- CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bullet's indentation is wrong!", sal_Int32(-998),pNumFmt->GetNumRule()->GetLevel(0). GetFirstLineOffset());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bullet's indentation is wrong!", sal_Int32(-1000),pNumFmt->GetNumRule()->GetLevel(0). GetFirstLineOffset());
xDocShRef->DoClose();
}
@@ -768,7 +768,7 @@ void SdOOXMLExportTest1::testParaMarginAndindentation()
sal_Int32 nParaFirstLineIndent = 0;
xPropSet->getPropertyValue( "ParaFirstLineIndent" ) >>= nParaFirstLineIndent;
- CPPUNIT_ASSERT_EQUAL(sal_Int32(-1268), nParaFirstLineIndent);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(-1270), nParaFirstLineIndent);
xDocShRef->DoClose();
}
diff --git a/sd/qa/unit/export-tests-ooxml2.cxx b/sd/qa/unit/export-tests-ooxml2.cxx
index b38678f62a61..faaf35f71347 100644
--- a/sd/qa/unit/export-tests-ooxml2.cxx
+++ b/sd/qa/unit/export-tests-ooxml2.cxx
@@ -1772,9 +1772,9 @@ void SdOOXMLExportTest2::testTdf90626()
xmlDocUniquePtr pXmlDocContent = parseExport(tempFile, "ppt/slides/slide1.xml");
assertXPath(pXmlDocContent, "/p:sld/p:cSld/p:spTree/p:sp[2]/p:txBody/a:p[1]/a:pPr/a:buSzPct", "val", "100000");
- assertXPath(pXmlDocContent, "/p:sld/p:cSld/p:spTree/p:sp[2]/p:txBody/a:p[2]/a:pPr/a:buSzPct", "val", "150568");
+ assertXPath(pXmlDocContent, "/p:sld/p:cSld/p:spTree/p:sp[2]/p:txBody/a:p[2]/a:pPr/a:buSzPct", "val", "150142");
assertXPath(pXmlDocContent, "/p:sld/p:cSld/p:spTree/p:sp[2]/p:txBody/a:p[3]/a:pPr/a:buSzPct", "val", "100000");
- assertXPath(pXmlDocContent, "/p:sld/p:cSld/p:spTree/p:sp[2]/p:txBody/a:p[4]/a:pPr/a:buSzPct", "val", "150568");
+ assertXPath(pXmlDocContent, "/p:sld/p:cSld/p:spTree/p:sp[2]/p:txBody/a:p[4]/a:pPr/a:buSzPct", "val", "150142");
}
void SdOOXMLExportTest2::testTdf107608()
diff --git a/sd/qa/unit/import-tests.cxx b/sd/qa/unit/import-tests.cxx
index dc270a38da7d..12560e90d586 100644
--- a/sd/qa/unit/import-tests.cxx
+++ b/sd/qa/unit/import-tests.cxx
@@ -2696,7 +2696,7 @@ void SdImportTest::testTdf90626()
{
const SvxNumBulletItem *pNumFmt = aEdit.GetParaAttribs(i).GetItem(EE_PARA_NUMBULLET);
CPPUNIT_ASSERT(pNumFmt);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(tools::Long(371), pNumFmt->GetNumRule()->GetLevel(0).GetGraphicSize().getHeight(), tools::Long(1));
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(tools::Long(372), pNumFmt->GetNumRule()->GetLevel(0).GetGraphicSize().getHeight(), tools::Long(1));
}
xDocShRef->DoClose();
@@ -2780,7 +2780,7 @@ void SdImportTest::testTdf114913()
CPPUNIT_ASSERT_MESSAGE("No text object", pTxtObj != nullptr);
const SvxNumBulletItem *pItem = pTxtObj->GetOutlinerParaObject()->GetTextObject().GetParaAttribs(0).GetItem(EE_PARA_NUMBULLET);
CPPUNIT_ASSERT(pItem);
- CPPUNIT_ASSERT_EQUAL(tools::Long(691), pItem->GetNumRule()->GetLevel(0).GetGraphicSize().getHeight());
+ CPPUNIT_ASSERT_EQUAL(tools::Long(692), pItem->GetNumRule()->GetLevel(0).GetGraphicSize().getHeight());
xDocShRef->DoClose();
}
diff --git a/sd/source/ui/unoidl/unomodel.cxx b/sd/source/ui/unoidl/unomodel.cxx
index 230eeefeb420..35b1c376940c 100644
--- a/sd/source/ui/unoidl/unomodel.cxx
+++ b/sd/source/ui/unoidl/unomodel.cxx
@@ -2216,10 +2216,9 @@ void SdXImpressDocument::paintTile( VirtualDevice& rDevice,
// that VirtualDevices use a DPI of 96.
// We specifically calculate these scales first as we're still
// in TWIPs, and might as well minimize the number of conversions.
- Fraction scaleX = Fraction( nOutputWidth, 96 ) * Fraction(1440) /
- Fraction( nTileWidth);
- Fraction scaleY = Fraction( nOutputHeight, 96 ) * Fraction(1440) /
- Fraction( nTileHeight);
+ const Fraction scale = conversionFract(o3tl::Length::px, o3tl::Length::twip);
+ Fraction scaleX = Fraction(nOutputWidth, nTileWidth) * scale;
+ Fraction scaleY = Fraction(nOutputHeight, nTileHeight) * scale;
// svx seems to be the only component that works natively in
// 100th mm rather than TWIP. It makes most sense just to
diff --git a/sfx2/source/view/lokcharthelper.cxx b/sfx2/source/view/lokcharthelper.cxx
index a27fc70271bb..f80637133744 100644
--- a/sfx2/source/view/lokcharthelper.cxx
+++ b/sfx2/source/view/lokcharthelper.cxx
@@ -248,8 +248,9 @@ void LokChartHelper::PaintAllChartsOnTile(VirtualDevice& rDevice,
// Scaling. Must convert from pixels to twips. We know
// that VirtualDevices use a DPI of 96.
- Fraction scaleX = Fraction(nOutputWidth, 96) * Fraction(1440) / Fraction(nTileWidth);
- Fraction scaleY = Fraction(nOutputHeight, 96) * Fraction(1440) / Fraction(nTileHeight);
+ const Fraction scale = conversionFract(o3tl::Length::px, o3tl::Length::twip);
+ Fraction scaleX = Fraction(nOutputWidth, nTileWidth) * scale;
+ Fraction scaleY = Fraction(nOutputHeight, nTileHeight) * scale;
aMapMode.SetScaleX(scaleX);
aMapMode.SetScaleY(scaleY);
rDevice.SetMapMode(aMapMode);
diff --git a/svtools/source/misc/unitconv.cxx b/svtools/source/misc/unitconv.cxx
index 361570163063..bdff583182b5 100644
--- a/svtools/source/misc/unitconv.cxx
+++ b/svtools/source/misc/unitconv.cxx
@@ -17,8 +17,10 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
+#include <o3tl/temporary.hxx>
#include <svtools/unitconv.hxx>
#include <tools/debug.hxx>
+#include <tools/UnitConversion.hxx>
#include <vcl/outdev.hxx>
#include <vcl/weld.hxx>
@@ -125,80 +127,19 @@ tools::Long CalcToUnit( float nIn, MapUnit eUnit )
eUnit == MapUnit::MapMM ||
eUnit == MapUnit::MapCM, "this unit is not implemented" );
- float nTmp = nIn;
+ if (const auto eTo = MapToO3tlLength(eUnit); eTo != o3tl::Length::invalid)
+ return o3tl::convert(nIn, o3tl::Length::pt, eTo);
- if ( MapUnit::MapTwip != eUnit )
- nTmp = nIn * 10 / 567;
-
- switch ( eUnit )
- {
- case MapUnit::Map100thMM: nTmp *= 100; break;
- case MapUnit::Map10thMM: nTmp *= 10; break;
- case MapUnit::MapMM: break;
- case MapUnit::MapCM: nTmp /= 10; break;
- default: ;//prevent warning
- }
-
- nTmp *= 20;
- tools::Long nRet = static_cast<tools::Long>(nTmp);
- return nRet;
-//! return (long)(nTmp * 20);
+ return 0;
}
tools::Long ItemToControl( tools::Long nIn, MapUnit eItem, FieldUnit eCtrl )
{
- tools::Long nOut = 0;
-
- switch ( eItem )
- {
- case MapUnit::Map100thMM:
- case MapUnit::Map10thMM:
- case MapUnit::MapMM:
- {
- if ( eItem == MapUnit::Map10thMM )
- nIn /= 10;
- else if ( eItem == MapUnit::Map100thMM )
- nIn /= 100;
- nOut = TransformMetric( nIn, FieldUnit::MM, eCtrl );
- }
- break;
-
- case MapUnit::MapCM:
- {
- nOut = TransformMetric( nIn, FieldUnit::CM, eCtrl );
- }
- break;
-
- case MapUnit::Map1000thInch:
- case MapUnit::Map100thInch:
- case MapUnit::Map10thInch:
- case MapUnit::MapInch:
- {
- if ( eItem == MapUnit::Map10thInch )
- nIn /= 10;
- else if ( eItem == MapUnit::Map100thInch )
- nIn /= 100;
- else if ( eItem == MapUnit::Map1000thInch )
- nIn /= 1000;
- nOut = TransformMetric( nIn, FieldUnit::INCH, eCtrl );
- }
- break;
-
- case MapUnit::MapPoint:
- {
- nOut = TransformMetric( nIn, FieldUnit::POINT, eCtrl );
- }
- break;
-
- case MapUnit::MapTwip:
- {
- nOut = TransformMetric( nIn, FieldUnit::TWIP, eCtrl );
- }
- break;
- default: ;//prevent warning
- }
- return nOut;
+ const auto eFrom = MapToO3tlLength(eItem), eTo = FieldToO3tlLength(eCtrl);
+ if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
+ return o3tl::convert(nIn, eFrom, eTo);
+ return 0;
}
@@ -245,374 +186,18 @@ tools::Long CalcToPoint( tools::Long nIn, MapUnit eUnit, sal_uInt16 nFactor )
eUnit == MapUnit::MapMM ||
eUnit == MapUnit::MapCM, "this unit is not implemented" );
- tools::Long nRet = 0;
-
- if ( MapUnit::MapTwip == eUnit )
- nRet = nIn;
- else
- nRet = nIn * 567;
-
- switch ( eUnit )
- {
- case MapUnit::Map100thMM: nRet /= 100; break;
- case MapUnit::Map10thMM: nRet /= 10; break;
- case MapUnit::MapMM: break;
- case MapUnit::MapCM: nRet *= 10; break;
- default: ;//prevent warning
- }
-
- // round up if necessary
- if ( MapUnit::MapTwip != eUnit )
- {
- tools::Long nTmp = nRet % 10;
-
- if ( nTmp >= 4 )
- nRet += 10 - nTmp;
- nRet /= 10;
- }
- return nRet * nFactor / 20;
-}
-
-
-static tools::Long CMToTwips( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 567 ) && nIn >= ( LONG_MIN / 567 ) )
- nRet = nIn * 567;
- return nRet;
-}
-
-
-static tools::Long MMToTwips( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 567 ) && nIn >= ( LONG_MIN / 567 ) )
- nRet = nIn * 567 / 10;
- return nRet;
-}
-
-
-static tools::Long InchToTwips( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 1440 ) && nIn >= ( LONG_MIN / 1440 ) )
- nRet = nIn * 1440;
- return nRet;
-}
-
-
-tools::Long PointToTwips( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 20 ) && nIn >= ( LONG_MIN / 20 ) )
- nRet = nIn * 20;
- return nRet;
-}
-
-
-static tools::Long PicaToTwips( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 240 ) && nIn >= ( LONG_MIN / 240 ) )
- nRet = nIn * 240;
- return nRet;
-}
-
-
-static tools::Long TwipsToCM( tools::Long nIn )
-{
- tools::Long nRet = nIn / 567;
- return nRet;
-}
-
-
-static tools::Long InchToCM( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 254 ) && nIn >= ( LONG_MIN / 254 ) )
- nRet = nIn * 254 / 100;
- return nRet;
-}
-
-
-static tools::Long MMToCM( tools::Long nIn )
-{
- tools::Long nRet = nIn / 10;
- return nRet;
-}
-
-
-static tools::Long PointToCM( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 20 ) && nIn >= ( LONG_MIN / 20 ) )
- nRet = nIn * 20 / 567;
- return nRet;
-}
-
-
-static tools::Long PicaToCM( tools::Long nIn)
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 12 / 20 ) && nIn >= ( LONG_MIN / 12 / 20 ) )
- nRet = nIn * 12 * 20 / 567;
- return nRet;
-}
-
-
-static tools::Long TwipsToMM( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 10 ) && nIn >= ( LONG_MIN / 10 ) )
- nRet = nIn * 10 / 566;
- return nRet;
-}
-
-
-static tools::Long CMToMM( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 10 ) && nIn >= ( LONG_MIN / 10 ) )
- nRet = nIn * 10;
- return nRet;
-}
-
-
-static tools::Long InchToMM( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 254 ) && nIn >= ( LONG_MIN / 254 ) )
- nRet = nIn * 254 / 10;
- return nRet;
-}
-
-
-static tools::Long PointToMM( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 200 ) && nIn >= ( LONG_MIN / 200 ) )
- nRet = nIn * 200 / 567;
- return nRet;
-}
-
-
-static tools::Long PicaToMM( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 12 / 200 ) && nIn >= ( LONG_MIN / 12 / 200 ) )
- nRet = nIn * 12 * 200 / 567;
- return nRet;
-}
-
-
-static tools::Long TwipsToInch( tools::Long nIn )
-{
- tools::Long nRet = nIn / 1440;
- return nRet;
-}
-
-
-static tools::Long CMToInch( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 100 ) && nIn >= ( LONG_MIN / 100 ) )
- nRet = nIn * 100 / 254;
- return nRet;
-}
-
-
-static tools::Long MMToInch( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 10 ) && nIn >= ( LONG_MIN / 10 ) )
- nRet = nIn * 10 / 254;
- return nRet;
-}
-
-
-static tools::Long PointToInch( tools::Long nIn )
-{
- tools::Long nRet = nIn / 72;
- return nRet;
-}
-
-
-static tools::Long PicaToInch( tools::Long nIn )
-{
- tools::Long nRet = nIn / 6;
- return nRet;
-}
-
-
-static tools::Long TwipsToPoint( tools::Long nIn )
-{
- tools::Long nRet = nIn / 20;
- return nRet;
-}
-
-
-static tools::Long InchToPoint( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 72 ) && nIn >= ( LONG_MIN / 72 ) )
- nRet = nIn * 72;
- return nRet;
-}
-
-
-static tools::Long CMToPoint( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 567 ) && nIn >= ( LONG_MIN / 567 ) )
- nRet = nIn * 567 / 20;
- return nRet;
-}
-
-
-static tools::Long MMToPoint( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 567 ) && nIn >= ( LONG_MIN / 567 ) )
- nRet = nIn * 567 / 200;
- return nRet;
-}
-
-
-static tools::Long PicaToPoint( tools::Long nIn )
-{
- tools::Long nRet = nIn / 12;
- return nRet;
-}
-
-
-static tools::Long TwipsToPica( tools::Long nIn )
-{
- tools::Long nRet = nIn / 240;
- return nRet;
-}
-
-
-static tools::Long InchToPica( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 6 ) && nIn >= ( LONG_MIN / 6 ) )
- nRet = nIn * 6;
- return nRet;
-}
-
-
-static tools::Long PointToPica( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 12 ) && nIn >= ( LONG_MIN / 12 ) )
- nRet = nIn * 12;
- return nRet;
-}
-
-
-static tools::Long CMToPica( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 567 ) && nIn >= ( LONG_MIN / 567 ) )
- nRet = nIn * 567 / 20 / 12;
- return nRet;
+ if (const auto eTo = MapToO3tlLength(eUnit); eTo != o3tl::Length::invalid)
+ return o3tl::convert(nIn, eTo, o3tl::Length::pt) * nFactor;
+ return 0;
}
-static tools::Long MMToPica( tools::Long nIn )
-{
- tools::Long nRet = 0;
-
- if ( nIn <= ( LONG_MAX / 567 ) && nIn >= ( LONG_MIN / 567 ) )
- nRet = nIn * 567 / 200 / 12;
- return nRet;
-}
-
-
-static tools::Long Nothing( tools::Long nIn )
-{
- tools::Long nRet = nIn;
- return nRet;
-}
-
-FUNC_CONVERT const ConvertTable[6][6] =
-{
-// CM, MM INCH POINT PICAS=32 TWIPS
- { Nothing, CMToMM, CMToInch, CMToPoint, CMToPica, CMToTwips },
- { MMToCM, Nothing, MMToInch, MMToPoint, MMToPica, MMToTwips },
- { InchToCM, InchToMM, Nothing, InchToPoint, InchToPica, InchToTwips },
- { PointToCM, PointToMM, PointToInch, Nothing, PointToPica, PointToTwips },
- { PicaToCM, PicaToMM, PicaToInch, PicaToPoint, Nothing, PicaToTwips },
- { TwipsToCM, TwipsToMM, TwipsToInch, TwipsToPoint,TwipsToPica, Nothing }
-};
-
-
tools::Long TransformMetric( tools::Long nVal, FieldUnit aOld, FieldUnit aNew )
{
- if ( aOld == FieldUnit::NONE || aNew == FieldUnit::NONE ||
- aOld == FieldUnit::CUSTOM || aNew == FieldUnit::CUSTOM )
- {
+ const auto eFrom = FieldToO3tlLength(aOld), eTo = FieldToO3tlLength(aNew);
+ if (eFrom == o3tl::Length::invalid || eTo == o3tl::Length::invalid)
return nVal;
- }
-
- sal_uInt16 nOld = 0;
- sal_uInt16 nNew = 0;
-
- switch ( aOld )
- {
- case FieldUnit::CM:
- nOld = 0; break;
- case FieldUnit::MM:
- nOld = 1; break;
- case FieldUnit::INCH:
- nOld = 2; break;
- case FieldUnit::POINT:
- nOld = 3; break;
- case FieldUnit::PICA:
- nOld = 4; break;
- case FieldUnit::TWIP:
- nOld = 5; break;
- default: ;//prevent warning
- }
-
- switch ( aNew )
- {
- case FieldUnit::CM:
- nNew = 0; break;
- case FieldUnit::MM:
- nNew = 1; break;
- case FieldUnit::INCH:
- nNew = 2; break;
- case FieldUnit::POINT:
- nNew = 3; break;
- case FieldUnit::PICA:
- nNew = 4; break;
- case FieldUnit::TWIP:
- nNew = 5; break;
- default: ;//prevent warning
- }
- return ConvertTable[nOld][nNew]( nVal );
+ return o3tl::convert(nVal, eFrom, eTo, o3tl::temporary(bool())); // Just 0 when overflown
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/customshapes/EnhancedCustomShape3d.cxx b/svx/source/customshapes/EnhancedCustomShape3d.cxx
index 651d176f6076..9c933ef9313e 100644
--- a/svx/source/customshapes/EnhancedCustomShape3d.cxx
+++ b/svx/source/customshapes/EnhancedCustomShape3d.cxx
@@ -18,6 +18,7 @@
*/
#include "EnhancedCustomShape3d.hxx"
+#include <o3tl/unit_conversion.hxx>
#include <svx/deflt3d.hxx>
#include <svx/svdmodel.hxx>
#include <tools/poly.hxx>
@@ -262,7 +263,8 @@ SdrObject* EnhancedCustomShape3d::Create3DObject(
if ( rSdrObjCustomShape.getSdrModelFromSdrObject().GetScaleUnit() != MapUnit::Map100thMM )
{
DBG_ASSERT( rSdrObjCustomShape.getSdrModelFromSdrObject().GetScaleUnit() == MapUnit::MapTwip, "EnhancedCustomShape3d::Current MapMode is Unsupported" );
- fMap *= 1440.0 / 2540.0;
+ // But we could use MapToO3tlUnit from <tools/UnitConversion> ... ?
+ fMap *= o3tl::convert(1.0, o3tl::Length::mm100, o3tl::Length::twip);
pMap = &fMap;
}
diff --git a/svx/source/svdraw/svdmodel.cxx b/svx/source/svdraw/svdmodel.cxx
index f6f2f8797d72..d5add2eb33b4 100644
--- a/svx/source/svdraw/svdmodel.cxx
+++ b/svx/source/svdraw/svdmodel.cxx
@@ -71,6 +71,7 @@
#include <sfx2/viewsh.hxx>
#include <o3tl/enumrange.hxx>
#include <tools/diagnose_ex.h>
+#include <tools/UnitConversion.hxx>
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
@@ -866,94 +867,31 @@ void SdrModel::ImpSetUIUnit()
m_aUIScale = Fraction(1,1);
}
- // set start values
m_nUIUnitDecimalMark = 0;
- sal_Int64 nMul(1);
- sal_Int64 nDiv(1);
-
- // normalize on meters resp. inch
- switch (m_eObjUnit)
- {
- case MapUnit::Map100thMM : m_nUIUnitDecimalMark+=5; break;
- case MapUnit::Map10thMM : m_nUIUnitDecimalMark+=4; break;
- case MapUnit::MapMM : m_nUIUnitDecimalMark+=3; break;
- case MapUnit::MapCM : m_nUIUnitDecimalMark+=2; break;
- case MapUnit::Map1000thInch: m_nUIUnitDecimalMark+=3; break;
- case MapUnit::Map100thInch : m_nUIUnitDecimalMark+=2; break;
- case MapUnit::Map10thInch : m_nUIUnitDecimalMark+=1; break;
- case MapUnit::MapInch : m_nUIUnitDecimalMark+=0; break;
- case MapUnit::MapPoint : nDiv=72; break; // 1Pt = 1/72"
- case MapUnit::MapTwip : nDiv=144; m_nUIUnitDecimalMark++; break; // 1Twip = 1/1440"
- case MapUnit::MapPixel : break;
- case MapUnit::MapSysFont : break;
- case MapUnit::MapAppFont : break;
- case MapUnit::MapRelative : break;
- default: break;
- } // switch
- // 1 mile = 8 furlong = 63.360" = 1.609.344,0mm
- // 1 furlong = 10 chains = 7.920" = 201.168,0mm
- // 1 chain = 4 poles = 792" = 20.116,8mm
- // 1 pole = 5 1/2 yd = 198" = 5.029,2mm
- // 1 yd = 3 ft = 36" = 914,4mm
- // 1 ft = 12 " = 1" = 304,8mm
+ o3tl::Length eFrom = MapToO3tlLength(m_eObjUnit, o3tl::Length::invalid);
+ o3tl::Length eTo;
+
switch (m_eUIUnit)
{
- case FieldUnit::NONE : break;
- // metric
- case FieldUnit::MM_100TH: m_nUIUnitDecimalMark-=5; break;
- case FieldUnit::MM : m_nUIUnitDecimalMark-=3; break;
- case FieldUnit::CM : m_nUIUnitDecimalMark-=2; break;
- case FieldUnit::M : m_nUIUnitDecimalMark+=0; break;
- case FieldUnit::KM : m_nUIUnitDecimalMark+=3; break;
- // Inch
- case FieldUnit::TWIP : nMul=144; m_nUIUnitDecimalMark--; break; // 1Twip = 1/1440"
- case FieldUnit::POINT : nMul=72; break; // 1Pt = 1/72"
- case FieldUnit::PICA : nMul=6; break; // 1Pica = 1/6"
- case FieldUnit::INCH : break; // 1" = 1"
- case FieldUnit::FOOT : nDiv*=12; break; // 1Ft = 12"
- case FieldUnit::MILE : nDiv*=6336; m_nUIUnitDecimalMark++; break; // 1mile = 63360"
- // other
- case FieldUnit::CUSTOM : break;
- case FieldUnit::PERCENT: m_nUIUnitDecimalMark+=2; break;
- // TODO: Add code to handle the following if needed (added to remove warning)
- case FieldUnit::CHAR : break;
- case FieldUnit::LINE : break;
- case FieldUnit::PIXEL : break;
- case FieldUnit::DEGREE : break;
- case FieldUnit::SECOND : break;
- case FieldUnit::MILLISECOND : break;
+ case FieldUnit::CHAR:
+ case FieldUnit::LINE:
+ eTo = o3tl::Length::invalid;
+ break;
+ case FieldUnit::PERCENT:
+ m_nUIUnitDecimalMark += 2;
+ [[fallthrough]];
+ default:
+ eTo = FieldToO3tlLength(m_eUIUnit, o3tl::Length::invalid);
} // switch
- // check if mapping is from metric to inch and adapt
- const bool bMapInch(IsInch(m_eObjUnit));
- const bool bUIMetr(IsMetric(m_eUIUnit));
-
- if (bMapInch && bUIMetr)
+ sal_Int32 nMul = 1, nDiv = 1;
+ if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
{
- m_nUIUnitDecimalMark += 4;
- nMul *= 254;
+ const auto& [mul, div] = o3tl::getConversionMulDiv(eFrom, eTo);
+ nMul = mul;
+ nDiv = div;
}
-
- // check if mapping is from inch to metric and adapt
- const bool bMapMetr(IsMetric(m_eObjUnit));
- const bool bUIInch(IsInch(m_eUIUnit));
-
- if (bMapMetr && bUIInch)
- {
- m_nUIUnitDecimalMark -= 4;
- nDiv *= 254;
- }
-
- // use temporary fraction for reduction (fallback to 32bit here),
- // may need to be changed in the future, too
- if(1 != nMul || 1 != nDiv)
- {
- const Fraction aTemp(static_cast< tools::Long >(nMul), static_cast< tools::Long >(nDiv));
- nMul = aTemp.GetNumerator();
- nDiv = aTemp.GetDenominator();
- }
-
// #i89872# take Unit of Measurement into account
if(1 != m_aUIScale.GetDenominator() || 1 != m_aUIScale.GetNumerator())
{
diff --git a/svx/source/svdraw/svdtrans.cxx b/svx/source/svdraw/svdtrans.cxx
index 5b02f994cc12..6af3a49ea873 100644
--- a/svx/source/svdraw/svdtrans.cxx
+++ b/svx/source/svdraw/svdtrans.cxx
@@ -25,6 +25,7 @@
#include <vcl/virdev.hxx>
#include <tools/bigint.hxx>
+#include <tools/UnitConversion.hxx>
#include <unotools/syslocale.hxx>
#include <unotools/localedatawrapper.hxx>
#include <sal/log.hxx>
@@ -564,22 +565,28 @@ tools::Long BigMulDiv(tools::Long nVal, tools::Long nMul, tools::Long nDiv)
return BigInt::Scale(nVal, nMul, nDiv);
}
+static FrPair toPair(o3tl::Length eFrom, o3tl::Length eTo)
+{
+ const auto& [nNum, nDen] = o3tl::getConversionMulDiv(eFrom, eTo);
+ return FrPair(nNum, nDen);
+}
+
// How many eU units fit into a mm, respectively an inch?
// Or: How many mm, respectively inches, are there in an eU (and then give me the inverse)
static FrPair GetInchOrMM(MapUnit eU)
{
switch (eU) {
- case MapUnit::Map1000thInch: return FrPair(1000,1);
- case MapUnit::Map100thInch : return FrPair( 100,1);
- case MapUnit::Map10thInch : return FrPair( 10,1);
- case MapUnit::MapInch : return FrPair( 1,1);
- case MapUnit::MapPoint : return FrPair( 72,1);
- case MapUnit::MapTwip : return FrPair(1440,1);
- case MapUnit::Map100thMM : return FrPair( 100,1);
- case MapUnit::Map10thMM : return FrPair( 10,1);
- case MapUnit::MapMM : return FrPair( 1,1);
- case MapUnit::MapCM : return FrPair( 1,10);
+ case MapUnit::Map1000thInch: return toPair(o3tl::Length::in, o3tl::Length::in1000);
+ case MapUnit::Map100thInch : return toPair(o3tl::Length::in, o3tl::Length::in100);
+ case MapUnit::Map10thInch : return toPair(o3tl::Length::in, o3tl::Length::in10);
+ case MapUnit::MapInch : return toPair(o3tl::Length::in, o3tl::Length::in);
+ case MapUnit::MapPoint : return toPair(o3tl::Length::in, o3tl::Length::pt);
+ case MapUnit::MapTwip : return toPair(o3tl::Length::in, o3tl::Length::twip);
+ case MapUnit::Map100thMM : return toPair(o3tl::Length::mm, o3tl::Length::mm100);
+ case MapUnit::Map10thMM : return toPair(o3tl::Length::mm, o3tl::Length::mm10);
+ case MapUnit::MapMM : return toPair(o3tl::Length::mm, o3tl::Length::mm);
+ case MapUnit::MapCM : return toPair(o3tl::Length::mm, o3tl::Length::cm);
case MapUnit::MapPixel : {
ScopedVclPtrInstance< VirtualDevice > pVD;
pVD->SetMapMode(MapMode(MapUnit::Map100thMM));
@@ -599,31 +606,16 @@ static FrPair GetInchOrMM(MapUnit eU)
return Fraction(1,1);
}
-static FrPair GetInchOrMM(FieldUnit eU)
-{
- switch (eU) {
- case FieldUnit::INCH : return FrPair( 1,1);
- case FieldUnit::POINT : return FrPair( 72,1);
- case FieldUnit::TWIP : return FrPair(1440,1);
- case FieldUnit::MM_100TH : return FrPair( 100,1);
- case FieldUnit::MM : return FrPair( 1,1);
- case FieldUnit::CM : return FrPair( 1,10);
- case FieldUnit::M : return FrPair( 1,1000);
- case FieldUnit::KM : return FrPair( 1,1000000);
- case FieldUnit::PICA : return FrPair( 6,1);
- case FieldUnit::FOOT : return FrPair( 1,12);
- case FieldUnit::MILE : return FrPair( 1,63360);
- default: break;
- }
- return Fraction(1,1);
-}
-
// Calculate the factor that we need to convert units from eS to eD.
// e. g. GetMapFactor(UNIT_MM,UNIT_100TH_MM) => 100.
FrPair GetMapFactor(MapUnit eS, MapUnit eD)
{
if (eS==eD) return FrPair(1,1,1,1);
+ const auto eFrom = MapToO3tlLength(eS, o3tl::Length::invalid);
+ const auto eTo = MapToO3tlLength(eD, o3tl::Length::invalid);
+ if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
+ return toPair(eFrom, eTo);
FrPair aS(GetInchOrMM(eS));
FrPair aD(GetInchOrMM(eD));
bool bSInch=IsInch(eS);
@@ -637,84 +629,51 @@ FrPair GetMapFactor(MapUnit eS, MapUnit eD)
FrPair GetMapFactor(FieldUnit eS, FieldUnit eD)
{
if (eS==eD) return FrPair(1,1,1,1);
- FrPair aS(GetInchOrMM(eS));
- FrPair aD(GetInchOrMM(eD));
- bool bSInch=IsInch(eS);
- bool bDInch=IsInch(eD);
- FrPair aRet(aD.X()/aS.X(),aD.Y()/aS.Y());
- if (bSInch && !bDInch) { aRet.X()*=Fraction(127,5); aRet.Y()*=Fraction(127,5); }
- if (!bSInch && bDInch) { aRet.X()*=Fraction(5,127); aRet.Y()*=Fraction(5,127); }
- return aRet;
+ auto eFrom = FieldToO3tlLength(eS), eTo = FieldToO3tlLength(eD);
+ if (eFrom == o3tl::Length::invalid)
+ {
+ if (eTo == o3tl::Length::invalid)
+ return FrPair(1,1,1,1);
+ eFrom = IsInch(eD) ? o3tl::Length::in : o3tl::Length::mm;
+ }
+ else if (eTo == o3tl::Length::invalid)
+ eTo = IsInch(eS) ? o3tl::Length::in : o3tl::Length::mm;
+ return toPair(eFrom, eTo);
};
-
- // 1 mile = 8 furlong = 63.360" = 1.609.344,0mm
- // 1 furlong = 10 chains = 7.920" = 201.168,0mm
- // 1 chain = 4 poles = 792" = 20.116,8mm
- // 1 pole = 5 1/2 yd = 198" = 5.029,2mm
- // 1 yd = 3 ft = 36" = 914,4mm
- // 1 ft = 12 " = 1" = 304,8mm
-
-static void GetMeterOrInch(MapUnit eMU, short& rnComma, tools::Long& rnMul, tools::Long& rnDiv, bool& rbMetr, bool& rbInch)
-{
- rnMul=1; rnDiv=1;
- short nComma=0;
- bool bMetr = false, bInch = false;
- switch (eMU) {
- // Metrically
- case MapUnit::Map100thMM : bMetr = true; nComma=5; break;
- case MapUnit::Map10thMM : bMetr = true; nComma=4; break;
- case MapUnit::MapMM : bMetr = true; nComma=3; break;
- case MapUnit::MapCM : bMetr = true; nComma=2; break;
- // Inch
- case MapUnit::Map1000thInch: bInch = true; nComma=3; break;
- case MapUnit::Map100thInch : bInch = true; nComma=2; break;
- case MapUnit::Map10thInch : bInch = true; nComma=1; break;
- case MapUnit::MapInch : bInch = true; nComma=0; break;
- case MapUnit::MapPoint : bInch = true; rnDiv=72; break; // 1Pt = 1/72"
- case MapUnit::MapTwip : bInch = true; rnDiv=144; nComma=1; break; // 1Twip = 1/1440"
- // Others
- case MapUnit::MapPixel : break;
- case MapUnit::MapSysFont : break;
- case MapUnit::MapAppFont : break;
- case MapUnit::MapRelative : break;
- default: break;
- } // switch
- rnComma=nComma;
- rbMetr=bMetr;
- rbInch=bInch;
-}
-
-
void SdrFormatter::Undirty()
{
- bool bSrcMetr,bSrcInch,bDstMetr,bDstInch;
- tools::Long nMul1,nDiv1,nMul2,nDiv2;
- short nComma1,nComma2;
- // first: normalize to m or in
- GetMeterOrInch(eSrcMU,nComma1,nMul1,nDiv1,bSrcMetr,bSrcInch);
- GetMeterOrInch(eDstMU,nComma2,nMul2,nDiv2,bDstMetr,bDstInch);
- nMul1*=nDiv2;
- nDiv1*=nMul2;
- nComma1=nComma1-nComma2;
-
- if (bSrcInch && bDstMetr) {
- nComma1+=4;
- nMul1*=254;
- }
- if (bSrcMetr && bDstInch) {
- nComma1-=4;
- nDiv1*=254;
- }
-
- // temporary fraction for canceling
- Fraction aTempFract(nMul1,nDiv1);
- nMul1=aTempFract.GetNumerator();
- nDiv1=aTempFract.GetDenominator();
-
- nMul_=nMul1;
- nDiv_=nDiv1;
- nComma_=nComma1;
+ const o3tl::Length eFrom = MapToO3tlLength(eSrcMU, o3tl::Length::invalid);
+ const o3tl::Length eTo = MapToO3tlLength(eDstMU, o3tl::Length::invalid);
+ if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
+ {
+ const auto& [mul, div] = o3tl::getConversionMulDiv(eFrom, eTo);
+ sal_Int64 nMul = mul;
+ sal_Int64 nDiv = div;
+ short nComma = 0;
+
+ // shorten trailing zeros for dividend
+ while (0 == (nMul % 10))
+ {
+ nComma--;
+ nMul /= 10;
+ }
+
+ // shorten trailing zeros for divisor
+ while (0 == (nDiv % 10))
+ {
+ nComma++;
+ nDiv /= 10;
+ }
+ nMul_ = nMul;
+ nDiv_ = nDiv;
+ nComma_ = nComma;
+ }
+ else
+ {
+ nMul_ = nDiv_ = 1;
+ nComma_ = 0;
+ }
bDirty=false;
}
diff --git a/sw/source/core/view/viewsh.cxx b/sw/source/core/view/viewsh.cxx
index 5365b3399698..2c4ad8f2e8f4 100644
--- a/sw/source/core/view/viewsh.cxx
+++ b/sw/source/core/view/viewsh.cxx
@@ -77,6 +77,7 @@
#include <svx/svdpagv.hxx>
#include <comphelper/lok.hxx>
#include <sfx2/lokhelper.hxx>
+#include <tools/UnitConversion.hxx>
#if !HAVE_FEATURE_DESKTOP
#include <vcl/sysdata.hxx>
@@ -1903,8 +1904,9 @@ void SwViewShell::PaintTile(VirtualDevice &rDevice, int contextWidth, int contex
// Scaling. Must convert from pixels to twips. We know
// that VirtualDevices use a DPI of 96.
- Fraction scaleX = Fraction(contextWidth, 96) * Fraction(1440) / Fraction(tileWidth);
- Fraction scaleY = Fraction(contextHeight, 96) * Fraction(1440) / Fraction(tileHeight);
+ const Fraction scale = conversionFract(o3tl::Length::px, o3tl::Length::twip);
+ Fraction scaleX = Fraction(contextWidth, tileWidth) * scale;
+ Fraction scaleY = Fraction(contextHeight, tileHeight) * scale;
aMapMode.SetScaleX(scaleX);
aMapMode.SetScaleY(scaleY);
rDevice.SetMapMode(aMapMode);
diff --git a/sw/source/filter/html/css1atr.cxx b/sw/source/filter/html/css1atr.cxx
index b2515833eba7..0b3721fe4caa 100644
--- a/sw/source/filter/html/css1atr.cxx
+++ b/sw/source/filter/html/css1atr.cxx
@@ -91,6 +91,7 @@
#include <IDocumentStylePoolAccess.hxx>
#include <numrule.hxx>
#include <o3tl/typed_flags_set.hxx>
+#include <o3tl/unit_conversion.hxx>
#include <rtl/strbuf.hxx>
@@ -376,10 +377,8 @@ static void AddUnitPropertyValue(OStringBuffer &rOut, tools::Long nVal,
rOut.append('-');
}
- // the recalculated unit results from (x * nMul)/(nDiv*nFac*10)
- tools::Long nMul = 1000;
- tools::Long nDiv = 1;
- tools::Long nFac = 100;
+ o3tl::Length eTo;
+ int nFac; // used to get specific number of decimals
const char *pUnit;
switch( eUnit )
{
@@ -387,9 +386,7 @@ static void AddUnitPropertyValue(OStringBuffer &rOut, tools::Long nVal,
OSL_ENSURE( FieldUnit::MM == eUnit, "Measuring unit not supported" );
[[fallthrough]];
case FieldUnit::MM:
- // 0.01mm = 0.57twip
- nMul = 25400; // 25.4 * 1000
- nDiv = 1440; // 72 * 20;
+ eTo = o3tl::Length::mm;
nFac = 100;
pUnit = sCSS1_UNIT_mm;
break;
@@ -399,9 +396,7 @@ static void AddUnitPropertyValue(OStringBuffer &rOut, tools::Long nVal,
OSL_ENSURE( FieldUnit::CM == eUnit, "Measuring unit not supported" );
[[fallthrough]];
case FieldUnit::CM:
- // 0.01cm = 5.7twip (not exact, but the UI is also not exact)
- nMul = 2540; // 2.54 * 1000
- nDiv = 1440; // 72 * 20;
+ eTo = o3tl::Length::cm;
nFac = 100;
pUnit = sCSS1_UNIT_cm;
break;
@@ -410,17 +405,13 @@ static void AddUnitPropertyValue(OStringBuffer &rOut, tools::Long nVal,
OSL_ENSURE( FieldUnit::POINT == eUnit, "Measuring unit not supported" );
[[fallthrough]];
case FieldUnit::POINT:
- // 0.1pt = 2.0twip (not exact, but the UI is also not exact)
- nMul = 100;
- nDiv = 20;
+ eTo = o3tl::Length::pt;
nFac = 10;
pUnit = sCSS1_UNIT_pt;
break;
case FieldUnit::PICA:
- // 0.01pc = 2.40twip (not exact, but the UI is also not exact)
- nMul = 1000;
- nDiv = 240; // 12 * 20;
+ eTo = o3tl::Length::pc;
nFac = 100;
pUnit = sCSS1_UNIT_pc;
break;
@@ -433,63 +424,21 @@ static void AddUnitPropertyValue(OStringBuffer &rOut, tools::Long nVal,
case FieldUnit::INCH:
default:
OSL_ENSURE( FieldUnit::INCH == eUnit, "Measuring unit not supported" );
- // 0.01in = 14.4twip (not exact, but the UI is also not exact)
- nMul = 1000;
- nDiv = 1440; // 72 * 20;
+ eTo = o3tl::Length::in;
nFac = 100;
pUnit = sCSS1_UNIT_inch;
break;
}
- tools::Long nLongVal = 0;
- bool bOutLongVal = true;
- if( nVal > LONG_MAX / nMul )
+ sal_Int64 nResult = o3tl::convert(nVal * nFac, o3tl::Length::twip, eTo);
+ rOut.append(OString::number(nResult/nFac));
+ if ((nResult % nFac) != 0)
{
- sal_Int64 nBigVal( nVal );
- nBigVal *= nMul;
- nBigVal /= nDiv;
- nBigVal += 5;
- nBigVal /= 10;
-
- if( nBigVal <= LONG_MAX )
- {
- // a long is sufficient
- nLongVal = static_cast<tools::Long>(nBigVal);
- }
- else
- {
- rOut.append(nBigVal / static_cast<sal_Int64>(nFac));
- if( (nBigVal % static_cast<sal_Int64>(nFac)) != 0 )
- {
- rOut.append('.');
- while( nFac > 1 && (nBigVal % static_cast<sal_Int64>(nFac)) != 0 )
- {
- nFac /= 10;
- rOut.append((nBigVal / static_cast<sal_Int64>(nFac)) % sal_Int64(10));
- }
- }
- bOutLongVal = false;
- }
- }
- else
- {
- nLongVal = nVal * nMul;
- nLongVal /= nDiv;
- nLongVal += 5;
- nLongVal /= 10;
- }
-
- if( bOutLongVal )
- {
- rOut.append(OString::number(nLongVal/nFac));
- if( (nLongVal % nFac) != 0 )
+ rOut.append('.');
+ while (nFac > 1 && (nResult % nFac) != 0)
{
- rOut.append('.');
- while( nFac > 1 && (nLongVal % nFac) != 0 )
- {
- nFac /= 10;
- rOut.append(OString::number((nLongVal / nFac) % 10));
- }
+ nFac /= 10;
+ rOut.append(OString::number((nResult / nFac) % 10));
}
}
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index c9f78fd2c446..ddc26f1a3be4 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -133,6 +133,7 @@
#include <txtatr.hxx>
#include <frameformats.hxx>
+#include <o3tl/unit_conversion.hxx>
#include <osl/file.hxx>
#include <utility>
#include <vcl/embeddedfontshelper.hxx>
@@ -9271,10 +9272,10 @@ void DocxAttributeOutput::FormatBox( const SvxBoxItem& rBox )
double fDistanceBottomTwips = double(rBox.GetDistance(SvxBoxItemLine::BOTTOM));
// Convert 'TWIPS' to 'INCH' (because in Word the default values are in Inches)
- double fDistanceLeftInch = fDistanceLeftTwips / 1440;
- double fDistanceTopInch = fDistanceTopTwips / 1440;
- double fDistanceRightInch = fDistanceRightTwips / 1440;
- double fDistanceBottomInch = fDistanceBottomTwips / 1440;
+ double fDistanceLeftInch = o3tl::convert(fDistanceLeftTwips, o3tl::Length::twip, o3tl::Length::in);
+ double fDistanceTopInch = o3tl::convert(fDistanceTopTwips, o3tl::Length::twip, o3tl::Length::in);
+ double fDistanceRightInch = o3tl::convert(fDistanceRightTwips, o3tl::Length::twip, o3tl::Length::in);
+ double fDistanceBottomInch = o3tl::convert(fDistanceBottomTwips, o3tl::Length::twip, o3tl::Length::in);
// This code will write ONLY the non-default values. The values are in 'left','top','right','bottom' order.
// so 'bottom' is checked if it is default and if it is non-default - all the values will be written
diff --git a/sw/source/filter/ww8/wrtw8esh.cxx b/sw/source/filter/ww8/wrtw8esh.cxx
index bee858964b4e..a964516780db 100644
--- a/sw/source/filter/ww8/wrtw8esh.cxx
+++ b/sw/source/filter/ww8/wrtw8esh.cxx
@@ -2145,11 +2145,8 @@ void SwBasicEscherEx::Init()
}
// MS-DFF-Properties mostly are in EMU (English Metric Units)
- // 1mm=36000emu, 1twip=635emu
- Fraction aFact(360, 1);
+ Fraction aFact = conversionFract(o3tl::Length::mm100, o3tl::Length::emu);
aFact /= GetMapFactor(MapUnit::Map100thMM, eMap).X();
- // create little values
- aFact = Fraction(aFact.GetNumerator(), aFact.GetDenominator());
mnEmuMul = aFact.GetNumerator();
mnEmuDiv = aFact.GetDenominator();
diff --git a/sw/source/filter/ww8/ww8par6.cxx b/sw/source/filter/ww8/ww8par6.cxx
index 44acfec4b3fb..9cffb20357fe 100644
--- a/sw/source/filter/ww8/ww8par6.cxx
+++ b/sw/source/filter/ww8/ww8par6.cxx
@@ -19,6 +19,7 @@
#include <stdlib.h>
#include <o3tl/safeint.hxx>
+#include <o3tl/unit_conversion.hxx>
#include <svl/itemiter.hxx>
#include <svl/grabbagitem.hxx>
#include <rtl/tencinfo.h>
@@ -106,8 +107,10 @@ using namespace nsHdFtFlags;
// various
-#define MM_250 1417 // WW default for horizontal borders: 2.5 cm
-#define MM_200 1134 // WW default for lower border: 2.0 cm
+// WW default for horizontal borders: 2.5 cm
+constexpr auto MM_250 = o3tl::convert(25, o3tl::Length::mm, o3tl::Length::twip); // 1417
+// WW default for lower border: 2.0 cm
+constexpr auto MM_200 = o3tl::convert(20, o3tl::Length::mm, o3tl::Length::twip); // 1134
static sal_uInt8 lcl_ReadBorders(bool bVer67, WW8_BRCVer9* brc, WW8PLCFx_Cp_FKP* pPap,
diff --git a/vcl/source/control/field.cxx b/vcl/source/control/field.cxx
index f232e50a7c7a..9a42dcb2d8a5 100644
--- a/vcl/source/control/field.cxx
+++ b/vcl/source/control/field.cxx
@@ -19,12 +19,14 @@
#include <sal/config.h>
+#include <cmath>
#include <string_view>
#include <sal/log.hxx>
#include <osl/diagnose.h>
#include <comphelper/string.hxx>
+#include <tools/UnitConversion.hxx>
#include <vcl/builder.hxx>
#include <vcl/fieldvalues.hxx>
@@ -972,35 +974,6 @@ static FieldUnit ImplMetricGetUnit(const OUString& rStr)
return vcl::StringToMetric(aStr);
}
-#define K *1000L
-#define M *1000000LL
-#define X *5280L
-
-// twip in km = 254 / 14 400 000 000
-// expressions too big for default size 32 bit need LL to avoid overflow
-
-const sal_Int64 aImplFactor[sal_uInt16(FieldUnit::LINE) + 1]
- [sal_uInt16(FieldUnit::LINE) + 1] =
-{ /*
-mm/100 mm cm m km twip point pica inch foot mile char line */
-{ 1, 100, 1 K, 100 K, 100 M, 2540, 2540, 2540, 2540,2540*12,2540*12 X , 53340, 396240},
-{ 1, 1, 10, 1 K, 1 M, 2540, 2540, 2540, 2540,2540*12,2540*12 X , 5334, 396240},
-{ 1, 1, 1, 100, 100 K, 254, 254, 254, 254, 254*12, 254*12 X , 5334, 39624},
-{ 1, 1, 1, 1, 1 K, 254, 254, 254, 254, 254*12, 254*12 X , 533400, 39624},
-{ 1, 1, 1, 1, 1, 254, 254, 254, 254, 254*12, 254*12 X ,533400 K, 39624},
-{ 1440,144 K,144 K,14400 K,14400LL M, 1, 20, 240, 1440,1440*12,1440*12 X , 210, 3120},
-{ 72, 7200, 7200, 720 K, 720 M, 1, 1, 12, 72, 72*12, 72*12 X , 210, 156},
-{ 6, 600, 600, 60 K, 60 M, 1, 1, 1, 6, 6*12, 6*12 X , 210, 10},
-{ 1, 100, 100, 10 K, 10 M, 1, 1, 1, 1, 12, 12 X , 210, 45},
-{ 1, 100, 100, 10 K, 10 M, 1, 1, 1, 1, 1, 1 X , 210, 45},
-{ 1, 100, 100, 10 K, 10 M, 1, 1, 1, 1, 1, 1 , 210, 45},
-{ 144, 1440,14400, 14400, 14400, 1, 20, 240, 1440,1440*12, 1440*12 X, 1, 156 },
-{ 720,72000,72000, 7200 K,7200LL M, 20, 10, 13, 11, 11*12, 11*12 X, 105, 1 }
-};
-#undef X
-#undef M
-#undef K
-
static FieldUnit ImplMap2FieldUnit( MapUnit meUnit, tools::Long& nDecDigits )
{
switch( meUnit )
@@ -1057,7 +1030,7 @@ namespace vcl
else if ( nDouble >= double(SAL_MAX_INT64) )
nLong = SAL_MAX_INT64;
else
- nLong = static_cast<sal_Int64>( nDouble );
+ nLong = static_cast<sal_Int64>( std::round(nDouble) );
return nLong;
}
@@ -1094,20 +1067,11 @@ double convertValue( double nValue, tools::Long nDigits, FieldUnit eInUnit, Fiel
if ( eInUnit != eOutUnit )
{
- sal_Int64 nDiv = aImplFactor[sal_uInt16(eInUnit)][sal_uInt16(eOutUnit)];
- sal_Int64 nMult = aImplFactor[sal_uInt16(eOutUnit)][sal_uInt16(eInUnit)];
-
- SAL_WARN_IF( nMult <= 0, "vcl", "illegal *" );
- SAL_WARN_IF( nDiv <= 0, "vcl", "illegal /" );
-
- if ( nMult != 1 && nMult > 0)
- nValue *= nMult;
- if ( nDiv != 1 && nDiv > 0 )
- {
- nValue += (nValue < 0) ? (-nDiv/2) : (nDiv/2);
- nValue /= nDiv;
- }
+ const o3tl::Length eFrom = FieldToO3tlLength(eInUnit), eTo = FieldToO3tlLength(eOutUnit);
+ if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
+ nValue = o3tl::convert(nValue, eFrom, eTo);
}
+
return nValue;
}
@@ -1143,49 +1107,22 @@ namespace vcl
{
if ( eInUnit != eOutUnit )
{
- sal_Int64 nMult = 1, nDiv = 1;
-
- if (eInUnit == FieldUnit::PERCENT)
+ if (eInUnit == FieldUnit::PERCENT && mnBaseValue > 0 && nValue > 0)
{
- if ( (mnBaseValue <= 0) || (nValue <= 0) )
- return nValue;
- nDiv = 100 * ImplPower10(nDecDigits);
+ sal_Int64 nDiv = 100 * ImplPower10(nDecDigits);
- nMult = mnBaseValue;
- }
- else if ( eOutUnit == FieldUnit::PERCENT ||
- eOutUnit == FieldUnit::CUSTOM ||
- eOutUnit == FieldUnit::NONE ||
- eOutUnit == FieldUnit::DEGREE ||
- eOutUnit == FieldUnit::SECOND ||
- eOutUnit == FieldUnit::MILLISECOND ||
- eOutUnit == FieldUnit::PIXEL ||
- eInUnit == FieldUnit::CUSTOM ||
- eInUnit == FieldUnit::NONE ||
- eInUnit == FieldUnit::DEGREE ||
- eInUnit == FieldUnit::MILLISECOND ||
- eInUnit == FieldUnit::PIXEL )
- return nValue;
- else
- {
- if (eOutUnit == FieldUnit::MM_100TH)
- eOutUnit = FieldUnit::NONE;
- if (eInUnit == FieldUnit::MM_100TH)
- eInUnit = FieldUnit::NONE;
+ if (mnBaseValue != 1)
+ nValue *= mnBaseValue;
- nDiv = aImplFactor[sal_uInt16(eInUnit)][sal_uInt16(eOutUnit)];
- nMult = aImplFactor[sal_uInt16(eOutUnit)][sal_uInt16(eInUnit)];
-
- SAL_WARN_IF( nMult <= 0, "vcl", "illegal *" );
- SAL_WARN_IF( nDiv <= 0, "vcl", "illegal /" );
+ nValue += nDiv / 2;
+ nValue /= nDiv;
}
-
- if ( nMult != 1 && nMult > 0 )
- nValue *= nMult;
- if ( nDiv != 1 && nDiv > 0 )
+ else
{
- nValue += ( nValue < 0 ) ? (-nDiv/2) : (nDiv/2);
- nValue /= nDiv;
+ const o3tl::Length eFrom = FieldToO3tlLength(eInUnit, o3tl::Length::invalid);
+ const o3tl::Length eTo = FieldToO3tlLength(eOutUnit, o3tl::Length::invalid);
+ if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
+ nValue = o3tl::convert(nValue, eFrom, eTo);
}
}
@@ -1240,19 +1177,10 @@ namespace vcl
if ( eFieldUnit != eInUnit )
{
- sal_Int64 nDiv = aImplFactor[sal_uInt16(eInUnit)][sal_uInt16(eFieldUnit)];
- sal_Int64 nMult = aImplFactor[sal_uInt16(eFieldUnit)][sal_uInt16(eInUnit)];
-
- SAL_WARN_IF( nMult <= 0, "vcl", "illegal *" );
- SAL_WARN_IF( nDiv <= 0, "vcl", "illegal /" );
-
- if( nMult != 1 && nMult > 0 )
- nValue *= nMult;
- if( nDiv != 1 && nDiv > 0 )
- {
- nValue += (nValue < 0) ? (-nDiv/2) : (nDiv/2);
- nValue /= nDiv;
- }
+ const o3tl::Length eFrom = FieldToO3tlLength(eInUnit, o3tl::Length::invalid);
+ const o3tl::Length eTo = FieldToO3tlLength(eFieldUnit, o3tl::Length::invalid);
+ if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
+ nValue = o3tl::convert(nValue, eFrom, eTo);
}
return nValue;
}
diff --git a/vcl/source/gdi/pdfwriter_impl2.cxx b/vcl/source/gdi/pdfwriter_impl2.cxx
index e349d8e837f9..304647aa1233 100644
--- a/vcl/source/gdi/pdfwriter_impl2.cxx
+++ b/vcl/source/gdi/pdfwriter_impl2.cxx
@@ -43,6 +43,7 @@
#include <com/sun/star/beans/XMaterialHolder.hpp>
#include <cppuhelper/implbase.hxx>
+#include <o3tl/unit_conversion.hxx>
#include <sal/log.hxx>
#include <memory>
@@ -116,8 +117,12 @@ void PDFWriterImpl::implWriteBitmapEx( const Point& i_rPoint, const Size& i_rSiz
const Size aDstSizeTwip( i_pDummyVDev->PixelToLogic(i_pDummyVDev->LogicToPixel(aSize), MapMode(MapUnit::MapTwip)) );
const double fBmpPixelX = aBmpSize.Width();
const double fBmpPixelY = aBmpSize.Height();
- const double fMaxPixelX = aDstSizeTwip.Width() * i_rContext.m_nMaxImageResolution / 1440.0;
- const double fMaxPixelY = aDstSizeTwip.Height() * i_rContext.m_nMaxImageResolution / 1440.0;
+ const double fMaxPixelX
+ = o3tl::convert<double>(aDstSizeTwip.Width(), o3tl::Length::twip, o3tl::Length::in)
+ * i_rContext.m_nMaxImageResolution;
+ const double fMaxPixelY
+ = o3tl::convert<double>(aDstSizeTwip.Height(), o3tl::Length::twip, o3tl::Length::in)
+ * i_rContext.m_nMaxImageResolution;
// check, if the bitmap DPI exceeds the maximum DPI (allow 4 pixel rounding tolerance)
if( ( ( fBmpPixelX > ( fMaxPixelX + 4 ) ) ||
@@ -460,8 +465,8 @@ void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevDa
if ( nMaxBmpDPI > i_rContext.m_nMaxImageResolution )
nMaxBmpDPI = i_rContext.m_nMaxImageResolution;
}
- const sal_Int32 nPixelX = static_cast<sal_Int32>(static_cast<double>(aDstSizeTwip.Width()) * static_cast<double>(nMaxBmpDPI) / 1440.0);
- const sal_Int32 nPixelY = static_cast<sal_Int32>(static_cast<double>(aDstSizeTwip.Height()) * static_cast<double>(nMaxBmpDPI) / 1440.0);
+ const sal_Int32 nPixelX = o3tl::convert<double>(aDstSizeTwip.Width(), o3tl::Length::twip, o3tl::Length::in) * nMaxBmpDPI;
+ const sal_Int32 nPixelY = o3tl::convert<double>(aDstSizeTwip.Height(), o3tl::Length::twip, o3tl::Length::in) * nMaxBmpDPI;
if ( nPixelX && nPixelY )
{
Size aDstSizePixel( nPixelX, nPixelY );
diff --git a/vcl/source/outdev/bitmap.cxx b/vcl/source/outdev/bitmap.cxx
index c69938b11878..6c93084f0062 100644
--- a/vcl/source/outdev/bitmap.cxx
+++ b/vcl/source/outdev/bitmap.cxx
@@ -46,6 +46,7 @@
#include <tools/helpers.hxx>
#include <tools/debug.hxx>
#include <rtl/math.hxx>
+#include <o3tl/unit_conversion.hxx>
#include <vcl/dibtools.hxx>
#include <tools/stream.hxx>
@@ -216,8 +217,12 @@ Bitmap OutputDevice::GetDownsampledBitmap( const Size& rDstSz,
const Size aBmpSize( aBmp.GetSizePixel() );
const double fBmpPixelX = aBmpSize.Width();
const double fBmpPixelY = aBmpSize.Height();
- const double fMaxPixelX = aDstSizeTwip.Width() * nMaxBmpDPIX / 1440.0;
- const double fMaxPixelY = aDstSizeTwip.Height() * nMaxBmpDPIY / 1440.0;
+ const double fMaxPixelX
+ = o3tl::convert<double>(aDstSizeTwip.Width(), o3tl::Length::twip, o3tl::Length::in)
+ * nMaxBmpDPIX;
+ const double fMaxPixelY
+ = o3tl::convert<double>(aDstSizeTwip.Height(), o3tl::Length::twip, o3tl::Length::in)
+ * nMaxBmpDPIY;
// check, if the bitmap DPI exceeds the maximum DPI (allow 4 pixel rounding tolerance)
if( ( ( fBmpPixelX > ( fMaxPixelX + 4 ) ) ||
diff --git a/vcl/source/outdev/map.cxx b/vcl/source/outdev/map.cxx
index 09ae63b0174d..e899fdc96fa4 100644
--- a/vcl/source/outdev/map.cxx
+++ b/vcl/source/outdev/map.cxx
@@ -33,14 +33,7 @@
#include <outdev.h>
#include <basegfx/matrix/b2dhommatrix.hxx>
-#include <o3tl/enumarray.hxx>
-
-// we don't actually handle units beyond, hence the zeros in the arrays
-const MapUnit s_MaxValidUnit = MapUnit::MapPixel;
-const o3tl::enumarray<MapUnit,tools::Long> aImplNumeratorAry =
- { 1, 1, 5, 50, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 };
-const o3tl::enumarray<MapUnit,tools::Long> aImplDenominatorAry =
- { 2540, 254, 127, 127, 1000, 100, 10, 1, 72, 1440, 1, 0, 0, 0 };
+#include <tools/UnitConversion.hxx>
/*
Reduces accuracy until it is a fraction (should become
@@ -82,6 +75,13 @@ static Fraction ImplMakeFraction( tools::Long nN1, tools::Long nN2, tools::Long
return aF;
}
+static auto setMapRes(ImplMapRes& rMapRes, const o3tl::Length eUnit)
+{
+ const auto [nNum, nDen] = o3tl::getConversionMulDiv(eUnit, o3tl::Length::in);
+ rMapRes.mnMapScNumX = rMapRes.mnMapScNumY = nNum;
+ rMapRes.mnMapScDenomX = rMapRes.mnMapScDenomY = nDen;
+};
+
static void ImplCalcMapResolution( const MapMode& rMapMode,
tools::Long nDPIX, tools::Long nDPIY, ImplMapRes& rMapRes )
{
@@ -90,64 +90,34 @@ static void ImplCalcMapResolution( const MapMode& rMapMode,
case MapUnit::MapRelative:
break;
case MapUnit::Map100thMM:
- rMapRes.mnMapScNumX = 1;
- rMapRes.mnMapScDenomX = 2540;
- rMapRes.mnMapScNumY = 1;
- rMapRes.mnMapScDenomY = 2540;
+ setMapRes(rMapRes, o3tl::Length::mm100);
break;
case MapUnit::Map10thMM:
- rMapRes.mnMapScNumX = 1;
- rMapRes.mnMapScDenomX = 254;
- rMapRes.mnMapScNumY = 1;
- rMapRes.mnMapScDenomY = 254;
+ setMapRes(rMapRes, o3tl::Length::mm10);
break;
case MapUnit::MapMM:
- rMapRes.mnMapScNumX = 5; // 10
- rMapRes.mnMapScDenomX = 127; // 254
- rMapRes.mnMapScNumY = 5; // 10
- rMapRes.mnMapScDenomY = 127; // 254
+ setMapRes(rMapRes, o3tl::Length::mm);
break;
case MapUnit::MapCM:
- rMapRes.mnMapScNumX = 50; // 100
- rMapRes.mnMapScDenomX = 127; // 254
- rMapRes.mnMapScNumY = 50; // 100
- rMapRes.mnMapScDenomY = 127; // 254
+ setMapRes(rMapRes, o3tl::Length::cm);
break;
case MapUnit::Map1000thInch:
- rMapRes.mnMapScNumX = 1;
- rMapRes.mnMapScDenomX = 1000;
- rMapRes.mnMapScNumY = 1;
- rMapRes.mnMapScDenomY = 1000;
+ setMapRes(rMapRes, o3tl::Length::in1000);
break;
case MapUnit::Map100thInch:
- rMapRes.mnMapScNumX = 1;
- rMapRes.mnMapScDenomX = 100;
- rMapRes.mnMapScNumY = 1;
- rMapRes.mnMapScDenomY = 100;
+ setMapRes(rMapRes, o3tl::Length::in100);
break;
case MapUnit::Map10thInch:
- rMapRes.mnMapScNumX = 1;
- rMapRes.mnMapScDenomX = 10;
- rMapRes.mnMapScNumY = 1;
- rMapRes.mnMapScDenomY = 10;
+ setMapRes(rMapRes, o3tl::Length::in10);
break;
case MapUnit::MapInch:
- rMapRes.mnMapScNumX = 1;
- rMapRes.mnMapScDenomX = 1;
- rMapRes.mnMapScNumY = 1;
- rMapRes.mnMapScDenomY = 1;
+ setMapRes(rMapRes, o3tl::Length::in);
break;
case MapUnit::MapPoint:
- rMapRes.mnMapScNumX = 1;
- rMapRes.mnMapScDenomX = 72;
- rMapRes.mnMapScNumY = 1;
- rMapRes.mnMapScDenomY = 72;
+ setMapRes(rMapRes, o3tl::Length::pt);
break;
case MapUnit::MapTwip:
- rMapRes.mnMapScNumX = 1;
- rMapRes.mnMapScDenomX = 1440;
- rMapRes.mnMapScNumY = 1;
- rMapRes.mnMapScDenomY = 1440;
+ setMapRes(rMapRes, o3tl::Length::twip);
break;
case MapUnit::MapPixel:
rMapRes.mnMapScNumX = 1;
@@ -701,8 +671,10 @@ void OutputDevice::SetRelativeMapMode( const MapMode& rNewMapMode )
}
else
{
- Fraction aF( aImplNumeratorAry[eNew] * aImplDenominatorAry[eOld],
- aImplNumeratorAry[eOld] * aImplDenominatorAry[eNew] );
+ const auto eFrom = MapToO3tlLength(eOld, o3tl::Length::in);
+ const auto eTo = MapToO3tlLength(eNew, o3tl::Length::in);
+ const auto& [nNum, nDen] = o3tl::getConversionMulDiv(eFrom, eTo);
+ Fraction aF(nNum, nDen);
// a?F = a?F * aF
aXF = ImplMakeFraction( aXF.GetNumerator(), aF.GetNumerator(),
@@ -1322,22 +1294,25 @@ static void verifyUnitSourceDest( MapUnit eUnitSource, MapUnit eUnitDest )
"Destination MapUnit is not permitted" );
}
-#define ENTER3( eUnitSource, eUnitDest ) \
- tools::Long nNumerator = 1; \
- tools::Long nDenominator = 1; \
- SAL_WARN_IF( eUnitSource > s_MaxValidUnit, "vcl.gdi", "Invalid source map unit"); \
- SAL_WARN_IF( eUnitDest > s_MaxValidUnit, "vcl.gdi", "Invalid destination map unit"); \
- if( (eUnitSource <= s_MaxValidUnit) && (eUnitDest <= s_MaxValidUnit) ) \
- { \
- nNumerator = aImplNumeratorAry[eUnitSource] * \
- aImplDenominatorAry[eUnitDest]; \
- nDenominator = aImplNumeratorAry[eUnitDest] * \
- aImplDenominatorAry[eUnitSource]; \
- } \
- if ( eUnitSource == MapUnit::MapPixel ) \
- nDenominator *= 72; \
- else if( eUnitDest == MapUnit::MapPixel ) \
- nNumerator *= 72
+namespace
+{
+auto getCorrectedUnit(MapUnit eMapSrc, MapUnit eMapDst)
+{
+ o3tl::Length eSrc = o3tl::Length::invalid;
+ o3tl::Length eDst = o3tl::Length::invalid;
+ if (eMapSrc > MapUnit::MapPixel)
+ SAL_WARN("vcl.gdi", "Invalid source map unit");
+ else if (eMapDst > MapUnit::MapPixel)
+ SAL_WARN("vcl.gdi", "Invalid destination map unit");
+ else if (eMapSrc != eMapDst)
+ {
+ // Here 72 PPI is assumed for MapPixel
+ eSrc = MapToO3tlLength(eMapSrc, o3tl::Length::pt);
+ eDst = MapToO3tlLength(eMapDst, o3tl::Length::pt);
+ }
+ return std::make_pair(eSrc, eDst);
+}
+}
#define ENTER4( rMapModeSource, rMapModeDest ) \
ImplMapRes aMapResSource; \
@@ -1464,13 +1439,15 @@ static tools::Long fn5( const tools::Long n1,
} // of else
}
-// return (n1 * n2) / n3
-static tools::Long fn3( const tools::Long n1, const tools::Long n2, const tools::Long n3 )
+static tools::Long fn3(const tools::Long n1, const o3tl::Length eFrom, const o3tl::Length eTo)
{
- if ( n1 == 0 || n2 == 0 || n3 == 0 )
+ if (n1 == 0 || eFrom == o3tl::Length::invalid || eTo == o3tl::Length::invalid)
return 0;
- if (std::numeric_limits<tools::Long>::max() / std::abs(n1) < std::abs(n2))
+ bool bOverflow;
+ const auto nResult = o3tl::convert(n1, eFrom, eTo, bOverflow);
+ if (bOverflow)
{
+ const auto& [n2, n3] = o3tl::getConversionMulDiv(eFrom, eTo);
BigInt a4 = n1;
a4 *= n2;
@@ -1483,20 +1460,7 @@ static tools::Long fn3( const tools::Long n1, const tools::Long n2, const tools:
return static_cast<tools::Long>(a4);
} // of if
else
- {
- tools::Long n4 = n1 * n2;
- const tools::Long n3_2 = n3 / 2;
-
- if( n4 < 0 )
- {
- if ((n4 - std::numeric_limits<tools::Long>::min()) >= n3_2)
- n4 -= n3_2;
- }
- else if ((std::numeric_limits<tools::Long>::max() - n4) >= n3_2)
- n4 += n3_2;
-
- return n4 / n3;
- } // of else
+ return nResult;
}
Point OutputDevice::LogicToLogic( const Point& rPtSource,
@@ -1566,10 +1530,8 @@ Point OutputDevice::LogicToLogic( const Point& rPtSource,
if (rMapModeSource.IsSimple() && rMapModeDest.IsSimple())
{
- ENTER3( eUnitSource, eUnitDest );
-
- return Point( fn3( rPtSource.X(), nNumerator, nDenominator ),
- fn3( rPtSource.Y(), nNumerator, nDenominator ) );
+ const auto& [eFrom, eTo] = getCorrectedUnit(eUnitSource, eUnitDest);
+ return Point(fn3(rPtSource.X(), eFrom, eTo), fn3(rPtSource.Y(), eFrom, eTo));
}
else
{
@@ -1599,10 +1561,8 @@ Size OutputDevice::LogicToLogic( const Size& rSzSource,
if (rMapModeSource.IsSimple() && rMapModeDest.IsSimple())
{
- ENTER3( eUnitSource, eUnitDest );
-
- return Size( fn3( rSzSource.Width(), nNumerator, nDenominator ),
- fn3( rSzSource.Height(), nNumerator, nDenominator ) );
+ const auto& [eFrom, eTo] = getCorrectedUnit(eUnitSource, eUnitDest);
+ return Size(fn3(rSzSource.Width(), eFrom, eTo), fn3(rSzSource.Height(), eFrom, eTo));
}
else
{
@@ -1648,9 +1608,10 @@ basegfx::B2DHomMatrix OutputDevice::LogicToLogic(const MapMode& rMapModeSource,
if (rMapModeSource.IsSimple() && rMapModeDest.IsSimple())
{
- ENTER3(eUnitSource, eUnitDest);
-
- const double fScaleFactor(static_cast<double>(nNumerator) / static_cast<double>(nDenominator));
+ const auto& [eFrom, eTo] = getCorrectedUnit(eUnitSource, eUnitDest);
+ const double fScaleFactor(eFrom == o3tl::Length::invalid || eTo == o3tl::Length::invalid
+ ? std::numeric_limits<double>::quiet_NaN()
+ : o3tl::convert(1.0, eFrom, eTo));
aTransform.set(0, 0, fScaleFactor);
aTransform.set(1, 1, fScaleFactor);
}
@@ -1685,15 +1646,15 @@ tools::Rectangle OutputDevice::LogicToLogic( const tools::Rectangle& rRectSource
if (rMapModeSource.IsSimple() && rMapModeDest.IsSimple())
{
- ENTER3( eUnitSource, eUnitDest );
+ const auto& [eFrom, eTo] = getCorrectedUnit(eUnitSource, eUnitDest);
- auto left = fn3( rRectSource.Left(), nNumerator, nDenominator );
- auto top = fn3( rRectSource.Top(), nNumerator, nDenominator );
+ auto left = fn3(rRectSource.Left(), eFrom, eTo);
+ auto top = fn3(rRectSource.Top(), eFrom, eTo);
if (rRectSource.IsEmpty())
return tools::Rectangle( left, top );
- auto right = fn3( rRectSource.Right(), nNumerator, nDenominator );
- auto bottom = fn3( rRectSource.Bottom(), nNumerator, nDenominator );
+ auto right = fn3(rRectSource.Right(), eFrom, eTo);
+ auto bottom = fn3(rRectSource.Bottom(), eFrom, eTo);
return tools::Rectangle(left, top, right, bottom);
}
else
@@ -1730,9 +1691,8 @@ tools::Long OutputDevice::LogicToLogic( tools::Long nLongSource,
return nLongSource;
verifyUnitSourceDest( eUnitSource, eUnitDest );
- ENTER3( eUnitSource, eUnitDest );
-
- return fn3( nLongSource, nNumerator, nDenominator );
+ const auto& [eFrom, eTo] = getCorrectedUnit(eUnitSource, eUnitDest);
+ return fn3(nLongSource, eFrom, eTo);
}
void OutputDevice::SetPixelOffset( const Size& rOffset )