blob: d7f09dfddd207632a66e45771608e08c0c27ad14 [file] [log] [blame] [edit]
/*
* (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 CSSPrimitiveValue_h
#define CSSPrimitiveValue_h
#include "core/CSSPropertyNames.h"
#include "core/CSSValueKeywords.h"
#include "core/CoreExport.h"
#include "core/css/CSSValue.h"
#include "platform/graphics/Color.h"
#include "wtf/BitVector.h"
#include "wtf/Forward.h"
#include "wtf/MathExtras.h"
#include "wtf/PassRefPtr.h"
#include "wtf/text/StringHash.h"
namespace blink {
class CSSBasicShape;
class CSSCalcValue;
class CSSToLengthConversionData;
class Length;
class RGBColor;
class ComputedStyle;
// 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 ceiledValue = ceil(value);
double proximityToNextInt = ceiledValue - value;
if (proximityToNextInt <= 0.01 && value > 0)
return static_cast<float>(ceiledValue);
if (proximityToNextInt >= 0.99 && value < 0)
return static_cast<float>(floor(value));
return static_cast<float>(value);
}
// CSSPrimitiveValues are immutable. This class has manual ref-counting
// of unioned types and does not have the code necessary
// to handle any kind of mutations.
class CORE_EXPORT CSSPrimitiveValue : public CSSValue {
public:
enum class UnitType {
Unknown,
Number,
Percentage,
Ems,
Exs,
Pixels,
Centimeters,
Millimeters,
Inches,
Points,
Picas,
Degrees,
Radians,
Gradians,
Turns,
Milliseconds,
Seconds,
Hertz,
Kilohertz,
CustomIdentifier,
URI,
RGBColor,
ViewportWidth,
ViewportHeight,
ViewportMin,
ViewportMax,
DotsPerPixel,
DotsPerInch,
DotsPerCentimeter,
Fraction,
Integer,
Rems,
Chs,
Shape,
Calc,
CalcPercentageWithNumber,
CalcPercentageWithLength,
String,
PropertyID,
ValueID,
// 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
QuirkyEms,
};
enum LengthUnitType {
UnitTypePixels = 0,
UnitTypePercentage,
UnitTypeFontSize,
UnitTypeFontXSize,
UnitTypeRootFontSize,
UnitTypeZeroCharacterWidth,
UnitTypeViewportWidth,
UnitTypeViewportHeight,
UnitTypeViewportMin,
UnitTypeViewportMax,
// This value must come after the last length unit type to enable iteration over the length unit types.
LengthUnitTypeCount,
};
using CSSLengthArray = Vector<double, CSSPrimitiveValue::LengthUnitTypeCount>;
using CSSLengthTypeArray = BitVector;
void accumulateLengthArray(CSSLengthArray&, double multiplier = 1) const;
void accumulateLengthArray(CSSLengthArray&, CSSLengthTypeArray&, double multiplier = 1) const;
enum UnitCategory {
UNumber,
UPercent,
ULength,
UAngle,
UTime,
UFrequency,
UResolution,
UOther
};
static UnitCategory unitCategory(UnitType);
static float clampToCSSLengthRange(double);
static void initUnitTable();
static UnitType fromName(const String& unit);
bool isAngle() const
{
return type() == UnitType::Degrees
|| type() == UnitType::Radians
|| type() == UnitType::Gradians
|| type() == UnitType::Turns;
}
bool isCustomIdent() const { return type() == UnitType::CustomIdentifier; }
bool isFontRelativeLength() const
{
return type() == UnitType::QuirkyEms
|| type() == UnitType::Ems
|| type() == UnitType::Exs
|| type() == UnitType::Rems
|| type() == UnitType::Chs;
}
bool isQuirkyEms() const { return type() == UnitType::QuirkyEms; }
bool isViewportPercentageLength() const { return isViewportPercentageLength(type()); }
static bool isViewportPercentageLength(UnitType type) { return type >= UnitType::ViewportWidth && type <= UnitType::ViewportMax; }
static bool isLength(UnitType type)
{
return (type >= UnitType::Ems && type <= UnitType::Picas) || type == UnitType::QuirkyEms || type == UnitType::Rems || type == UnitType::Chs || isViewportPercentageLength(type);
}
bool isLength() const { return isLength(typeWithCalcResolved()); }
bool isNumber() const { return typeWithCalcResolved() == UnitType::Number || typeWithCalcResolved() == UnitType::Integer; }
bool isPercentage() const { return typeWithCalcResolved() == UnitType::Percentage; }
bool isPropertyID() const { return type() == UnitType::PropertyID; }
bool isPx() const { return typeWithCalcResolved() == UnitType::Pixels; }
bool isRGBColor() const { return type() == UnitType::RGBColor; }
bool isShape() const { return type() == UnitType::Shape; }
bool isString() const { return type() == UnitType::String; }
bool isTime() const { return type() == UnitType::Seconds || type() == UnitType::Milliseconds; }
bool isURI() const { return type() == UnitType::URI; }
bool isCalculated() const { return type() == UnitType::Calc; }
bool isCalculatedPercentageWithNumber() const { return typeWithCalcResolved() == UnitType::CalcPercentageWithNumber; }
bool isCalculatedPercentageWithLength() const { return typeWithCalcResolved() == UnitType::CalcPercentageWithLength; }
static bool isDotsPerInch(UnitType type) { return type == UnitType::DotsPerInch; }
static bool isDotsPerPixel(UnitType type) { return type == UnitType::DotsPerPixel; }
static bool isDotsPerCentimeter(UnitType type) { return type == UnitType::DotsPerCentimeter; }
static bool isResolution(UnitType type) { return type >= UnitType::DotsPerPixel && type <= UnitType::DotsPerCentimeter; }
bool isFlex() const { return typeWithCalcResolved() == UnitType::Fraction; }
bool isValueID() const { return type() == UnitType::ValueID; }
bool colorIsDerivedFromElement() const;
static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> createIdentifier(CSSValueID valueID)
{
return adoptRefWillBeNoop(new CSSPrimitiveValue(valueID));
}
static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> createIdentifier(CSSPropertyID propertyID)
{
return adoptRefWillBeNoop(new CSSPrimitiveValue(propertyID));
}
static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> createColor(RGBA32 rgbValue)
{
return adoptRefWillBeNoop(new CSSPrimitiveValue(rgbValue));
}
static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> create(double value, UnitType type)
{
return adoptRefWillBeNoop(new CSSPrimitiveValue(value, type));
}
static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> create(const String& value, UnitType type)
{
return adoptRefWillBeNoop(new CSSPrimitiveValue(value, type));
}
static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> create(const Length& value, float zoom)
{
return adoptRefWillBeNoop(new CSSPrimitiveValue(value, zoom));
}
template<typename T> static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> create(T value)
{
return adoptRefWillBeNoop(new CSSPrimitiveValue(value));
}
~CSSPrimitiveValue();
void cleanup();
UnitType typeWithCalcResolved() const;
double computeDegrees() const;
double computeSeconds() 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()); }
String getStringValue() const;
RGBA32 getRGBA32Value() const { ASSERT(isRGBColor()); return m_value.rgbcolor; }
CSSBasicShape* getShapeValue() const { ASSERT(isShape()); return m_value.shape; }
CSSCalcValue* cssCalcValue() const { ASSERT(isCalculated()); return m_value.calc; }
CSSPropertyID getPropertyID() const { ASSERT(isPropertyID()); return m_value.propertyID; }
CSSValueID getValueID() const { return type() == UnitType::ValueID ? m_value.valueID : CSSValueInvalid; }
template<typename T> inline operator T() const; // Defined in CSSPrimitiveValueMappings.h
static const char* unitTypeToString(UnitType);
String customCSSText() const;
bool equals(const CSSPrimitiveValue&) const;
DECLARE_TRACE_AFTER_DISPATCH();
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(CSSValueID);
CSSPrimitiveValue(CSSPropertyID);
CSSPrimitiveValue(RGBA32 color);
CSSPrimitiveValue(const Length&, float zoom);
CSSPrimitiveValue(const String&, UnitType);
CSSPrimitiveValue(double, UnitType);
template<typename T> CSSPrimitiveValue(T); // Defined in CSSPrimitiveValueMappings.h
template<typename T> CSSPrimitiveValue(T* val)
: CSSValue(PrimitiveClass)
{
init(PassRefPtrWillBeRawPtr<T>(val));
}
template<typename T> CSSPrimitiveValue(PassRefPtrWillBeRawPtr<T> val)
: CSSValue(PrimitiveClass)
{
init(val);
}
static void create(int); // compile-time guard
static void create(unsigned); // compile-time guard
template<typename T> operator T*(); // compile-time guard
void init(UnitType);
void init(const Length&);
void init(PassRefPtrWillBeRawPtr<CSSBasicShape>);
void init(PassRefPtrWillBeRawPtr<CSSCalcValue>);
double computeLengthDouble(const CSSToLengthConversionData&) const;
inline UnitType type() const { return static_cast<UnitType>(m_primitiveUnitType); }
union {
CSSPropertyID propertyID;
CSSValueID valueID;
double num;
StringImpl* string;
RGBA32 rgbcolor;
// FIXME: oilpan: Should be members, but no support for members in unions. Just trace the raw ptr for now.
CSSBasicShape* shape;
CSSCalcValue* calc;
} m_value;
};
using CSSLengthArray = CSSPrimitiveValue::CSSLengthArray;
using CSSLengthTypeArray = CSSPrimitiveValue::CSSLengthTypeArray;
DEFINE_CSS_VALUE_TYPE_CASTS(CSSPrimitiveValue, isPrimitiveValue());
} // namespace blink
#endif // CSSPrimitiveValue_h