blob: e8ed23596f649eb8df911f96d51c3eb33359ac3e [file] [log] [blame]
/*
* (C) 1999-2003 Lars Knoll (knoll@kde.org)
* Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
*
* 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 THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_PRIMITIVE_VALUE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_PRIMITIVE_VALUE_H_
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/css/css_value.h"
#include "third_party/blink/renderer/core/css_property_names.h"
#include "third_party/blink/renderer/core/css_value_keywords.h"
#include "third_party/blink/renderer/platform/wtf/bit_vector.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
#include "third_party/blink/renderer/platform/wtf/text/string_view.h"
namespace blink {
class CSSCalcValue;
class CSSToLengthConversionData;
class Length;
// Dimension calculations are imprecise, often resulting in values of e.g.
// 44.99998. We need to go ahead and round if we're really close to the next
// integer value.
template <typename T>
inline T RoundForImpreciseConversion(double value) {
value += (value < 0) ? -0.01 : +0.01;
return ((value > std::numeric_limits<T>::max()) ||
(value < std::numeric_limits<T>::min()))
? 0
: static_cast<T>(value);
}
template <>
inline float RoundForImpreciseConversion(double value) {
double ceiled_value = ceil(value);
double proximity_to_next_int = ceiled_value - value;
if (proximity_to_next_int <= 0.01 && value > 0)
return static_cast<float>(ceiled_value);
if (proximity_to_next_int >= 0.99 && value < 0)
return static_cast<float>(floor(value));
return static_cast<float>(value);
}
// CSSPrimitiveValue stores numeric data types (e.g. 1, 10px, 4%) and calc()
// values (e.g. calc(3px + 2em)).
class CORE_EXPORT CSSPrimitiveValue : public CSSValue {
public:
// These units are iterated through, so be careful when adding or changing the
// order.
enum class UnitType {
kUnknown,
kNumber,
kPercentage,
// Length units
kEms,
kExs,
kPixels,
kCentimeters,
kMillimeters,
kInches,
kPoints,
kPicas,
kQuarterMillimeters,
kViewportWidth,
kViewportHeight,
kViewportMin,
kViewportMax,
kRems,
kChs,
kUserUnits, // The SVG term for unitless lengths
// Angle units
kDegrees,
kRadians,
kGradians,
kTurns,
// Time units
kMilliseconds,
kSeconds,
kHertz,
kKilohertz,
// Resolution
kDotsPerPixel,
kDotsPerInch,
kDotsPerCentimeter,
// Other units
kFraction,
kInteger,
kCalc,
kCalcPercentageWithNumber,
kCalcPercentageWithLength,
kCalcLengthWithNumber,
kCalcPercentageWithLengthAndNumber,
// This value is used to handle quirky margins in reflow roots (body, td,
// and th) like WinIE. The basic idea is that a stylesheet can use the value
// __qem (for quirky em) instead of em. When the quirky value is used, if
// you're in quirks mode, the margin will collapse away inside a table cell.
// This quirk is specified in the HTML spec but our impl is different.
// TODO: Remove this. crbug.com/443952
kQuirkyEms,
};
enum LengthUnitType {
kUnitTypePixels = 0,
kUnitTypePercentage,
kUnitTypeFontSize,
kUnitTypeFontXSize,
kUnitTypeRootFontSize,
kUnitTypeZeroCharacterWidth,
kUnitTypeViewportWidth,
kUnitTypeViewportHeight,
kUnitTypeViewportMin,
kUnitTypeViewportMax,
// This value must come after the last length unit type to enable iteration
// over the length unit types.
kLengthUnitTypeCount,
};
struct CSSLengthArray {
CSSLengthArray() : values(kLengthUnitTypeCount) {
type_flags.Resize(kLengthUnitTypeCount);
}
Vector<double, CSSPrimitiveValue::kLengthUnitTypeCount> values;
BitVector type_flags;
};
void AccumulateLengthArray(CSSLengthArray&, double multiplier = 1) const;
enum UnitCategory {
kUNumber,
kUPercent,
kULength,
kUAngle,
kUTime,
kUFrequency,
kUResolution,
kUOther
};
static UnitCategory UnitTypeToUnitCategory(UnitType);
static float ClampToCSSLengthRange(double);
static bool IsAngle(UnitType unit) {
return unit == UnitType::kDegrees || unit == UnitType::kRadians ||
unit == UnitType::kGradians || unit == UnitType::kTurns;
}
bool IsAngle() const { return IsAngle(TypeWithCalcResolved()); }
bool IsFontRelativeLength() const {
return GetType() == UnitType::kQuirkyEms || GetType() == UnitType::kEms ||
GetType() == UnitType::kExs || GetType() == UnitType::kRems ||
GetType() == UnitType::kChs;
}
bool IsQuirkyEms() const { return GetType() == UnitType::kQuirkyEms; }
bool IsViewportPercentageLength() const {
return IsViewportPercentageLength(GetType());
}
static bool IsViewportPercentageLength(UnitType type) {
return type >= UnitType::kViewportWidth && type <= UnitType::kViewportMax;
}
static bool IsLength(UnitType type) {
return (type >= UnitType::kEms && type <= UnitType::kUserUnits) ||
type == UnitType::kQuirkyEms;
}
static inline bool IsRelativeUnit(UnitType type) {
return type == UnitType::kPercentage || type == UnitType::kEms ||
type == UnitType::kExs || type == UnitType::kRems ||
type == UnitType::kChs || IsViewportPercentageLength(type);
}
bool IsLength() const { return IsLength(TypeWithCalcResolved()); }
bool IsNumber() const {
return TypeWithCalcResolved() == UnitType::kNumber ||
TypeWithCalcResolved() == UnitType::kInteger;
}
bool IsPercentage() const {
return TypeWithCalcResolved() == UnitType::kPercentage;
}
bool IsPx() const { return TypeWithCalcResolved() == UnitType::kPixels; }
static bool IsTime(UnitType unit) {
return unit == UnitType::kSeconds || unit == UnitType::kMilliseconds;
}
bool IsTime() const { return IsTime(TypeWithCalcResolved()); }
static bool IsFrequency(UnitType unit) {
return unit == UnitType::kHertz || unit == UnitType::kKilohertz;
}
bool IsCalculated() const { return GetType() == UnitType::kCalc; }
bool IsCalculatedPercentageWithNumber() const {
return TypeWithCalcResolved() == UnitType::kCalcPercentageWithNumber;
}
bool IsCalculatedPercentageWithLength() const {
return TypeWithCalcResolved() == UnitType::kCalcPercentageWithLength;
}
static bool IsResolution(UnitType type) {
return type >= UnitType::kDotsPerPixel &&
type <= UnitType::kDotsPerCentimeter;
}
bool IsResolution() const { return IsResolution(GetType()); }
static bool IsFlex(UnitType unit) { return unit == UnitType::kFraction; }
bool IsFlex() const { return IsFlex(GetType()); }
static CSSPrimitiveValue* Create(double value, UnitType);
static CSSPrimitiveValue* Create(const Length& value, float zoom) {
return new CSSPrimitiveValue(value, zoom);
}
// TODO(sashab): Remove this.
template <typename T>
static CSSPrimitiveValue* Create(T value) {
return new CSSPrimitiveValue(value);
}
~CSSPrimitiveValue();
UnitType TypeWithCalcResolved() const;
double ComputeDegrees() const;
double ComputeSeconds() const;
double ComputeDotsPerPixel() const;
// Computes a length in pixels, resolving relative lengths
template <typename T>
T ComputeLength(const CSSToLengthConversionData&) const;
// Converts to a Length (Fixed, Percent or Calculated)
Length ConvertToLength(const CSSToLengthConversionData&) const;
double GetDoubleValue() const;
float GetFloatValue() const { return GetValue<float>(); }
int GetIntValue() const { return GetValue<int>(); }
template <typename T>
inline T GetValue() const {
return clampTo<T>(GetDoubleValue());
}
CSSCalcValue* CssCalcValue() const {
DCHECK(IsCalculated());
return value_.calc;
}
template <typename T>
inline T ConvertTo() const; // Defined in CSSPrimitiveValueMappings.h
static const char* UnitTypeToString(UnitType);
static UnitType StringToUnitType(StringView string) {
if (string.Is8Bit())
return StringToUnitType(string.Characters8(), string.length());
return StringToUnitType(string.Characters16(), string.length());
}
String CustomCSSText() const;
bool Equals(const CSSPrimitiveValue&) const;
void TraceAfterDispatch(blink::Visitor*);
static UnitType CanonicalUnitTypeForCategory(UnitCategory);
static double ConversionToCanonicalUnitsScaleFactor(UnitType);
// Returns true and populates lengthUnitType, if unitType is a length unit.
// Otherwise, returns false.
static bool UnitTypeToLengthUnitType(UnitType, LengthUnitType&);
static UnitType LengthUnitTypeToUnitType(LengthUnitType);
private:
CSSPrimitiveValue(const Length&, float zoom);
CSSPrimitiveValue(double, UnitType);
template <typename T>
CSSPrimitiveValue(T); // Defined in CSSPrimitiveValueMappings.h
template <typename T>
CSSPrimitiveValue(T* val) : CSSValue(kPrimitiveClass) {
Init(val);
}
static void Create(int); // compile-time guard
static void Create(unsigned); // compile-time guard
template <typename T>
operator T*(); // compile-time guard
// Code generated by css_primitive_value_unit_trie.cc.tmpl
static UnitType StringToUnitType(const LChar*, unsigned length);
static UnitType StringToUnitType(const UChar*, unsigned length);
void Init(UnitType);
void Init(const Length&);
void Init(CSSCalcValue*);
double ComputeLengthDouble(const CSSToLengthConversionData&) const;
inline UnitType GetType() const {
return static_cast<UnitType>(primitive_unit_type_);
}
union {
double num;
// FIXME: oilpan: Should be a member, but no support for members in unions.
// Just trace the raw ptr for now.
CSSCalcValue* calc;
} value_;
};
using CSSLengthArray = CSSPrimitiveValue::CSSLengthArray;
DEFINE_CSS_VALUE_TYPE_CASTS(CSSPrimitiveValue, IsPrimitiveValue());
template <>
int CSSPrimitiveValue::ComputeLength(const CSSToLengthConversionData&) const;
template <>
Length CSSPrimitiveValue::ComputeLength(const CSSToLengthConversionData&) const;
template <>
unsigned CSSPrimitiveValue::ComputeLength(
const CSSToLengthConversionData&) const;
template <>
short CSSPrimitiveValue::ComputeLength(const CSSToLengthConversionData&) const;
template <>
float CSSPrimitiveValue::ComputeLength(const CSSToLengthConversionData&) const;
template <>
double CSSPrimitiveValue::ComputeLength(const CSSToLengthConversionData&) const;
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_PRIMITIVE_VALUE_H_