Title: [241192] trunk
Revision
241192
Author
[email protected]
Date
2019-02-08 01:46:36 -0800 (Fri, 08 Feb 2019)

Log Message

clampTo(): do not convert the input to double when dealing with integers
https://bugs.webkit.org/show_bug.cgi?id=194263
<rdar://problem/47692312>

Reviewed by Darin Adler.

Source/WebCore:

Make the calls to clampTo<float>() unambiguous.

* page/FrameView.cpp:
(WebCore::FrameView::computeUpdatedLayoutViewportRect):
* rendering/style/RenderStyle.h:
(WebCore::RenderStyle::setOpacity):
(WebCore::RenderStyle::setShapeImageThreshold):

Source/WTF:

Previously, every use of clampTo() was converting the input to double,
doing the comparison in double, then casting back to whatever type was needed.

In many case, that was very wasteful. WebKit has many cases of clampTo() with
the same type as input/output, or with integer types of different size/sign.

This patch adds a few versions of clampTo() for the common cases seen in WebKit.
In each case, I tried to minimize the amount of conversion needed at runtime.

* wtf/MathExtras.h:
(clampTo):

Tools:

* TestWebKitAPI/Tests/WTF/MathExtras.cpp:
(TestWebKitAPI::testClampFloatingPointToFloatingPoint):
(TestWebKitAPI::testClampFloatingPointToInteger):
(TestWebKitAPI::testClampSameSignIntegers):
(TestWebKitAPI::testClampUnsignedToSigned):
(TestWebKitAPI::testClampSignedToUnsigned):

Modified Paths

Diff

Modified: trunk/Source/WTF/ChangeLog (241191 => 241192)


--- trunk/Source/WTF/ChangeLog	2019-02-08 08:48:35 UTC (rev 241191)
+++ trunk/Source/WTF/ChangeLog	2019-02-08 09:46:36 UTC (rev 241192)
@@ -1,3 +1,23 @@
+2019-02-08  Benjamin Poulain  <[email protected]>
+
+        clampTo(): do not convert the input to double when dealing with integers
+        https://bugs.webkit.org/show_bug.cgi?id=194263
+        <rdar://problem/47692312>
+
+        Reviewed by Darin Adler.
+
+        Previously, every use of clampTo() was converting the input to double,
+        doing the comparison in double, then casting back to whatever type was needed.
+
+        In many case, that was very wasteful. WebKit has many cases of clampTo() with
+        the same type as input/output, or with integer types of different size/sign.
+
+        This patch adds a few versions of clampTo() for the common cases seen in WebKit.
+        In each case, I tried to minimize the amount of conversion needed at runtime.
+
+        * wtf/MathExtras.h:
+        (clampTo):
+
 2019-02-07  Chris Dumez  <[email protected]>
 
         Mark more heap-allocated classes as fast allocated

Modified: trunk/Source/WTF/wtf/MathExtras.h (241191 => 241192)


--- trunk/Source/WTF/wtf/MathExtras.h	2019-02-08 08:48:35 UTC (rev 241191)
+++ trunk/Source/WTF/wtf/MathExtras.h	2019-02-08 09:46:36 UTC (rev 241192)
@@ -123,16 +123,111 @@
 template<> constexpr double defaultMinimumForClamp() { return -std::numeric_limits<double>::max(); }
 template<typename T> constexpr T defaultMaximumForClamp() { return std::numeric_limits<T>::max(); }
 
-template<typename T> inline T clampTo(double value, T min = defaultMinimumForClamp<T>(), T max = defaultMaximumForClamp<T>())
+// Same type in and out.
+template<typename TargetType, typename SourceType>
+typename std::enable_if<std::is_same<TargetType, SourceType>::value, TargetType>::type
+clampTo(SourceType value, TargetType min = defaultMinimumForClamp<TargetType>(), TargetType max = defaultMaximumForClamp<TargetType>())
 {
-    if (value >= static_cast<double>(max))
+    if (value >= max)
         return max;
-    if (value <= static_cast<double>(min))
+    if (value <= min)
         return min;
-    return static_cast<T>(value);
+    return value;
 }
-template<> inline long long int clampTo(double, long long int, long long int); // clampTo does not support long long ints.
 
