blob: ba79d67062f5d961ab978498cf742879c8cfa46e [file] [log] [blame]
/*
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