Web Automation: elements larger than the viewport have incorrect in-view center point
[WebKit-https.git] / Source / WebCore / platform / LayoutUnit.h
index a83e95c..8e605ed 100644 (file)
@@ -28,8 +28,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef LayoutUnit_h
-#define LayoutUnit_h
+#pragma once
 
 #include <limits.h>
 #include <limits>
 #include <stdlib.h>
 #include <wtf/MathExtras.h>
 #include <wtf/SaturatedArithmetic.h>
+#include <wtf/text/ValueToString.h>
+
+namespace WTF {
+class TextStream;
+}
 
 namespace WebCore {
 
@@ -54,120 +58,65 @@ while (0)
 
 #endif
 
-#if ENABLE(SUBPIXEL_LAYOUT)
 static const int kFixedPointDenominator = 64;
-#else
-static const int kFixedPointDenominator = 1;
-#endif
 const int intMaxForLayoutUnit = INT_MAX / kFixedPointDenominator;
 const int intMinForLayoutUnit = INT_MIN / kFixedPointDenominator;
 
 class LayoutUnit {
 public:
-    // FIXME: Ideally we would have size_t versions of the constructor and operators.
-    // However due to compiler and platform differences adding those are non-trivial.
-    // See https://bugs.webkit.org/show_bug.cgi?id=83848 for details.
-    
     LayoutUnit() : m_value(0) { }
-#if ENABLE(SUBPIXEL_LAYOUT)
     LayoutUnit(int value) { setValue(value); }
     LayoutUnit(unsigned short value) { setValue(value); }
     LayoutUnit(unsigned value) { setValue(value); }
+    LayoutUnit(unsigned long value)
+    {
+        m_value = clampTo<int>(value * kFixedPointDenominator);
+    }
+    LayoutUnit(unsigned long long value)
+    {
+        m_value = clampTo<int>(value * kFixedPointDenominator);
+    }
     LayoutUnit(float value)
     {
-#if ENABLE(SATURATED_LAYOUT_ARITHMETIC)
-        m_value = clampTo<float>(value * kFixedPointDenominator, static_cast<float>(INT_MIN), static_cast<float>(INT_MAX));
-#else
-        REPORT_OVERFLOW(isInBounds(value));
-        m_value = value * kFixedPointDenominator;
-#endif
+        m_value = clampToInteger(value * kFixedPointDenominator);
     }
     LayoutUnit(double value)
     {
-#if ENABLE(SATURATED_LAYOUT_ARITHMETIC)
-        m_value = clampTo<double>(value * kFixedPointDenominator, static_cast<double>(INT_MIN), static_cast<double>(INT_MAX));
-#else
-        REPORT_OVERFLOW(isInBounds(value));
-        m_value = value * kFixedPointDenominator;
-#endif
+        m_value = clampToInteger(value * kFixedPointDenominator);
     }
-#else
-    LayoutUnit(int value) { REPORT_OVERFLOW(isInBounds(value)); m_value = value; }
-    LayoutUnit(unsigned short value) { REPORT_OVERFLOW(isInBounds(value)); m_value = value; }
-    LayoutUnit(unsigned value) { REPORT_OVERFLOW(isInBounds(value)); m_value = value; }
-    LayoutUnit(float value) { REPORT_OVERFLOW(isInBounds(value)); m_value = value; }
-    LayoutUnit(double value) { REPORT_OVERFLOW(isInBounds(value)); m_value = value; }
-#endif
-    LayoutUnit(const LayoutUnit& value) { m_value = value.rawValue(); }
 
     static LayoutUnit fromFloatCeil(float value)
     {
         LayoutUnit v;
-#if ENABLE(SATURATED_LAYOUT_ARITHMETIC)
         v.m_value = clampToInteger(ceilf(value * kFixedPointDenominator));
-#else
-        REPORT_OVERFLOW(isInBounds(value));
-        v.m_value = ceilf(value * kFixedPointDenominator);
-#endif
         return v;
     }
 
     static LayoutUnit fromFloatFloor(float value)
     {
         LayoutUnit v;
-#if ENABLE(SATURATED_LAYOUT_ARITHMETIC)
         v.m_value = clampToInteger(floorf(value * kFixedPointDenominator));
-#else
-        REPORT_OVERFLOW(isInBounds(value));
-        v.m_value = floorf(value * kFixedPointDenominator);
-#endif
         return v;
     }
 
     static LayoutUnit fromFloatRound(float value)
     {
-#if ENABLE(SATURATED_LAYOUT_ARITHMETIC)
         if (value >= 0)
             return clamp(value + epsilon() / 2.0f);
         return clamp(value - epsilon() / 2.0f);
-#else
-        if (value >= 0) {
-            REPORT_OVERFLOW(isInBounds(value + epsilon() / 2.0f));
-            return LayoutUnit(value + epsilon() / 2.0f);
-        }
-        REPORT_OVERFLOW(isInBounds(value - epsilon() / 2.0f));
-        return LayoutUnit(value - epsilon() / 2.0f);
-#endif
     }
 
-#if ENABLE(SUBPIXEL_LAYOUT)
     int toInt() const { return m_value / kFixedPointDenominator; }
     float toFloat() const { return static_cast<float>(m_value) / kFixedPointDenominator; }
     double toDouble() const { return static_cast<double>(m_value) / kFixedPointDenominator; }
-    float ceilToFloat() const
-    {
-        float floatValue = toFloat();
-        if (static_cast<int>(floatValue * kFixedPointDenominator) == m_value)
-            return floatValue;
-        if (floatValue > 0)
-            return nextafterf(floatValue, std::numeric_limits<float>::max());
-        return nextafterf(floatValue, std::numeric_limits<float>::min());
-    }
-#else
-    int toInt() const { return m_value; }
-    float toFloat() const { return static_cast<float>(m_value); }
-    double toDouble() const { return static_cast<double>(m_value); }
-    float ceilToFloat() const { return toFloat(); }
-#endif
     unsigned toUnsigned() const { REPORT_OVERFLOW(m_value >= 0); return toInt(); }
 
     operator int() const { return toInt(); }
-    operator unsigned() const { return toUnsigned(); }
     operator float() const { return toFloat(); }
     operator double() const { return toDouble(); }
-    operator bool() const { return m_value; }
+    explicit operator bool() const { return m_value; }
 
-    LayoutUnit operator++(int)
+    LayoutUnit& operator++()
     {
         m_value += kFixedPointDenominator;
         return *this;
@@ -187,44 +136,39 @@ public:
         returnValue.setRawValue(::abs(m_value));
         return returnValue;
     }
-#if OS(DARWIN)
-    int wtf_ceil() const
-#else
     int ceil() const
-#endif
     {
-#if ENABLE(SUBPIXEL_LAYOUT)
+        if (UNLIKELY(m_value >= INT_MAX - kFixedPointDenominator + 1))
+            return intMaxForLayoutUnit;
         if (m_value >= 0)
             return (m_value + kFixedPointDenominator - 1) / kFixedPointDenominator;
         return toInt();
-#else
-        return m_value;
-#endif
     }
+
     int round() const
     {
-#if ENABLE(SUBPIXEL_LAYOUT) && ENABLE(SATURATED_LAYOUT_ARITHMETIC)
         if (m_value > 0)
             return saturatedAddition(rawValue(), kFixedPointDenominator / 2) / kFixedPointDenominator;
-        return saturatedSubtraction(rawValue(), kFixedPointDenominator / 2) / kFixedPointDenominator;
-#elif ENABLE(SUBPIXEL_LAYOUT)
-        if (m_value > 0)
-            return (m_value + (kFixedPointDenominator / 2)) / kFixedPointDenominator;
-        return (m_value - (kFixedPointDenominator / 2)) / kFixedPointDenominator;
-#else
-        return m_value;
-#endif
+        return saturatedSubtraction(rawValue(), (kFixedPointDenominator / 2) - 1) / kFixedPointDenominator;
     }
 
     int floor() const
     {
-#if ENABLE(SUBPIXEL_LAYOUT)
+        if (UNLIKELY(m_value <= INT_MIN + kFixedPointDenominator - 1))
+            return intMinForLayoutUnit;
         if (m_value >= 0)
             return toInt();
         return (m_value - kFixedPointDenominator + 1) / kFixedPointDenominator;
-#else
-        return m_value;
-#endif
+    }
+
+    float ceilToFloat() const
+    {
+        float floatValue = toFloat();
+        if (static_cast<int>(floatValue * kFixedPointDenominator) == m_value)
+            return floatValue;
+        if (floatValue > 0)
+            return nextafterf(floatValue, std::numeric_limits<float>::max());
+        return nextafterf(floatValue, std::numeric_limits<float>::min());
     }
 
     LayoutUnit fraction() const
@@ -236,11 +180,14 @@ public:
         return fraction;
     }
 
-#if ENABLE(SUBPIXEL_LAYOUT)
+    bool mightBeSaturated() const
+    {
+        return rawValue() == std::numeric_limits<int>::max()
+            || rawValue() == std::numeric_limits<int>::min();
+    }
+
     static float epsilon() { return 1.0f / kFixedPointDenominator; }
-#else
-    static int epsilon() { return 0; }
-#endif
+
     static const LayoutUnit max()
     {
         LayoutUnit m;
@@ -286,32 +233,22 @@ private:
     {
         return ::fabs(value) <= std::numeric_limits<int>::max() / kFixedPointDenominator;
     }
-    
+
     inline void setValue(int value)
     {
-#if ENABLE(SATURATED_LAYOUT_ARITHMETIC)
         if (value > intMaxForLayoutUnit)
             m_value = std::numeric_limits<int>::max();
         else if (value < intMinForLayoutUnit)
             m_value = std::numeric_limits<int>::min();
         else
             m_value = value * kFixedPointDenominator;
-#else
-        REPORT_OVERFLOW(isInBounds(value));
-        m_value = value * kFixedPointDenominator;
-#endif
     }
     inline void setValue(unsigned value)
     {
-#if ENABLE(SATURATED_LAYOUT_ARITHMETIC)
         if (value >= static_cast<unsigned>(intMaxForLayoutUnit))
             m_value = std::numeric_limits<int>::max();
         else
             m_value = value * kFixedPointDenominator;
-#else
-        REPORT_OVERFLOW(isInBounds(value));
-        m_value = value * kFixedPointDenominator;
-#endif
     }
 
     int m_value;
@@ -480,33 +417,23 @@ inline bool operator==(const float a, const LayoutUnit& b)
 // For multiplication that's prone to overflow, this bounds it to LayoutUnit::max() and ::min()
 inline LayoutUnit boundedMultiply(const LayoutUnit& a, const LayoutUnit& b)
 {
-#if ENABLE(SUBPIXEL_LAYOUT)
+    int64_t result = static_cast<int64_t>(a.rawValue()) * static_cast<int64_t>(b.rawValue()) / kFixedPointDenominator;
+    int32_t high = static_cast<int32_t>(result >> 32);
+    int32_t low = static_cast<int32_t>(result);
+    uint32_t saturated = (static_cast<uint32_t>(a.rawValue() ^ b.rawValue()) >> 31) + std::numeric_limits<int>::max();
+    // If the higher 32 bits does not match the lower 32 with sign extension the operation overflowed.
+    if (high != low >> 31)
+        result = saturated;
+
     LayoutUnit returnVal;
-    long long rawVal = static_cast<long long>(a.rawValue()) * b.rawValue() / kFixedPointDenominator;
-    if (rawVal > std::numeric_limits<int>::max())
-        return LayoutUnit::max();
-    if (rawVal < std::numeric_limits<int>::min())
-        return LayoutUnit::min();
-    returnVal.setRawValue(rawVal);
+    returnVal.setRawValue(static_cast<int>(result));
     return returnVal;
-#else
-    return a.rawValue() * b.rawValue();
-#endif
 }
 
 inline LayoutUnit operator*(const LayoutUnit& a, const LayoutUnit& b)
 {
-#if ENABLE(SUBPIXEL_LAYOUT) && ENABLE(SATURATED_LAYOUT_ARITHMETIC)
     return boundedMultiply(a, b);
-#elif ENABLE(SUBPIXEL_LAYOUT)
-    LayoutUnit returnVal;
-    long long rawVal = static_cast<long long>(a.rawValue()) * b.rawValue() / kFixedPointDenominator;
-    returnVal.setRawValue(rawVal);
-    return returnVal;
-#else
-    return a.rawValue() * b.rawValue();
-#endif
-}    
+}
 
 inline double operator*(const LayoutUnit& a, double b)
 {
@@ -523,16 +450,46 @@ inline LayoutUnit operator*(const LayoutUnit& a, int b)
     return a * LayoutUnit(b);
 }
 
+inline LayoutUnit operator*(const LayoutUnit& a, unsigned short b)
+{
+    return a * LayoutUnit(b);
+}
+
 inline LayoutUnit operator*(const LayoutUnit& a, unsigned b)
 {
     return a * LayoutUnit(b);
 }
 
+inline LayoutUnit operator*(const LayoutUnit& a, unsigned long b)
+{
+    return a * LayoutUnit(b);
+}
+
+inline LayoutUnit operator*(const LayoutUnit& a, unsigned long long b)
+{
+    return a * LayoutUnit(b);
+}
+
+inline LayoutUnit operator*(unsigned short a, const LayoutUnit& b)
+{
+    return LayoutUnit(a) * b;
+}
+
 inline LayoutUnit operator*(unsigned a, const LayoutUnit& b)
 {
     return LayoutUnit(a) * b;
 }
 
+inline LayoutUnit operator*(unsigned long a, const LayoutUnit& b)
+{
+    return LayoutUnit(a) * b;
+}
+
+inline LayoutUnit operator*(unsigned long long a, const LayoutUnit& b)
+{
+    return LayoutUnit(a) * b;
+}
+
 inline LayoutUnit operator*(const int a, const LayoutUnit& b)
 {
     return LayoutUnit(a) * b;
@@ -550,15 +507,11 @@ inline double operator*(const double a, const LayoutUnit& b)
 
 inline LayoutUnit operator/(const LayoutUnit& a, const LayoutUnit& b)
 {
-#if ENABLE(SUBPIXEL_LAYOUT)
     LayoutUnit returnVal;
     long long rawVal = static_cast<long long>(kFixedPointDenominator) * a.rawValue() / b.rawValue();
-    returnVal.setRawValue(rawVal);
+    returnVal.setRawValue(clampTo<int>(rawVal));
     return returnVal;
-#else
-    return a.rawValue() / b.rawValue();
-#endif
-}    
+}
 
 inline float operator/(const LayoutUnit& a, float b)
 {
@@ -575,11 +528,26 @@ inline LayoutUnit operator/(const LayoutUnit& a, int b)
     return a / LayoutUnit(b);
 }
 
+inline LayoutUnit operator/(const LayoutUnit& a, unsigned short b)
+{
+    return a / LayoutUnit(b);
+}
+
 inline LayoutUnit operator/(const LayoutUnit& a, unsigned b)
 {
     return a / LayoutUnit(b);
 }
 
+inline LayoutUnit operator/(const LayoutUnit& a, unsigned long b)
+{
+    return a / LayoutUnit(b);
+}
+
+inline LayoutUnit operator/(const LayoutUnit& a, unsigned long long b)
+{
+    return a / LayoutUnit(b);
+}
+
 inline float operator/(const float a, const LayoutUnit& b)
 {
     return a / b.toFloat();
@@ -595,19 +563,30 @@ inline LayoutUnit operator/(const int a, const LayoutUnit& b)
     return LayoutUnit(a) / b;
 }
 
+inline LayoutUnit operator/(unsigned short a, const LayoutUnit& b)
+{
+    return LayoutUnit(a) / b;
+}
+
 inline LayoutUnit operator/(unsigned a, const LayoutUnit& b)
 {
     return LayoutUnit(a) / b;
 }
 
+inline LayoutUnit operator/(unsigned long a, const LayoutUnit& b)
+{
+    return LayoutUnit(a) / b;
+}
+
+inline LayoutUnit operator/(unsigned long long a, const LayoutUnit& b)
+{
+    return LayoutUnit(a) / b;
+}
+
 inline LayoutUnit operator+(const LayoutUnit& a, const LayoutUnit& b)
 {
     LayoutUnit returnVal;
-#if ENABLE(SATURATED_LAYOUT_ARITHMETIC)
     returnVal.setRawValue(saturatedAddition(a.rawValue(), b.rawValue()));
-#else
-    returnVal.setRawValue(a.rawValue() + b.rawValue());
-#endif
     return returnVal;
 }
 
@@ -644,11 +623,7 @@ inline double operator+(const double a, const LayoutUnit& b)
 inline LayoutUnit operator-(const LayoutUnit& a, const LayoutUnit& b)
 {
     LayoutUnit returnVal;
-#if ENABLE(SATURATED_LAYOUT_ARITHMETIC)
     returnVal.setRawValue(saturatedSubtraction(a.rawValue(), b.rawValue()));
-#else
-    returnVal.setRawValue(a.rawValue() - b.rawValue());
-#endif
     return returnVal;
 }
 
@@ -687,27 +662,19 @@ inline LayoutUnit operator-(const LayoutUnit& a)
 // For returning the remainder after a division with integer results.
 inline LayoutUnit intMod(const LayoutUnit& a, const LayoutUnit& b)
 {
-#if ENABLE(SUBPIXEL_LAYOUT)
     // This calculates the modulo so that: a = static_cast<int>(a / b) * b + intMod(a, b).
     LayoutUnit returnVal;
     returnVal.setRawValue(a.rawValue() % b.rawValue());
     return returnVal;
-#else
-    return a.rawValue() % b.rawValue();
-#endif
 }
 
 inline LayoutUnit operator%(const LayoutUnit& a, const LayoutUnit& b)
 {
-#if ENABLE(SUBPIXEL_LAYOUT)
     // This calculates the modulo so that: a = (a / b) * b + a % b.
     LayoutUnit returnVal;
     long long rawVal = (static_cast<long long>(kFixedPointDenominator) * a.rawValue()) % b.rawValue();
     returnVal.setRawValue(rawVal / kFixedPointDenominator);
     return returnVal;
-#else
-    return a.rawValue() % b.rawValue();
-#endif
 }
 
 inline LayoutUnit operator%(const LayoutUnit& a, int b)
@@ -722,11 +689,7 @@ inline LayoutUnit operator%(int a, const LayoutUnit& b)
 
 inline LayoutUnit& operator+=(LayoutUnit& a, const LayoutUnit& b)
 {
-#if ENABLE(SATURATED_LAYOUT_ARITHMETIC)
     a.setRawValue(saturatedAddition(a.rawValue(), b.rawValue()));
-#else
-    a = a + b;
-#endif
     return a;
 }
 
@@ -756,11 +719,7 @@ inline LayoutUnit& operator-=(LayoutUnit& a, int b)
 
 inline LayoutUnit& operator-=(LayoutUnit& a, const LayoutUnit& b)
 {
-#if ENABLE(SATURATED_LAYOUT_ARITHMETIC)
     a.setRawValue(saturatedSubtraction(a.rawValue(), b.rawValue()));
-#else
-    a = a - b;
-#endif
     return a;
 }
 
@@ -814,11 +773,7 @@ inline float& operator/=(float& a, const LayoutUnit& b)
     return a;
 }
 