+// Floating point source.
+template<typename TargetType, typename SourceType>
+typename std::enable_if<!std::is_same<TargetType, SourceType>::value
+    && std::is_floating_point<SourceType>::value
+    && !(std::is_floating_point<TargetType>::value && sizeof(TargetType) > sizeof(SourceType)), TargetType>::type
+clampTo(SourceType value, TargetType min = defaultMinimumForClamp<TargetType>(), TargetType max = defaultMaximumForClamp<TargetType>())
+{
+    if (value >= static_cast<SourceType>(max))
+        return max;
+    if (value <= static_cast<SourceType>(min))
+        return min;
+    return static_cast<TargetType>(value);
+}
+
+template<typename TargetType, typename SourceType>
+typename std::enable_if<!std::is_same<TargetType, SourceType>::value
+    && std::is_floating_point<SourceType>::value
+    && std::is_floating_point<TargetType>::value
+    && (sizeof(TargetType) > sizeof(SourceType)), TargetType>::type
+clampTo(SourceType value, TargetType min = defaultMinimumForClamp<TargetType>(), TargetType max = defaultMaximumForClamp<TargetType>())
+{
+    TargetType convertedValue = static_cast<TargetType>(value);
+    if (convertedValue >= max)
+        return max;
+    if (convertedValue <= min)
+        return min;
+    return convertedValue;
+}
+
+// Source and Target have the same sign and Source is larger or equal to Target
+template<typename TargetType, typename SourceType>
+typename std::enable_if<!std::is_same<TargetType, SourceType>::value
+    && std::numeric_limits<SourceType>::is_integer
+    && std::numeric_limits<TargetType>::is_integer
+    && std::numeric_limits<TargetType>::is_signed == std::numeric_limits<SourceType>::is_signed
+    && sizeof(SourceType) >= sizeof(TargetType), TargetType>::type
+clampTo(SourceType value, TargetType min = defaultMinimumForClamp<TargetType>(), TargetType max = defaultMaximumForClamp<TargetType>())
+{
+    if (value >= static_cast<SourceType>(max))
+        return max;
+    if (value <= static_cast<SourceType>(min))
+        return min;
+    return static_cast<TargetType>(value);
+}
+
+// Clamping a unsigned integer to the max signed value.
+template<typename TargetType, typename SourceType>
+typename std::enable_if<!std::is_same<TargetType, SourceType>::value
+    && std::numeric_limits<SourceType>::is_integer
+    && std::numeric_limits<TargetType>::is_integer
+    && std::numeric_limits<TargetType>::is_signed
+    && !std::numeric_limits<SourceType>::is_signed
+    && sizeof(SourceType) >= sizeof(TargetType), TargetType>::type
+clampTo(SourceType value)
+{
+    TargetType max = std::numeric_limits<TargetType>::max();
+    if (value >= static_cast<SourceType>(max))
+        return max;
+    return static_cast<TargetType>(value);
+}
+
+// Clamping a signed integer into a valid unsigned integer.
+template<typename TargetType, typename SourceType>
+typename std::enable_if<!std::is_same<TargetType, SourceType>::value
+    && std::numeric_limits<SourceType>::is_integer
+    && std::numeric_limits<TargetType>::is_integer
+    && !std::numeric_limits<TargetType>::is_signed
+    && std::numeric_limits<SourceType>::is_signed
+    && sizeof(SourceType) == sizeof(TargetType), TargetType>::type
+clampTo(SourceType value)
+{
+    if (value < 0)
+        return 0;
+    return static_cast<TargetType>(value);
+}
+
+template<typename TargetType, typename SourceType>
+typename std::enable_if<!std::is_same<TargetType, SourceType>::value
+    && std::numeric_limits<SourceType>::is_integer
+    && std::numeric_limits<TargetType>::is_integer
+    && !std::numeric_limits<TargetType>::is_signed
+    && std::numeric_limits<SourceType>::is_signed
+    && (sizeof(SourceType) > sizeof(TargetType)), TargetType>::type
+clampTo(SourceType value)
+{
+    if (value < 0)
+        return 0;
+    TargetType max = std::numeric_limits<TargetType>::max();
+    if (value >= static_cast<SourceType>(max))
+        return max;
+    return static_cast<TargetType>(value);
+}
+
 inline int clampToInteger(double value)
 {
     return clampTo<int>(value);

Modified: trunk/Source/WebCore/ChangeLog (241191 => 241192)


--- trunk/Source/WebCore/ChangeLog	2019-02-08 08:48:35 UTC (rev 241191)
+++ trunk/Source/WebCore/ChangeLog	2019-02-08 09:46:36 UTC (rev 241192)
@@ -1,3 +1,19 @@
+2019-02-08  Benjamin Poulain  <[email protected]>
+
+        clampTo(): do not convert the input to double when dealing with integers
+        https://bugs.webkit.org/show_bug.cgi?id=194263
+        <rdar://problem/47692312>
+
+        Reviewed by Darin Adler.
+
+        Make the calls to clampTo<float>() unambiguous.
+
+        * page/FrameView.cpp:
+        (WebCore::FrameView::computeUpdatedLayoutViewportRect):
+        * rendering/style/RenderStyle.h:
+        (WebCore::RenderStyle::setOpacity):
+        (WebCore::RenderStyle::setShapeImageThreshold):
+
 2019-02-08  Eric Liang  <[email protected]>
 
         When performing AXPress, check to see if the menu list is disabled.

Modified: trunk/Source/WebCore/page/FrameView.cpp (241191 => 241192)


--- trunk/Source/WebCore/page/FrameView.cpp	2019-02-08 08:48:35 UTC (rev 241191)
+++ trunk/Source/WebCore/page/FrameView.cpp	2019-02-08 09:46:36 UTC (rev 241192)
@@ -1530,8 +1530,8 @@
         // The max stable layout viewport origin really depends on the size of the layout viewport itself, so we need to adjust the location of the layout viewport one final time to make sure it does not end up out of bounds of the document.
         // Without this adjustment (and with using the non-constrained unobscuredContentRect's size as the size of the layout viewport) the layout viewport can be pushed past the bounds of the document during rubber-banding, and cannot be pushed
         // back in until the user scrolls back in the other direction.
-        layoutViewportOrigin.setX(clampTo<float>(layoutViewportOrigin.x(), 0, documentRect.width() - layoutViewportRect.width()));
-        layoutViewportOrigin.setY(clampTo<float>(layoutViewportOrigin.y(), 0, documentRect.height() - layoutViewportRect.height()));
+        layoutViewportOrigin.setX(clampTo<float>(layoutViewportOrigin.x().toFloat(), 0, documentRect.width() - layoutViewportRect.width()));
+        layoutViewportOrigin.setY(clampTo<float>(layoutViewportOrigin.y().toFloat(), 0, documentRect.height() - layoutViewportRect.height()));
     }
     layoutViewportRect.setLocation(layoutViewportOrigin);
     

