1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* 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 <sal/types.h>
#include <cassert>
#include <type_traits>
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);
}
constexpr int actualMul(int m, int d) { return (m % d == 0) ? m / d : (d % m == 0) ? 1 : m; }
constexpr int actualDiv(int m, int d) { return (m % d == 0) ? 1 : (d % m == 0) ? d / m : d; }
// 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)
{
static_assert(mul > 0 && div > 0);
constexpr int m = actualMul(mul, div), d = actualDiv(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;
}
template <int mul, int div, typename F, std::enable_if_t<std::is_floating_point_v<F>, int> = 0>
constexpr double MulDiv(F f)
{
static_assert(mul > 0 && div > 0);
return f * (double(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)
{
constexpr int m = actualMul(mul, div), d = actualDiv(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);
}
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); }
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); }
// 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); }
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|