-inline int snapSizeToPixel(LayoutUnit size, LayoutUnit location) 
-{
-    LayoutUnit fraction = location.fraction();
-    return (fraction + size).round() - fraction.round();
-}
+WEBCORE_EXPORT WTF::TextStream& operator<<(WTF::TextStream&, const LayoutUnit&);
 
 inline int roundToInt(LayoutUnit value)
 {
@@ -830,32 +785,35 @@ inline int floorToInt(LayoutUnit value)
     return value.floor();
 }
 
-inline LayoutUnit roundedLayoutUnit(float value)
+inline float roundToDevicePixel(LayoutUnit value, float pixelSnappingFactor, bool needsDirectionalRounding = false)
 {
-#if ENABLE(SUBPIXEL_LAYOUT)
-    return LayoutUnit::fromFloatRound(value);
-#else
-    return static_cast<int>(lroundf(value));
-#endif
+    double valueToRound = value.toDouble();
+    if (needsDirectionalRounding)
+        valueToRound -= LayoutUnit::epsilon() / (2 * kFixedPointDenominator);
+
+    if (valueToRound >= 0)
+        return round(valueToRound * pixelSnappingFactor) / pixelSnappingFactor;
+
+    // This adjusts directional rounding on negative halfway values. It produces the same direction for both negative and positive values.
+    // Instead of rounding negative halfway cases away from zero, we translate them to positive values before rounding.
+    // It helps snapping relative negative coordinates to the same position as if they were positive absolute coordinates.
+    unsigned translateOrigin = -value.rawValue();
+    return (round((valueToRound + translateOrigin) * pixelSnappingFactor) / pixelSnappingFactor) - translateOrigin;
 }
 