Modified: trunk/Source/WebCore/rendering/style/RenderStyle.h (241191 => 241192)


--- trunk/Source/WebCore/rendering/style/RenderStyle.h	2019-02-08 08:48:35 UTC (rev 241191)
+++ trunk/Source/WebCore/rendering/style/RenderStyle.h	2019-02-08 09:46:36 UTC (rev 241192)
@@ -1055,7 +1055,7 @@
     void setTextStrokeWidth(float w) { SET_VAR(m_rareInheritedData, textStrokeWidth, w); }
     void setTextFillColor(const Color& c) { SET_VAR(m_rareInheritedData, textFillColor, c); }
     void setCaretColor(const Color& c) { SET_VAR(m_rareInheritedData, caretColor, c); }
-    void setOpacity(float f) { float v = clampTo<float>(f, 0, 1); SET_VAR(m_rareNonInheritedData, opacity, v); }
+    void setOpacity(float f) { float v = clampTo<float>(f, 0.f, 1.f); SET_VAR(m_rareNonInheritedData, opacity, v); }
     void setAppearance(ControlPart a) { SET_VAR(m_rareNonInheritedData, appearance, a); }
     // For valid values of box-align see http://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#alignment
     void setBoxAlign(BoxAlignment a) { SET_NESTED_VAR(m_rareNonInheritedData, deprecatedFlexibleBox, align, static_cast<unsigned>(a)); }
@@ -2196,7 +2196,7 @@
 
 inline void RenderStyle::setShapeImageThreshold(float shapeImageThreshold)
 {
-    float clampedShapeImageThreshold = clampTo<float>(shapeImageThreshold, 0, 1);
+    float clampedShapeImageThreshold = clampTo<float>(shapeImageThreshold, 0.f, 1.f);
     SET_VAR(m_rareNonInheritedData, shapeImageThreshold, clampedShapeImageThreshold);
 }
 

