| /* |
| Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| Copyright (C) 2006, 2008, 2014 Apple Inc. All rights reserved. |
| Copyright (C) 2011 Rik Cabanier (cabanier@adobe.com) |
| Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. |
| |
| This library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Library General Public |
| License as published by the Free Software Foundation; either |
| version 2 of the License, or (at your option) any later version. |
| |
| This library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Library General Public License for more details. |
| |
| You should have received a copy of the GNU Library General Public License |
| along with this library; see the file COPYING.LIB. If not, write to |
| the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| Boston, MA 02110-1301, USA. |
| */ |
| |
| #pragma once |
| |
| #include "AnimationUtilities.h" |
| #include <string.h> |
| #include <wtf/Assertions.h> |
| #include <wtf/FastMalloc.h> |
| #include <wtf/Forward.h> |
| #include <wtf/UniqueArray.h> |
| |
| namespace WTF { |
| class TextStream; |
| } |
| |
| namespace WebCore { |
| |
| enum class LengthType : uint8_t { |
| Auto, |
| Relative, |
| Percent, |
| Fixed, |
| Intrinsic, |
| MinIntrinsic, |
| MinContent, |
| MaxContent, |
| FillAvailable, |
| FitContent, |
| Calculated, |
| Undefined |
| }; |
| |
| enum class ValueRange : uint8_t { |
| All, |
| NonNegative |
| }; |
| |
| struct BlendingContext; |
| class CalculationValue; |
| |
| struct Length { |
| WTF_MAKE_FAST_ALLOCATED; |
| public: |
| Length(LengthType = LengthType::Auto); |
| |
| Length(int value, LengthType, bool hasQuirk = false); |
| Length(LayoutUnit value, LengthType, bool hasQuirk = false); |
| Length(float value, LengthType, bool hasQuirk = false); |
| Length(double value, LengthType, bool hasQuirk = false); |
| |
| WEBCORE_EXPORT explicit Length(Ref<CalculationValue>&&); |
| |
| Length(const Length&); |
| Length(Length&&); |
| Length& operator=(const Length&); |
| Length& operator=(Length&&); |
| |
| ~Length(); |
| |
| void setValue(LengthType, int value); |
| void setValue(LengthType, float value); |
| void setValue(LengthType, LayoutUnit value); |
| Length& operator*=(float); |
| |
| bool operator==(const Length&) const; |
| bool operator!=(const Length&) const; |
| |
| float value() const; |
| int intValue() const; |
| float percent() const; |
| CalculationValue& calculationValue() const; |
| |
| LengthType type() const; |
| |
| bool isAuto() const; |
| bool isCalculated() const; |
| bool isFixed() const; |
| bool isMaxContent() const; |
| bool isMinContent() const; |
| bool isPercent() const; |
| bool isRelative() const; |
| bool isUndefined() const; |
| bool isFillAvailable() const; |
| bool isFitContent() const; |
| bool isMinIntrinsic() const; |
| |
| bool hasQuirk() const; |
| void setHasQuirk(bool); |
| |
| // FIXME calc: https://bugs.webkit.org/show_bug.cgi?id=80357. A calculated Length |
| // always contains a percentage, and without a maxValue passed to these functions |
| // it's impossible to determine the sign or zero-ness. The following three functions |
| // act as if all calculated values are positive. |
| bool isZero() const; |
| bool isPositive() const; |
| bool isNegative() const; |
| |
| bool isFloat() const; |
| |
| bool isPercentOrCalculated() const; // Returns true for both Percent and Calculated. |
| |
| bool isIntrinsic() const; |
| bool isIntrinsicOrAuto() const; |
| bool isSpecified() const; |
| bool isSpecifiedOrIntrinsic() const; |
| |
| float nonNanCalculatedValue(float maxValue) const; |
| |
| bool isLegacyIntrinsic() const; |
| |
| private: |
| bool isCalculatedEqual(const Length&) const; |
| |
| void initialize(const Length&); |
| void initialize(Length&&); |
| |
| WEBCORE_EXPORT void ref() const; |
| WEBCORE_EXPORT void deref() const; |
| |
| union { |
| int m_intValue { 0 }; |
| float m_floatValue; |
| unsigned m_calculationValueHandle; |
| }; |
| LengthType m_type; |
| bool m_hasQuirk { false }; |
| bool m_isFloat { false }; |
| }; |
| |
| // Blend two lengths to produce a new length that is in between them. Used for animation. |
| Length blend(const Length& from, const Length& to, const BlendingContext&); |
| Length blend(const Length& from, const Length& to, const BlendingContext&, ValueRange); |
| |
| UniqueArray<Length> newCoordsArray(const String&, int& length); |
| UniqueArray<Length> newLengthArray(const String&, int& length); |
| |
| inline Length::Length(LengthType type) |
| : m_type(type) |
| { |
| ASSERT(type != LengthType::Calculated); |
| } |
| |
| inline Length::Length(int value, LengthType type, bool hasQuirk) |
| : m_intValue(value) |
| , m_type(type) |
| , m_hasQuirk(hasQuirk) |
| { |
| ASSERT(type != LengthType::Calculated); |
| } |
| |
| inline Length::Length(LayoutUnit value, LengthType type, bool hasQuirk) |
| : m_floatValue(value.toFloat()) |
| , m_type(type) |
| , m_hasQuirk(hasQuirk) |
| , m_isFloat(true) |
| { |
| ASSERT(type != LengthType::Calculated); |
| } |
| |
| inline Length::Length(float value, LengthType type, bool hasQuirk) |
| : m_floatValue(value) |
| , m_type(type) |
| , m_hasQuirk(hasQuirk) |
| , m_isFloat(true) |
| { |
| ASSERT(type != LengthType::Calculated); |
| } |
| |
| inline Length::Length(double value, LengthType type, bool hasQuirk) |
| : m_floatValue(static_cast<float>(value)) |
| , m_type(type) |
| , m_hasQuirk(hasQuirk) |
| , m_isFloat(true) |
| { |
| ASSERT(type != LengthType::Calculated); |
| } |
| |
| inline Length::Length(const Length& other) |
| { |
| initialize(other); |
| } |
| |
| inline Length::Length(Length&& other) |
| { |
| initialize(WTFMove(other)); |
| } |
| |
| inline Length& Length::operator=(const Length& other) |
| { |
| if (this == &other) |
| return *this; |
| |
| if (isCalculated()) |
| deref(); |
| |
| initialize(other); |
| return *this; |
| } |
| |
| inline Length& Length::operator=(Length&& other) |
| { |
| if (this == &other) |
| return *this; |
| |
| if (isCalculated()) |
| deref(); |
| |
| initialize(WTFMove(other)); |
| return *this; |
| } |
| |
| inline void Length::initialize(const Length& other) |
| { |
| m_type = other.m_type; |
| m_hasQuirk = other.m_hasQuirk; |
| |
| switch (m_type) { |
| case LengthType::Auto: |
| case LengthType::Undefined: |
| m_intValue = 0; |
| break; |
| case LengthType::Fixed: |
| case LengthType::Relative: |
| case LengthType::Intrinsic: |
| case LengthType::MinIntrinsic: |
| case LengthType::MinContent: |
| case LengthType::MaxContent: |
| case LengthType::FillAvailable: |
| case LengthType::FitContent: |
| case LengthType::Percent: |
| m_isFloat = other.m_isFloat; |
| if (m_isFloat) |
| m_floatValue = other.m_floatValue; |
| else |
| m_intValue = other.m_intValue; |
| break; |
| case LengthType::Calculated: |
| m_calculationValueHandle = other.m_calculationValueHandle; |
| ref(); |
| break; |
| } |
| } |
| |
| inline void Length::initialize(Length&& other) |
| { |
| m_type = other.m_type; |
| m_hasQuirk = other.m_hasQuirk; |
| |
| switch (m_type) { |
| case LengthType::Auto: |
| case LengthType::Undefined: |
| m_intValue = 0; |
| break; |
| case LengthType::Fixed: |
| case LengthType::Relative: |
| case LengthType::Intrinsic: |
| case LengthType::MinIntrinsic: |
| case LengthType::MinContent: |
| case LengthType::MaxContent: |
| case LengthType::FillAvailable: |
| case LengthType::FitContent: |
| case LengthType::Percent: |
| m_isFloat = other.m_isFloat; |
| if (m_isFloat) |
| m_floatValue = other.m_floatValue; |
| else |
| m_intValue = other.m_intValue; |
| break; |
| case LengthType::Calculated: |
| m_calculationValueHandle = std::exchange(other.m_calculationValueHandle, 0); |
| break; |
| } |
| |
| other.m_type = LengthType::Auto; |
| } |
| |
| inline Length::~Length() |
| { |
| if (isCalculated()) |
| deref(); |
| } |
| |
| inline bool Length::operator==(const Length& other) const |
| { |
| // FIXME: This might be too long to be inline. |
| if (type() != other.type() || hasQuirk() != other.hasQuirk()) |
| return false; |
| if (isUndefined()) |
| return true; |
| if (isCalculated()) |
| return isCalculatedEqual(other); |
| return value() == other.value(); |
| } |
| |
| inline bool Length::operator!=(const Length& other) const |
| { |
| return !(*this == other); |
| } |
| |
| inline Length& Length::operator*=(float value) |
| { |
| ASSERT(!isCalculated()); |
| if (isCalculated()) |
| return *this; |
| |
| if (m_isFloat) |
| m_floatValue *= value; |
| else |
| m_intValue *= value; |
| |
| return *this; |
| } |
| |
| inline float Length::value() const |
| { |
| ASSERT(!isUndefined()); |
| ASSERT(!isCalculated()); |
| return m_isFloat ? m_floatValue : m_intValue; |
| } |
| |
| inline int Length::intValue() const |
| { |
| ASSERT(!isUndefined()); |
| ASSERT(!isCalculated()); |
| // FIXME: Makes no sense to return 0 here but not in the value() function above. |
| if (isCalculated()) |
| return 0; |
| return m_isFloat ? static_cast<int>(m_floatValue) : m_intValue; |
| } |
| |
| inline float Length::percent() const |
| { |
| ASSERT(isPercent()); |
| return value(); |
| } |
| |
| inline LengthType Length::type() const |
| { |
| return static_cast<LengthType>(m_type); |
| } |
| |
| inline bool Length::hasQuirk() const |
| { |
| return m_hasQuirk; |
| } |
| |
| inline bool Length::isFloat() const |
| { |
| return m_isFloat; |
| } |
| |
| inline void Length::setHasQuirk(bool hasQuirk) |
| { |
| m_hasQuirk = hasQuirk; |
| } |
| |
| inline void Length::setValue(LengthType type, int value) |
| { |
| ASSERT(m_type != LengthType::Calculated); |
| ASSERT(type != LengthType::Calculated); |
| m_type = type; |
| m_intValue = value; |
| m_isFloat = false; |
| } |
| |
| inline void Length::setValue(LengthType type, float value) |
| { |
| ASSERT(m_type != LengthType::Calculated); |
| ASSERT(type != LengthType::Calculated); |
| m_type = type; |
| m_floatValue = value; |
| m_isFloat = true; |
| } |
| |
| inline void Length::setValue(LengthType type, LayoutUnit value) |
| { |
| ASSERT(m_type != LengthType::Calculated); |
| ASSERT(type != LengthType::Calculated); |
| m_type = type; |
| m_floatValue = value; |
| m_isFloat = true; |
| } |
| |
| inline bool Length::isAuto() const |
| { |
| return type() == LengthType::Auto; |
| } |
| |
| inline bool Length::isFixed() const |
| { |
| return type() == LengthType::Fixed; |
| } |
| |
| inline bool Length::isMaxContent() const |
| { |
| return type() == LengthType::MaxContent; |
| } |
| |
| inline bool Length::isMinContent() const |
| { |
| return type() == LengthType::MinContent; |
| } |
| |
| inline bool Length::isNegative() const |
| { |
| if (isUndefined() || isCalculated()) |
| return false; |
| return m_isFloat ? (m_floatValue < 0) : (m_intValue < 0); |
| } |
| |
| inline bool Length::isPercent() const |
| { |
| return type() == LengthType::Percent; |
| } |
| |
| inline bool Length::isRelative() const |
| { |
| return type() == LengthType::Relative; |
| } |
| |
| inline bool Length::isUndefined() const |
| { |
| return type() == LengthType::Undefined; |
| } |
| |
| inline bool Length::isPercentOrCalculated() const |
| { |
| return isPercent() || isCalculated(); |
| } |
| |
| inline bool Length::isPositive() const |
| { |
| if (isUndefined()) |
| return false; |
| if (isCalculated()) |
| return true; |
| return m_isFloat ? (m_floatValue > 0) : (m_intValue > 0); |
| } |
| |
| inline bool Length::isZero() const |
| { |
| ASSERT(!isUndefined()); |
| if (isCalculated() || isAuto()) |
| return false; |
| return m_isFloat ? !m_floatValue : !m_intValue; |
| } |
| |
| inline bool Length::isCalculated() const |
| { |
| return type() == LengthType::Calculated; |
| } |
| |
| inline bool Length::isLegacyIntrinsic() const |
| { |
| return type() == LengthType::Intrinsic || type() == LengthType::MinIntrinsic; |
| } |
| |
| inline bool Length::isIntrinsic() const |
| { |
| // FIXME: This is misleadingly named. One would expect this function does "return type() == LengthType::Intrinsic;". |
| return type() == LengthType::MinContent || type() == LengthType::MaxContent || type() == LengthType::FillAvailable || type() == LengthType::FitContent; |
| } |
| |
| inline bool Length::isIntrinsicOrAuto() const |
| { |
| return isAuto() || isIntrinsic() || isLegacyIntrinsic(); |
| } |
| |
| inline bool Length::isSpecified() const |
| { |
| return isFixed() || isPercentOrCalculated(); |
| } |
| |
| inline bool Length::isSpecifiedOrIntrinsic() const |
| { |
| return isSpecified() || isIntrinsic(); |
| } |
| |
| inline bool Length::isFillAvailable() const |
| { |
| return type() == LengthType::FillAvailable; |
| } |
| |
| inline bool Length::isFitContent() const |
| { |
| return type() == LengthType::FitContent; |
| } |
| |
| inline bool Length::isMinIntrinsic() const |
| { |
| return type() == LengthType::MinIntrinsic; |
| } |
| |
| Length convertTo100PercentMinusLength(const Length&); |
| |
| WTF::TextStream& operator<<(WTF::TextStream&, Length); |
| |
| } // namespace WebCore |