-inline LayoutUnit ceiledLayoutUnit(float value)
+inline float floorToDevicePixel(LayoutUnit value, float pixelSnappingFactor)
 {
-#if ENABLE(SUBPIXEL_LAYOUT)
-    return LayoutUnit::fromFloatCeil(value);
-#else
-    return ceilf(value);
-#endif
+    return floorf((value.rawValue() * pixelSnappingFactor) / kFixedPointDenominator) / pixelSnappingFactor;
 }
 
-inline LayoutUnit absoluteValue(const LayoutUnit& value)
+inline float ceilToDevicePixel(LayoutUnit value, float pixelSnappingFactor)
 {
-    return value.abs();
+    return ceilf((value.rawValue() * pixelSnappingFactor) / kFixedPointDenominator) / pixelSnappingFactor;
 }
 
-inline LayoutUnit layoutMod(const LayoutUnit& numerator, const LayoutUnit& denominator)
+inline LayoutUnit absoluteValue(const LayoutUnit& value)
 {
-    return numerator % denominator;
+    return value.abs();
 }
 
 inline bool isIntegerValue(const LayoutUnit value)
@@ -863,6 +821,26 @@ inline bool isIntegerValue(const LayoutUnit value)
     return value.toInt() == value;
 }
 
+inline namespace StringLiterals {
+
+inline LayoutUnit operator"" _lu(unsigned long long value)
+{
+    return LayoutUnit(value);
+}
+
+}
+
 } // namespace WebCore
 
-#endif // LayoutUnit_h
+#ifndef NDEBUG
+
+namespace WTF {
+
+// This structure is used by PODIntervalTree for debugging.
+template<> struct ValueToString<WebCore::LayoutUnit> {
+    static String string(WebCore::LayoutUnit value) { return String::numberToStringFixedPrecision(value.toFloat()); }
+};
+
+} // namespace WTF
+
+#endif