Modified: trunk/Tools/ChangeLog (241191 => 241192)


--- trunk/Tools/ChangeLog	2019-02-08 08:48:35 UTC (rev 241191)
+++ trunk/Tools/ChangeLog	2019-02-08 09:46:36 UTC (rev 241192)
@@ -1,3 +1,18 @@
+2019-02-08  Benjamin Poulain  <[email protected]>
+
+        clampTo(): do not convert the input to double when dealing with integers
+        https://bugs.webkit.org/show_bug.cgi?id=194263
+        <rdar://problem/47692312>
+
+        Reviewed by Darin Adler.
+
+        * TestWebKitAPI/Tests/WTF/MathExtras.cpp:
+        (TestWebKitAPI::testClampFloatingPointToFloatingPoint):
+        (TestWebKitAPI::testClampFloatingPointToInteger):
+        (TestWebKitAPI::testClampSameSignIntegers):
+        (TestWebKitAPI::testClampUnsignedToSigned):
+        (TestWebKitAPI::testClampSignedToUnsigned):
+
 2019-02-07  Jonathan Bedard  <[email protected]>
 
         webkitpy: Respect --dedicated-simulators flag

Modified: trunk/Tools/TestWebKitAPI/Tests/WTF/MathExtras.cpp (241191 => 241192)


--- trunk/Tools/TestWebKitAPI/Tests/WTF/MathExtras.cpp	2019-02-08 08:48:35 UTC (rev 241191)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/MathExtras.cpp	2019-02-08 09:46:36 UTC (rev 241192)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2012 Intel Corporation
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -174,6 +175,238 @@
     EXPECT_EQ(clampTo<unsigned>(-1), 0u);
 }
 
