blob: f8925568f1bc58fe30123a022a592bb045432149 [file] [log] [blame]
/*
Copyright (C) 1999 Lars Knoll (knoll@kde.org)
Copyright (C) 2006, 2008 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.
*/
#ifndef Length_h
#define Length_h
#include "platform/LayoutUnit.h"
#include "platform/PlatformExport.h"
#include "platform/wtf/Allocator.h"
namespace blink {
// FIXME: This enum makes it hard to tell in general what values may be
// appropriate for any given Length.
enum LengthType {
kAuto,
kPercent,
kFixed,
kMinContent,
kMaxContent,
kFillAvailable,
kFitContent,
kCalculated,
kExtendToZoom,
kDeviceWidth,
kDeviceHeight,
kMaxSizeNone
};
enum ValueRange { kValueRangeAll, kValueRangeNonNegative };
struct PixelsAndPercent {
DISALLOW_NEW();
PixelsAndPercent(float pixels, float percent)
: pixels(pixels), percent(percent) {}
float pixels;
float percent;
};
class CalculationValue;
class PLATFORM_EXPORT Length {
DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
public:
Length() : int_value_(0), quirk_(false), type_(kAuto), is_float_(false) {}
explicit Length(LengthType t)
: int_value_(0), quirk_(false), type_(t), is_float_(false) {
DCHECK_NE(t, kCalculated);
}
Length(int v, LengthType t, bool q = false)
: int_value_(v), quirk_(q), type_(t), is_float_(false) {
DCHECK_NE(t, kCalculated);
}
Length(LayoutUnit v, LengthType t, bool q = false)
: float_value_(v.ToFloat()), quirk_(q), type_(t), is_float_(true) {
DCHECK_NE(t, kCalculated);
}
Length(float v, LengthType t, bool q = false)
: float_value_(v), quirk_(q), type_(t), is_float_(true) {
DCHECK_NE(t, kCalculated);
}
Length(double v, LengthType t, bool q = false)
: quirk_(q), type_(t), is_float_(true) {
float_value_ = static_cast<float>(v);
}
explicit Length(scoped_refptr<CalculationValue>);
Length(const Length& length) {
memcpy(this, &length, sizeof(Length));
if (IsCalculated())
IncrementCalculatedRef();
}
Length& operator=(const Length& length) {
if (length.IsCalculated())
length.IncrementCalculatedRef();
if (IsCalculated())
DecrementCalculatedRef();
memcpy(this, &length, sizeof(Length));
return *this;
}
~Length() {
if (IsCalculated())
DecrementCalculatedRef();
}
bool operator==(const Length& o) const {
return (type_ == o.type_) && (quirk_ == o.quirk_) &&
(IsMaxSizeNone() || (GetFloatValue() == o.GetFloatValue()) ||
IsCalculatedEqual(o));
}
bool operator!=(const Length& o) const { return !(*this == o); }
const Length& operator*=(float v) {
if (IsCalculated()) {
NOTREACHED();
return *this;
}
if (is_float_)
float_value_ = static_cast<float>(float_value_ * v);
else
int_value_ = static_cast<int>(int_value_ * v);
return *this;
}
// FIXME: Make this private (if possible) or at least rename it
// (http://crbug.com/432707).
inline float Value() const {
DCHECK(!IsCalculated());
return GetFloatValue();
}
int IntValue() const {
if (IsCalculated()) {
NOTREACHED();
return 0;
}
return GetIntValue();
}
float Pixels() const {
DCHECK_EQ(GetType(), kFixed);
return GetFloatValue();
}
float Percent() const {
DCHECK_EQ(GetType(), kPercent);
return GetFloatValue();
}
PixelsAndPercent GetPixelsAndPercent() const;
CalculationValue& GetCalculationValue() const;
LengthType GetType() const { return static_cast<LengthType>(type_); }
bool Quirk() const { return quirk_; }
void SetQuirk(bool quirk) { quirk_ = quirk; }
void SetValue(LengthType t, int value) {
type_ = t;
int_value_ = value;
is_float_ = false;
}
void SetValue(int value) {
if (IsCalculated()) {
NOTREACHED();
return;
}
SetValue(kFixed, value);
}
void SetValue(LengthType t, float value) {
type_ = t;
float_value_ = value;
is_float_ = true;
}
void SetValue(LengthType t, LayoutUnit value) {
type_ = t;
float_value_ = value.ToFloat();
is_float_ = true;
}
void SetValue(float value) { *this = Length(value, kFixed); }
bool IsMaxSizeNone() const { return GetType() == kMaxSizeNone; }
// 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. We assume all
// calc values are positive and non-zero for now.
bool IsZero() const {
DCHECK(!IsMaxSizeNone());
if (IsCalculated())
return false;
return is_float_ ? !float_value_ : !int_value_;
}
bool IsPositive() const {
if (IsMaxSizeNone())
return false;
if (IsCalculated())
return true;
return GetFloatValue() > 0;
}
bool IsNegative() const {
if (IsMaxSizeNone() || IsCalculated())
return false;
return GetFloatValue() < 0;
}
bool IsAuto() const { return GetType() == kAuto; }
bool IsFixed() const { return GetType() == kFixed; }
bool IsIntrinsicOrAuto() const { return GetType() == kAuto || IsIntrinsic(); }
bool IsIntrinsic() const {
return GetType() == kMinContent || GetType() == kMaxContent ||
GetType() == kFillAvailable || GetType() == kFitContent;
}
bool IsSpecified() const {
return GetType() == kFixed || GetType() == kPercent ||
GetType() == kCalculated;
}
bool IsSpecifiedOrIntrinsic() const { return IsSpecified() || IsIntrinsic(); }
bool IsCalculated() const { return GetType() == kCalculated; }
bool IsCalculatedEqual(const Length&) const;
bool IsMinContent() const { return GetType() == kMinContent; }
bool IsMaxContent() const { return GetType() == kMaxContent; }
bool IsFillAvailable() const { return GetType() == kFillAvailable; }
bool IsFitContent() const { return GetType() == kFitContent; }
bool IsPercent() const { return GetType() == kPercent; }
bool IsPercentOrCalc() const {
return GetType() == kPercent || GetType() == kCalculated;
}
Length Blend(const Length& from, double progress, ValueRange range) const {
DCHECK(IsSpecified());
DCHECK(from.IsSpecified());
if (progress == 0.0)
return from;
if (progress == 1.0)
return *this;
if (from.GetType() == kCalculated || GetType() == kCalculated)
return BlendMixedTypes(from, progress, range);
if (!from.IsZero() && !IsZero() && from.GetType() != GetType())
return BlendMixedTypes(from, progress, range);
if (from.IsZero() && IsZero())
return *this;
return BlendSameTypes(from, progress, range);
}
float GetFloatValue() const {
DCHECK(!IsMaxSizeNone());
return is_float_ ? float_value_ : int_value_;
}
float NonNanCalculatedValue(LayoutUnit max_value) const;
Length SubtractFromOneHundredPercent() const;
Length Zoom(double factor) const;
private:
int GetIntValue() const {
DCHECK(!IsMaxSizeNone());
return is_float_ ? static_cast<int>(float_value_) : int_value_;
}
Length BlendMixedTypes(const Length& from, double progress, ValueRange) const;
Length BlendSameTypes(const Length& from, double progress, ValueRange) const;
int CalculationHandle() const {
DCHECK(IsCalculated());
return GetIntValue();
}
void IncrementCalculatedRef() const;
void DecrementCalculatedRef() const;
union {
int int_value_;
float float_value_;
};
bool quirk_;
unsigned char type_;
bool is_float_;
};
} // namespace blink
#endif // Length_h