/* * Copyright (c) 2012, Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef FractionalLayoutUnit_h #define FractionalLayoutUnit_h #include #include #include #include namespace WebCore { #ifdef NDEBUG #define REPORT_OVERFLOW(doesOverflow) ((void)0) #else #define REPORT_OVERFLOW(doesOverflow) do \ if (!(doesOverflow)) { \ WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, "!(%s)", #doesOverflow); \ } \ while (0) #endif #if ENABLE(SUBPIXEL_LAYOUT) static const int kFixedPointDenominator = 60; #else static const int kFixedPointDenominator = 1; #endif const int intMaxForLayoutUnit = INT_MAX / kFixedPointDenominator; const int intMinForLayoutUnit = -intMaxForLayoutUnit; class FractionalLayoutUnit { 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. FractionalLayoutUnit() : m_value(0) { } FractionalLayoutUnit(int value) { REPORT_OVERFLOW(isInBounds(value)); m_value = value * kFixedPointDenominator; } FractionalLayoutUnit(unsigned short value) { REPORT_OVERFLOW(isInBounds(value)); m_value = value * kFixedPointDenominator; } FractionalLayoutUnit(unsigned int value) { REPORT_OVERFLOW(isInBounds(value)); m_value = value * kFixedPointDenominator; } FractionalLayoutUnit(float value) { REPORT_OVERFLOW(isInBounds(value)); m_value = value * kFixedPointDenominator; } FractionalLayoutUnit(double value) { REPORT_OVERFLOW(isInBounds(value)); m_value = value * kFixedPointDenominator; } FractionalLayoutUnit(const FractionalLayoutUnit& value) { m_value = value.rawValue(); } inline int toInt() const { return m_value / kFixedPointDenominator; } inline unsigned toUnsigned() const { REPORT_OVERFLOW(m_value >= 0); return toInt(); } inline float toFloat() const { return static_cast(m_value) / kFixedPointDenominator; } inline double toDouble() const { return static_cast(m_value) / kFixedPointDenominator; } 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; } inline FractionalLayoutUnit operator++(int) { m_value += kFixedPointDenominator; return *this; } inline int rawValue() const { return m_value; } inline void setRawValue(int value) { m_value = value; } inline void setRawValue(long long value) { REPORT_OVERFLOW(value > std::numeric_limits::min() && value < std::numeric_limits::max()); m_value = static_cast(value); } inline FractionalLayoutUnit abs() const { FractionalLayoutUnit returnValue; returnValue.setRawValue(::abs(m_value)); return returnValue; } #if OS(DARWIN) inline int wtf_ceil() const #else inline int ceil() const #endif { if (m_value > 0) return (m_value + kFixedPointDenominator - 1) / kFixedPointDenominator; return (m_value - kFixedPointDenominator + 1) / kFixedPointDenominator; } inline int round() const { if (m_value > 0) return (m_value + (kFixedPointDenominator / 2)) / kFixedPointDenominator; return (m_value - (kFixedPointDenominator / 2)) / kFixedPointDenominator; } inline int floor() const { return toInt(); } static float epsilon() { return 1 / kFixedPointDenominator; } static const FractionalLayoutUnit max() { FractionalLayoutUnit m; m.m_value = std::numeric_limits::max(); return m; } static const FractionalLayoutUnit min() { FractionalLayoutUnit m; m.m_value = std::numeric_limits::min(); return m; } private: inline bool isInBounds(int value) { return ::abs(value) <= std::numeric_limits::max() / kFixedPointDenominator; } inline bool isInBounds(unsigned value) { return value <= static_cast(std::numeric_limits::max()) / kFixedPointDenominator; } inline bool isInBounds(double value) { return ::fabs(value) <= std::numeric_limits::max() / kFixedPointDenominator; } int m_value; }; inline bool operator<=(const FractionalLayoutUnit& a, const FractionalLayoutUnit& b) { return a.rawValue() <= b.rawValue(); } inline bool operator<=(const FractionalLayoutUnit& a, float b) { return a.toFloat() <= b; } inline bool operator<=(const FractionalLayoutUnit& a, int b) { return a <= FractionalLayoutUnit(b); } inline bool operator<=(const float a, const FractionalLayoutUnit& b) { return a <= b.toFloat(); } inline bool operator<=(const int a, const FractionalLayoutUnit& b) { return FractionalLayoutUnit(a) <= b; } inline bool operator>=(const FractionalLayoutUnit& a, const FractionalLayoutUnit& b) { return a.rawValue() >= b.rawValue(); } inline bool operator>=(const FractionalLayoutUnit& a, int b) { return a >= FractionalLayoutUnit(b); } inline bool operator>=(const float a, const FractionalLayoutUnit& b) { return a >= b.toFloat(); } inline bool operator>=(const FractionalLayoutUnit& a, float b) { return a.toFloat() >= b; } inline bool operator>=(const int a, const FractionalLayoutUnit& b) { return FractionalLayoutUnit(a) >= b; } inline bool operator<(const FractionalLayoutUnit& a, const FractionalLayoutUnit& b) { return a.rawValue() < b.rawValue(); } inline bool operator<(const FractionalLayoutUnit& a, int b) { return a < FractionalLayoutUnit(b); } inline bool operator<(const FractionalLayoutUnit& a, float b) { return a.toFloat() < b; } inline bool operator<(const FractionalLayoutUnit& a, double b) { return a.toDouble() < b; } inline bool operator<(const int a, const FractionalLayoutUnit& b) { return FractionalLayoutUnit(a) < b; } inline bool operator<(const float a, const FractionalLayoutUnit& b) { return a < b.toFloat(); } inline bool operator>(const FractionalLayoutUnit& a, const FractionalLayoutUnit& b) { return a.rawValue() > b.rawValue(); } inline bool operator>(const FractionalLayoutUnit& a, double b) { return a.toDouble() > b; } inline bool operator>(const FractionalLayoutUnit& a, float b) { return a.toFloat() > b; } inline bool operator>(const FractionalLayoutUnit& a, int b) { return a > FractionalLayoutUnit(b); } inline bool operator>(const int a, const FractionalLayoutUnit& b) { return FractionalLayoutUnit(a) > b; } inline bool operator>(const float a, const FractionalLayoutUnit& b) { return a > b.toFloat(); } inline bool operator>(const double a, const FractionalLayoutUnit& b) { return a > b.toDouble(); } inline bool operator!=(const FractionalLayoutUnit& a, const FractionalLayoutUnit& b) { return a.rawValue() != b.rawValue(); } inline bool operator!=(const FractionalLayoutUnit& a, float b) { return a != FractionalLayoutUnit(b); } inline bool operator!=(const int a, const FractionalLayoutUnit& b) { return FractionalLayoutUnit(a) != b; } inline bool operator!=(const FractionalLayoutUnit& a, int b) { return a != FractionalLayoutUnit(b); } inline bool operator==(const FractionalLayoutUnit& a, const FractionalLayoutUnit& b) { return a.rawValue() == b.rawValue(); } inline bool operator==(const FractionalLayoutUnit& a, int b) { return a == FractionalLayoutUnit(b); } inline bool operator==(const int a, const FractionalLayoutUnit& b) { return FractionalLayoutUnit(a) == b; } inline bool operator==(const FractionalLayoutUnit& a, float b) { return a.toFloat() == b; } inline bool operator==(const float a, const FractionalLayoutUnit& b) { return a == b.toFloat(); } // For multiplication that's prone to overflow, this bounds it to FractionalLayoutUnit::max() and ::min() inline FractionalLayoutUnit boundedMultiply(const FractionalLayoutUnit& a, const FractionalLayoutUnit& b) { FractionalLayoutUnit returnVal; long long rawVal = static_cast(a.rawValue()) * b.rawValue() / kFixedPointDenominator; if (rawVal > std::numeric_limits::max()) return FractionalLayoutUnit::max(); if (rawVal < std::numeric_limits::min()) return FractionalLayoutUnit::min(); returnVal.setRawValue(rawVal); return returnVal; } inline FractionalLayoutUnit operator*(const FractionalLayoutUnit& a, const FractionalLayoutUnit& b) { FractionalLayoutUnit returnVal; long long rawVal = static_cast(a.rawValue()) * b.rawValue() / kFixedPointDenominator; returnVal.setRawValue(rawVal); return returnVal; } inline double operator*(const FractionalLayoutUnit& a, double b) { return a.toDouble() * b; } inline float operator*(const FractionalLayoutUnit& a, float b) { return a.toFloat() * b; } inline FractionalLayoutUnit operator*(const FractionalLayoutUnit& a, int b) { return a * FractionalLayoutUnit(b); } inline FractionalLayoutUnit operator*(const FractionalLayoutUnit& a, unsigned b) { return a * FractionalLayoutUnit(b); } inline FractionalLayoutUnit operator*(unsigned a, const FractionalLayoutUnit& b) { return FractionalLayoutUnit(a) * b; } inline FractionalLayoutUnit operator*(const int a, const FractionalLayoutUnit& b) { return FractionalLayoutUnit(a) * b; } inline float operator*(const float a, const FractionalLayoutUnit& b) { return a * b.toFloat(); } inline double operator*(const double a, const FractionalLayoutUnit& b) { return a * b.toDouble(); } inline FractionalLayoutUnit operator/(const FractionalLayoutUnit& a, const FractionalLayoutUnit& b) { FractionalLayoutUnit returnVal; long long rawVal = static_cast(kFixedPointDenominator) * a.rawValue() / b.rawValue(); returnVal.setRawValue(rawVal); return returnVal; } inline float operator/(const FractionalLayoutUnit& a, float b) { return a.toFloat() / b; } inline double operator/(const FractionalLayoutUnit& a, double b) { return a.toDouble() / b; } inline FractionalLayoutUnit operator/(const FractionalLayoutUnit& a, int b) { return a / FractionalLayoutUnit(b); } inline FractionalLayoutUnit operator/(const FractionalLayoutUnit& a, unsigned int b) { return a / FractionalLayoutUnit(b); } inline float operator/(const float a, const FractionalLayoutUnit& b) { return a / b.toFloat(); } inline double operator/(const double a, const FractionalLayoutUnit& b) { return a / b.toDouble(); } inline FractionalLayoutUnit operator/(const int a, const FractionalLayoutUnit& b) { return FractionalLayoutUnit(a) / b; } inline FractionalLayoutUnit operator/(unsigned int a, const FractionalLayoutUnit& b) { return FractionalLayoutUnit(a) / b; } inline FractionalLayoutUnit operator+(const FractionalLayoutUnit& a, const FractionalLayoutUnit& b) { FractionalLayoutUnit returnVal; returnVal.setRawValue(a.rawValue() + b.rawValue()); return returnVal; } inline FractionalLayoutUnit operator+(const FractionalLayoutUnit& a, int b) { return a + FractionalLayoutUnit(b); } inline float operator+(const FractionalLayoutUnit& a, float b) { return a.toFloat() + b; } inline double operator+(const FractionalLayoutUnit& a, double b) { return a.toDouble() + b; } inline FractionalLayoutUnit operator+(const int a, const FractionalLayoutUnit& b) { return FractionalLayoutUnit(a) + b; } inline float operator+(const float a, const FractionalLayoutUnit& b) { return a + b.toFloat(); } inline double operator+(const double a, const FractionalLayoutUnit& b) { return a + b.toDouble(); } inline FractionalLayoutUnit operator-(const FractionalLayoutUnit& a, const FractionalLayoutUnit& b) { FractionalLayoutUnit returnVal; returnVal.setRawValue(a.rawValue() - b.rawValue()); return returnVal; } inline FractionalLayoutUnit operator-(const FractionalLayoutUnit& a, int b) { return a - FractionalLayoutUnit(b); } inline FractionalLayoutUnit operator-(const FractionalLayoutUnit& a, unsigned b) { return a - FractionalLayoutUnit(b); } inline float operator-(const FractionalLayoutUnit& a, float b) { return a.toFloat() - b; } inline FractionalLayoutUnit operator-(const int a, const FractionalLayoutUnit& b) { return FractionalLayoutUnit(a) - b; } inline float operator-(const float a, const FractionalLayoutUnit& b) { return a - b.toFloat(); } inline FractionalLayoutUnit operator-(const FractionalLayoutUnit& a) { FractionalLayoutUnit returnVal; returnVal.setRawValue(-a.rawValue()); return returnVal; } inline FractionalLayoutUnit& operator+=(FractionalLayoutUnit& a, const FractionalLayoutUnit& b) { a = a + b; return a; } inline FractionalLayoutUnit& operator+=(FractionalLayoutUnit& a, int b) { a = a + b; return a; } inline float& operator+=(float& a, const FractionalLayoutUnit& b) { a = a + b; return a; } inline FractionalLayoutUnit& operator-=(FractionalLayoutUnit& a, int b) { a = a - b; return a; } inline FractionalLayoutUnit& operator-=(FractionalLayoutUnit& a, const FractionalLayoutUnit& b) { a = a - b; return a; } inline float& operator-=(float& a, const FractionalLayoutUnit& b) { a = a - b; return a; } inline FractionalLayoutUnit& operator*=(FractionalLayoutUnit& a, int b) { a = a * b; return a; } inline FractionalLayoutUnit& operator*=(FractionalLayoutUnit& a, float b) { a = a * b; return a; } inline int snapSizeToPixel(FractionalLayoutUnit size, FractionalLayoutUnit location) { return (location + size).round() - location.round(); } } // namespace WebCore #endif // FractionalLayoutUnit_h