+#if !COMPILER(MSVC)
+template<typename TargetType, typename SourceType>
+static void testClampFloatingPointToFloatingPoint()
+{
+    // No clamping.
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(0)), static_cast<TargetType>(0));
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(1)), static_cast<TargetType>(1));
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(1.5)), static_cast<TargetType>(1.5));
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(-1)), static_cast<TargetType>(-1));
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(-1.5)), static_cast<TargetType>(-1.5));
+
+    // Explicit boundaries, clamped or not.
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(-42), static_cast<SourceType>(-42.5)), static_cast<TargetType>(-42));
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(-43), static_cast<SourceType>(-42.5)), static_cast<TargetType>(static_cast<SourceType>(-42.5)));
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(42), static_cast<SourceType>(41), static_cast<SourceType>(42.5)), static_cast<TargetType>(42));
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(43), static_cast<SourceType>(41), static_cast<SourceType>(42.5)), static_cast<TargetType>(static_cast<SourceType>(42.5)));
+
+    // Integer bounds.
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<int32_t>::max()) + 1), static_cast<TargetType>(std::numeric_limits<int32_t>::max()) + 1);
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<int64_t>::max())), static_cast<TargetType>(std::numeric_limits<int64_t>::max()));
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<int32_t>::max()) + 1), static_cast<TargetType>(std::numeric_limits<int32_t>::max()) + 1);
+
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<int32_t>::min())), static_cast<TargetType>(std::numeric_limits<int32_t>::min()));
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<int64_t>::min())), static_cast<TargetType>(std::numeric_limits<int64_t>::min()));
+
+    if (std::is_same<TargetType, double>::value && std::is_same<SourceType, float>::value) {
+        // If the source is float and target is double, the input of those cases has lost bits in float.
+        // In that case, we also round the expectation to float.
+        EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<int32_t>::max())), static_cast<TargetType>(static_cast<SourceType>(std::numeric_limits<int32_t>::max())));
+        EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<int32_t>::min()) - 1), static_cast<TargetType>(static_cast<SourceType>(std::numeric_limits<int32_t>::min()) - 1));
+        EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<int32_t>::min()) - 1), static_cast<TargetType>(static_cast<SourceType>(std::numeric_limits<int32_t>::min()) - 1));
+    } else {
+        EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<int32_t>::max())), static_cast<TargetType>(std::numeric_limits<int32_t>::max()));
+        EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<int32_t>::min()) - 1), static_cast<TargetType>(std::numeric_limits<int32_t>::min()) - 1);
+        EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<int32_t>::min()) - 1), static_cast<TargetType>(std::numeric_limits<int32_t>::min()) - 1);
+    }
+
+    // At the limit.
+    EXPECT_EQ(clampTo<TargetType>(std::numeric_limits<TargetType>::max()), std::numeric_limits<TargetType>::max());
+    EXPECT_EQ(clampTo<TargetType>(-std::numeric_limits<TargetType>::max()), -std::numeric_limits<TargetType>::max());
+
+    // At Epsilon from the limit.
+    TargetType epsilon = std::numeric_limits<TargetType>::epsilon();
+    EXPECT_EQ(clampTo<TargetType>(std::numeric_limits<TargetType>::max() - epsilon), std::numeric_limits<TargetType>::max() - epsilon);
+    EXPECT_EQ(clampTo<TargetType>(-std::numeric_limits<TargetType>::max() + epsilon), -std::numeric_limits<TargetType>::max() + epsilon);
+
+    // Infinity.
+    EXPECT_EQ(clampTo<TargetType>(std::numeric_limits<SourceType>::infinity()), std::numeric_limits<TargetType>::max());
+    EXPECT_EQ(clampTo<TargetType>(-std::numeric_limits<SourceType>::infinity()), -std::numeric_limits<TargetType>::max());
+}
+
+TEST(WTF, clampFloatingPointToFloatingPoint)
+{
+    testClampFloatingPointToFloatingPoint<float, float>();
+    testClampFloatingPointToFloatingPoint<double, double>();
+
+    testClampFloatingPointToFloatingPoint<double, float>();
+    testClampFloatingPointToFloatingPoint<float, double>();
+
+    // Large double into smaller float.
+    EXPECT_EQ(clampTo<float>(static_cast<double>(std::numeric_limits<float>::max())), std::numeric_limits<float>::max());
+    EXPECT_EQ(clampTo<float>(-static_cast<double>(std::numeric_limits<float>::max())), -std::numeric_limits<float>::max());
+    EXPECT_EQ(clampTo<float>(static_cast<double>(std::numeric_limits<float>::max()) + 1), std::numeric_limits<float>::max());
+    EXPECT_EQ(clampTo<float>(-static_cast<double>(std::numeric_limits<float>::max()) - 1), -std::numeric_limits<float>::max());
+    EXPECT_EQ(clampTo<float>(std::numeric_limits<double>::max()), std::numeric_limits<float>::max());
+    EXPECT_EQ(clampTo<float>(-std::numeric_limits<double>::max()), -std::numeric_limits<float>::max());
+
+    float floatEspilon = std::numeric_limits<float>::epsilon();
+    double doubleEspilon = std::numeric_limits<double>::epsilon();
+    EXPECT_EQ(clampTo<float>(static_cast<double>(std::numeric_limits<float>::max()) + doubleEspilon), std::numeric_limits<float>::max());
+    EXPECT_EQ(clampTo<float>(static_cast<double>(std::numeric_limits<float>::max()) - doubleEspilon), std::numeric_limits<float>::max());
+    EXPECT_EQ(clampTo<float>(static_cast<double>(std::numeric_limits<float>::max()) + floatEspilon), std::numeric_limits<float>::max());
+    EXPECT_EQ(clampTo<float>(static_cast<double>(std::numeric_limits<float>::max()) - floatEspilon), std::numeric_limits<float>::max() - floatEspilon);
+}
+#endif // !COMPILER(MSVC)
+
+template<typename FloatingPointType>
+static void testClampFloatingPointToInteger()
+{
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(0)), 0);
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(1)), 1);
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(-1)), -1);
+    if (std::is_same<FloatingPointType, double>::value)
+        EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<int32_t>::max()) - 1.f), std::numeric_limits<int32_t>::max() - 1);
+    else
+        EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<int32_t>::max()) - 1.f), std::numeric_limits<int32_t>::max());
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<int32_t>::max())), std::numeric_limits<int32_t>::max());
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<int32_t>::max()) + 1.f), std::numeric_limits<int32_t>::max());
+
+    if (std::is_same<FloatingPointType, double>::value)
+        EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<int32_t>::min()) + 1.f), std::numeric_limits<int32_t>::min() + 1);
+    else
+        EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<int32_t>::min()) + 1.f), std::numeric_limits<int32_t>::min());
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<int32_t>::min())), std::numeric_limits<int32_t>::min());
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<int32_t>::min()) - 1.f), std::numeric_limits<int32_t>::min());
+
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<uint32_t>::max())), std::numeric_limits<int32_t>::max());
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<uint32_t>::max()) + 1.f), std::numeric_limits<int32_t>::max());
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<uint32_t>::min())), 0.f);
+
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<int64_t>::max())), std::numeric_limits<int32_t>::max());
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<int64_t>::max()) + 1.f), std::numeric_limits<int32_t>::max());
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<int64_t>::min())), std::numeric_limits<int32_t>::min());
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<int64_t>::min()) - 1.f), std::numeric_limits<int32_t>::min());
+
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<uint64_t>::max())), std::numeric_limits<int32_t>::max());
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<uint64_t>::max()) + 1.f), std::numeric_limits<int32_t>::max());
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<uint64_t>::min())), 0.f);
+
+    FloatingPointType epsilon = std::numeric_limits<FloatingPointType>::epsilon();
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<int32_t>::max()) - epsilon), std::numeric_limits<int32_t>::max());
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<int32_t>::max()) + epsilon), std::numeric_limits<int32_t>::max());
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<int32_t>::min()) - epsilon), std::numeric_limits<int32_t>::min());
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<int32_t>::min()) + epsilon), std::numeric_limits<int32_t>::min());
+
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(std::numeric_limits<FloatingPointType>::infinity())), std::numeric_limits<int32_t>::max());
+    EXPECT_EQ(clampTo<int32_t>(static_cast<FloatingPointType>(-std::numeric_limits<FloatingPointType>::infinity())), std::numeric_limits<int32_t>::min());
+}
+
+TEST(WTF, clampFloatToInt)
+{
+    testClampFloatingPointToInteger<float>();
+    testClampFloatingPointToInteger<double>();
+
+    // 2**24 = 16777216, the largest integer representable exactly as float.
+    EXPECT_EQ(clampTo<int32_t>(static_cast<float>(16777215)), 16777215);
+    EXPECT_EQ(clampTo<int32_t>(static_cast<float>(16777216)), 16777216);
+    EXPECT_EQ(clampTo<int32_t>(static_cast<float>(16777217)), 16777216);
+    EXPECT_EQ(clampTo<int32_t>(static_cast<double>(16777216)), 16777216);
+    EXPECT_EQ(clampTo<int32_t>(static_cast<double>(16777217)), 16777217);
+
+    EXPECT_EQ(clampTo<int16_t>(static_cast<float>(16777215)), std::numeric_limits<int16_t>::max());
+    EXPECT_EQ(clampTo<int16_t>(static_cast<float>(16777216)), std::numeric_limits<int16_t>::max());
+    EXPECT_EQ(clampTo<int16_t>(static_cast<float>(16777217)), std::numeric_limits<int16_t>::max());
+
+    // 2**53 = 9007199254740992, the largest integer representable exactly as double.
+    EXPECT_EQ(clampTo<uint64_t>(static_cast<double>(9007199254740991)), static_cast<uint64_t>(9007199254740991));
+    EXPECT_EQ(clampTo<uint64_t>(static_cast<double>(9007199254740992)), static_cast<uint64_t>(9007199254740992));
+    EXPECT_EQ(clampTo<uint64_t>(static_cast<double>(9007199254740993)), static_cast<uint64_t>(9007199254740992));
+
+    EXPECT_EQ(clampTo<int32_t>(static_cast<double>(9007199254740991)), std::numeric_limits<int32_t>::max());
+    EXPECT_EQ(clampTo<int32_t>(static_cast<double>(9007199254740992)), std::numeric_limits<int32_t>::max());
+    EXPECT_EQ(clampTo<int32_t>(static_cast<double>(9007199254740993)), std::numeric_limits<int32_t>::max());
+}
+
+template<typename TargetType, typename SourceType>
+static void testClampSameSignIntegers()
+{
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(0)), static_cast<TargetType>(0));
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(1)), static_cast<TargetType>(1));
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(-1)), std::numeric_limits<TargetType>::is_signed ? static_cast<TargetType>(-1) : std::numeric_limits<TargetType>::max());
+
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<TargetType>::min())), std::numeric_limits<TargetType>::min());
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<TargetType>::max())), std::numeric_limits<TargetType>::max());
+
+    EXPECT_EQ(clampTo<TargetType>(std::numeric_limits<SourceType>::min()), std::numeric_limits<TargetType>::min());
+    EXPECT_EQ(clampTo<TargetType>(std::numeric_limits<SourceType>::max()), std::numeric_limits<TargetType>::max());
+}
+
+TEST(WTF, clampSameSignIntegers)
+{
+    testClampSameSignIntegers<char, char>();
+    testClampSameSignIntegers<unsigned char, unsigned char>();
+    testClampSameSignIntegers<char, int32_t>();
+    testClampSameSignIntegers<unsigned char, uint32_t>();
+    testClampSameSignIntegers<char, int64_t>();
+    testClampSameSignIntegers<unsigned char, uint64_t>();
+
+    testClampSameSignIntegers<int32_t, int32_t>();
+    testClampSameSignIntegers<uint32_t, uint32_t>();
+    testClampSameSignIntegers<int32_t, int64_t>();
+    testClampSameSignIntegers<uint32_t, uint64_t>();
+    testClampSameSignIntegers<int16_t, int64_t>();
+    testClampSameSignIntegers<uint16_t, uint64_t>();
+}
+
+template<typename TargetType, typename SourceType>
+static void testClampUnsignedToSigned()
+{
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(0)), static_cast<TargetType>(0));
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(1)), static_cast<TargetType>(1));
+
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<TargetType>::max()) - 1), std::numeric_limits<TargetType>::max() - 1);
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<TargetType>::max())), std::numeric_limits<TargetType>::max());
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<TargetType>::max()) + 1), std::numeric_limits<TargetType>::max());
+    EXPECT_EQ(clampTo<TargetType>(std::numeric_limits<SourceType>::max()), std::numeric_limits<TargetType>::max());
+    EXPECT_EQ(clampTo<TargetType>(std::numeric_limits<SourceType>::max() - 1), std::numeric_limits<TargetType>::max());
+}
+
+TEST(WTF, clampUnsignedToSigned)
+{
+    testClampUnsignedToSigned<char, unsigned char>();
+    testClampUnsignedToSigned<char, uint32_t>();
+    testClampUnsignedToSigned<int32_t, uint32_t>();
+    testClampUnsignedToSigned<int64_t, uint64_t>();
+    testClampUnsignedToSigned<int32_t, uint64_t>();
+    testClampUnsignedToSigned<int16_t, uint32_t>();
+    testClampUnsignedToSigned<int16_t, uint64_t>();
+}
+
+template<typename TargetType, typename SourceType>
+static void testClampSignedToUnsigned()
+{
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(0)), static_cast<TargetType>(0));
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(1)), static_cast<TargetType>(1));
+    EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(-1)), static_cast<TargetType>(0));
+
+    if (sizeof(TargetType) < sizeof(SourceType)) {
+        EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<TargetType>::min())), static_cast<TargetType>(0));
+        EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<TargetType>::max()) - 1), std::numeric_limits<TargetType>::max() - 1);
+        EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<TargetType>::max())), std::numeric_limits<TargetType>::max());
+        EXPECT_EQ(clampTo<TargetType>(static_cast<SourceType>(std::numeric_limits<TargetType>::max()) + 1), std::numeric_limits<TargetType>::max());
+    }
+
+    EXPECT_EQ(clampTo<TargetType>(std::numeric_limits<SourceType>::min()), static_cast<TargetType>(0));
+    if (sizeof(TargetType) < sizeof(SourceType))
+        EXPECT_EQ(clampTo<TargetType>(std::numeric_limits<SourceType>::max()), std::numeric_limits<TargetType>::max());
+    else
+        EXPECT_EQ(clampTo<TargetType>(std::numeric_limits<SourceType>::max()), static_cast<TargetType>(std::numeric_limits<SourceType>::max()));
+}
+
+TEST(WTF, clampSignedToUnsigned)
+{
+    testClampSignedToUnsigned<unsigned char, char>();
+    testClampSignedToUnsigned<unsigned char, int32_t>();
+    testClampSignedToUnsigned<uint32_t, int32_t>();
+    testClampSignedToUnsigned<uint64_t, int64_t>();
+    testClampSignedToUnsigned<uint32_t, int64_t>();
+    testClampSignedToUnsigned<uint16_t, int32_t>();
+    testClampSignedToUnsigned<uint16_t, int64_t>();
+}
+
 TEST(WTF, roundUpToPowerOfTwo)
 {
     EXPECT_EQ(WTF::roundUpToPowerOfTwo(UINT32_MAX), 0U);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to