Index: Source/core/css/CSSPrimitiveValue.h |
diff --git a/Source/core/css/CSSPrimitiveValue.h b/Source/core/css/CSSPrimitiveValue.h |
index 3f7b65ed10fa47ffdcee0ea063f26b3bc7687402..1820b226d24c511e3c90c80db830cb3cfecda590 100644 |
--- a/Source/core/css/CSSPrimitiveValue.h |
+++ b/Source/core/css/CSSPrimitiveValue.h |
@@ -31,6 +31,7 @@ |
#include "wtf/Forward.h" |
#include "wtf/MathExtras.h" |
#include "wtf/PassRefPtr.h" |
+#include "wtf/RefCounted.h" |
#include "wtf/text/StringHash.h" |
namespace blink { |
@@ -70,56 +71,58 @@ template<> inline float roundForImpreciseConversion(double 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. |
+// In some cases, CSSPrimitiveValue is a tagged pointer. If isTaggedPtr() returns |
+// true, |this| is an invalid pointer and member variables should not be accessed. |
class CORE_EXPORT CSSPrimitiveValue : public CSSValue { |
public: |
enum UnitType { |
- CSS_UNKNOWN = 0, |
- CSS_NUMBER = 1, |
- CSS_PERCENTAGE = 2, |
- CSS_EMS = 3, |
- CSS_EXS = 4, |
- CSS_PX = 5, |
- CSS_CM = 6, |
- CSS_MM = 7, |
- CSS_IN = 8, |
- CSS_PT = 9, |
- CSS_PC = 10, |
- CSS_DEG = 11, |
- CSS_RAD = 12, |
- CSS_GRAD = 13, |
- CSS_MS = 14, |
- CSS_S = 15, |
- CSS_HZ = 16, |
- CSS_KHZ = 17, |
- CSS_CUSTOM_IDENT = 19, |
- CSS_URI = 20, |
- CSS_IDENT = 21, |
- CSS_ATTR = 22, |
- CSS_COUNTER = 23, |
- CSS_RECT = 24, |
- CSS_RGBCOLOR = 25, |
- CSS_VW = 26, |
- CSS_VH = 27, |
- CSS_VMIN = 28, |
- CSS_VMAX = 29, |
- CSS_DPPX = 30, |
- CSS_DPI = 31, |
- CSS_DPCM = 32, |
- CSS_FR = 33, |
- CSS_INTEGER = 34, |
- CSS_PAIR = 100, |
- CSS_TURN = 107, |
- CSS_REMS = 108, |
- CSS_CHS = 109, |
- CSS_SHAPE = 111, |
- CSS_QUAD = 112, |
- CSS_CALC = 113, |
- CSS_CALC_PERCENTAGE_WITH_NUMBER = 114, |
- CSS_CALC_PERCENTAGE_WITH_LENGTH = 115, |
- CSS_STRING = 116, |
- CSS_PROPERTY_ID = 117, |
- CSS_VALUE_ID = 118, |
- CSS_QEM = 119 |
+ CSS_UNKNOWN, |
+ CSS_NUMBER, |
+ CSS_PERCENTAGE, |
+ CSS_EMS, |
+ CSS_EXS, |
+ CSS_PX, |
+ CSS_CM, |
+ CSS_MM, |
+ CSS_IN, |
+ CSS_PT, |
+ CSS_PC, |
+ CSS_DEG, |
+ CSS_RAD, |
+ CSS_GRAD, |
+ CSS_MS, |
+ CSS_S, |
+ CSS_HZ, |
+ CSS_KHZ, |
+ CSS_CUSTOM_IDENT, |
+ CSS_URI, |
+ CSS_IDENT, |
+ CSS_ATTR, |
+ CSS_COUNTER, |
+ CSS_RECT, |
+ CSS_RGBCOLOR, |
+ CSS_VW, |
+ CSS_VH, |
+ CSS_VMIN, |
+ CSS_VMAX, |
+ CSS_DPPX, |
+ CSS_DPI, |
+ CSS_DPCM, |
+ CSS_FR, |
+ CSS_INTEGER, |
+ CSS_PAIR, |
+ CSS_TURN, |
+ CSS_REMS, |
+ CSS_CHS, |
+ CSS_SHAPE, |
+ CSS_QUAD, |
+ CSS_CALC, |
+ CSS_CALC_PERCENTAGE_WITH_NUMBER, |
+ CSS_CALC_PERCENTAGE_WITH_LENGTH, |
+ CSS_STRING, |
+ CSS_PROPERTY_ID, |
+ CSS_VALUE_ID, |
+ CSS_QEM |
}; |
enum LengthUnitType { |
@@ -138,6 +141,21 @@ public: |
LengthUnitTypeCount, |
}; |
+ union CSSPrimitiveValueData { |
+ 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; |
+ Counter* counter; |
+ Pair* pair; |
+ Rect* rect; |
+ Quad* quad; |
+ }; |
+ |
typedef Vector<double, CSSPrimitiveValue::LengthUnitTypeCount> CSSLengthArray; |
typedef BitVector CSSLengthTypeArray; |
@@ -163,22 +181,22 @@ public: |
bool isAngle() const |
{ |
- return m_primitiveUnitType == CSS_DEG |
- || m_primitiveUnitType == CSS_RAD |
- || m_primitiveUnitType == CSS_GRAD |
- || m_primitiveUnitType == CSS_TURN; |
+ return type() == CSS_DEG |
+ || type() == CSS_RAD |
+ || type() == CSS_GRAD |
+ || type() == CSS_TURN; |
} |
- bool isAttr() const { return m_primitiveUnitType == CSS_ATTR; } |
- bool isCounter() const { return m_primitiveUnitType == CSS_COUNTER; } |
- bool isCustomIdent() const { return m_primitiveUnitType == CSS_CUSTOM_IDENT; } |
+ bool isAttr() const { return type() == CSS_ATTR; } |
+ bool isCounter() const { return type() == CSS_COUNTER; } |
+ bool isCustomIdent() const { return type() == CSS_CUSTOM_IDENT; } |
bool isFontRelativeLength() const |
{ |
- return m_primitiveUnitType == CSS_EMS |
- || m_primitiveUnitType == CSS_EXS |
- || m_primitiveUnitType == CSS_REMS |
- || m_primitiveUnitType == CSS_CHS; |
+ return type() == CSS_EMS |
+ || type() == CSS_EXS |
+ || type() == CSS_REMS |
+ || type() == CSS_CHS; |
} |
- bool isViewportPercentageLength() const { return isViewportPercentageLength(static_cast<UnitType>(m_primitiveUnitType)); } |
+ bool isViewportPercentageLength() const { return isViewportPercentageLength(type()); } |
static bool isViewportPercentageLength(UnitType type) { return type >= CSS_VW && type <= CSS_VMAX; } |
static bool isLength(UnitType type) |
{ |
@@ -188,13 +206,13 @@ public: |
bool isNumber() const { return primitiveType() == CSS_NUMBER || primitiveType() == CSS_INTEGER; } |
bool isPercentage() const { return primitiveType() == CSS_PERCENTAGE; } |
bool isPx() const { return primitiveType() == CSS_PX; } |
- bool isRect() const { return m_primitiveUnitType == CSS_RECT; } |
- bool isRGBColor() const { return m_primitiveUnitType == CSS_RGBCOLOR; } |
- bool isShape() const { return m_primitiveUnitType == CSS_SHAPE; } |
- bool isString() const { return m_primitiveUnitType == CSS_STRING; } |
- bool isTime() const { return m_primitiveUnitType == CSS_S || m_primitiveUnitType == CSS_MS; } |
- bool isURI() const { return m_primitiveUnitType == CSS_URI; } |
- bool isCalculated() const { return m_primitiveUnitType == CSS_CALC; } |
+ bool isRect() const { return type() == CSS_RECT; } |
+ bool isRGBColor() const { return type() == CSS_RGBCOLOR; } |
+ bool isShape() const { return type() == CSS_SHAPE; } |
+ bool isString() const { return type() == CSS_STRING; } |
+ bool isTime() const { return type() == CSS_S || type() == CSS_MS; } |
+ bool isURI() const { return type() == CSS_URI; } |
+ bool isCalculated() const { return type() == CSS_CALC; } |
bool isCalculatedPercentageWithNumber() const { return primitiveType() == CSS_CALC_PERCENTAGE_WITH_NUMBER; } |
bool isCalculatedPercentageWithLength() const { return primitiveType() == CSS_CALC_PERCENTAGE_WITH_LENGTH; } |
static bool isDotsPerInch(UnitType type) { return type == CSS_DPI; } |
@@ -202,24 +220,63 @@ public: |
static bool isDotsPerCentimeter(UnitType type) { return type == CSS_DPCM; } |
static bool isResolution(UnitType type) { return type >= CSS_DPPX && type <= CSS_DPCM; } |
bool isFlex() const { return primitiveType() == CSS_FR; } |
- bool isValueID() const { return m_primitiveUnitType == CSS_VALUE_ID; } |
+ bool isValueID() const { return type() == CSS_VALUE_ID; } |
bool colorIsDerivedFromElement() const; |
static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> createIdentifier(CSSValueID valueID) |
{ |
- return adoptRefWillBeNoop(new CSSPrimitiveValue(valueID)); |
+ CSSTaggedPtrValue taggedPtr; |
+ taggedPtr.flag = 1; |
+ taggedPtr.type = static_cast<uintptr_t>(CSSPrimitiveValue::CSS_VALUE_ID); |
+ taggedPtr.value = static_cast<uintptr_t>(valueID); |
+ return adoptRefWillBeNoop(toPtr(taggedPtr)); |
} |
static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> createIdentifier(CSSPropertyID propertyID) |
{ |
- return adoptRefWillBeNoop(new CSSPrimitiveValue(propertyID)); |
+ CSSTaggedPtrValue taggedPtr; |
+ taggedPtr.flag = 1; |
+ taggedPtr.type = static_cast<uintptr_t>(CSSPrimitiveValue::CSS_PROPERTY_ID); |
+ taggedPtr.value = static_cast<uintptr_t>(propertyID); |
+ return adoptRefWillBeNoop(toPtr(taggedPtr)); |
} |
static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> createColor(RGBA32 rgbValue) |
{ |
- return adoptRefWillBeNoop(new CSSPrimitiveValue(rgbValue)); |
+ bool canFitColor; |
+#if CPU(32BIT) |
+ canFitColor = alphaChannel(rgbValue) == 0 || alphaChannel(rgbValue) == 255; |
+#elif CPU(64BIT) |
+ canFitColor = true; |
+#endif |
+ if (!canFitColor) |
+ return adoptRefWillBeNoop(new CSSPrimitiveValue(rgbValue)); |
+ |
+ CSSTaggedPtrValue taggedPtr; |
+ taggedPtr.flag = 1; |
+ taggedPtr.type = static_cast<uintptr_t>(CSSPrimitiveValue::CSS_RGBCOLOR); |
+ |
+ packedColor colorToStore; |
+ colorToStore.red = static_cast<uintptr_t>(redChannel(rgbValue)); |
+ colorToStore.green = static_cast<uintptr_t>(greenChannel(rgbValue)); |
+ colorToStore.blue = static_cast<uintptr_t>(blueChannel(rgbValue)); |
+#if CPU(32BIT) |
+ colorToStore.alpha = static_cast<uintptr_t>(alphaChannel(rgbValue) == 255 ? 1 : 0); |
+#elif CPU(64BIT) |
+ colorToStore.alpha = static_cast<uintptr_t>(alphaChannel(rgbValue)); |
+#endif |
+ taggedPtr.value = *reinterpret_cast<uintptr_t*>(&colorToStore); |
+ return adoptRefWillBeNoop(toPtr(taggedPtr)); |
} |
static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> create(double value, UnitType type) |
{ |
- return adoptRefWillBeNoop(new CSSPrimitiveValue(value, type)); |
+ uint64_t& doubleAsBits = reinterpret_cast<uint64_t&>(value); |
+ if ((doubleAsBits & mantissaTruncationMask) != 0) |
+ return adoptRefWillBeNoop(new CSSPrimitiveValue(value, type)); |
+ |
+ CSSTaggedPtrValue taggedPtr; |
+ taggedPtr.flag = 1; |
+ taggedPtr.type = static_cast<uintptr_t>(type); |
+ taggedPtr.value = doubleAsBits >> doubleShiftAmount; |
+ return adoptRefWillBeNoop(toPtr(taggedPtr)); |
} |
static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> create(const String& value, UnitType type) |
{ |
@@ -264,36 +321,49 @@ public: |
// Converts to a Length (Fixed, Percent or Calculated) |
Length convertToLength(const CSSToLengthConversionData&); |
- double getDoubleValue() const; |
+ double getDoubleValue() const |
+ { |
+ if (type() == CSS_CALC) |
+ return getCalcDoubleValue(); |
+ return value().num; |
+ } |
+ |
+ double getCalcDoubleValue() 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; |
- Counter* getCounterValue() const { return m_primitiveUnitType != CSS_COUNTER ? 0 : m_value.counter; } |
+ Counter* getCounterValue() const { return type() != CSS_COUNTER ? 0 : value().counter; } |
- Rect* getRectValue() const { return m_primitiveUnitType != CSS_RECT ? 0 : m_value.rect; } |
+ Rect* getRectValue() const { return type() != CSS_RECT ? 0 : value().rect; } |
- Quad* getQuadValue() const { return m_primitiveUnitType != CSS_QUAD ? 0 : m_value.quad; } |
+ Quad* getQuadValue() const { return type() != CSS_QUAD ? 0 : value().quad; } |
- RGBA32 getRGBA32Value() const { return m_primitiveUnitType != CSS_RGBCOLOR ? 0 : m_value.rgbcolor; } |
+ RGBA32 getRGBA32Value() const { return type() != CSS_RGBCOLOR ? 0 : value().rgbcolor; } |
- Pair* getPairValue() const { return m_primitiveUnitType != CSS_PAIR ? 0 : m_value.pair; } |
+ Pair* getPairValue() const { return type() != CSS_PAIR ? 0 : value().pair; } |
- CSSBasicShape* getShapeValue() const { return m_primitiveUnitType != CSS_SHAPE ? 0 : m_value.shape; } |
+ CSSBasicShape* getShapeValue() const { return type() != CSS_SHAPE ? 0 : value().shape; } |
- CSSCalcValue* cssCalcValue() const { return m_primitiveUnitType != CSS_CALC ? 0 : m_value.calc; } |
+ CSSCalcValue* cssCalcValue() const { return type() != CSS_CALC ? 0 : value().calc; } |
- CSSPropertyID getPropertyID() const { return m_primitiveUnitType == CSS_PROPERTY_ID ? m_value.propertyID : CSSPropertyInvalid; } |
- CSSValueID getValueID() const { return m_primitiveUnitType == CSS_VALUE_ID ? m_value.valueID : CSSValueInvalid; } |
+ CSSPropertyID getPropertyID() const { return type() == CSS_PROPERTY_ID ? value().propertyID : CSSPropertyInvalid; } |
+ CSSValueID getValueID() const { return type() == CSS_VALUE_ID ? value().valueID : CSSValueInvalid; } |
template<typename T> inline operator T() const; // Defined in CSSPrimitiveValueMappings.h |
static const char* unitTypeToString(UnitType); |
String customCSSText() const; |
- bool isQuirkValue() { return m_isQuirkValue; } |
+ inline bool isQuirkValue() const |
+ { |
+ if (isTaggedPtr()) |
+ return false; |
+ return m_isQuirkValue; |
+ } |
bool equals(const CSSPrimitiveValue&) const; |
@@ -343,20 +413,86 @@ private: |
double computeLengthDouble(const CSSToLengthConversionData&); |
- 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; |
- Counter* counter; |
- Pair* pair; |
- Rect* rect; |
- Quad* quad; |
- } m_value; |
+ // Useful bit masks for dealing with tagged pointer doubles. |
+#if CPU(32BIT) |
+ static const unsigned doubleShiftAmount = 32 + 7; |
+ static const uint64_t mantissaTruncationMask = 0x7fffffffff; |
+#elif CPU(64BIT) |
+ static const unsigned doubleShiftAmount = 7; |
+ static const uint64_t mantissaTruncationMask = 0x7f; |
+#endif |
+ |
+ // Struct for storing RGB values. |
+ typedef struct { |
+ unsigned red : 8; |
+ unsigned green : 8; |
+ unsigned blue : 8; |
+#if CPU(32BIT) |
+ unsigned alpha : 1; |
+#elif CPU(64BIT) |
+ unsigned alpha : 8; |
+#endif |
+ } packedColor; |
+ |
+ // Getter/setter functions that account for tagged pointer optimization. |
+ inline bool isTaggedPtr() const |
+ { |
+ return reinterpret_cast<uintptr_t>(this) & 1; |
+ } |
+ |
+ static inline CSSPrimitiveValue* toPtr(CSSTaggedPtrValue taggedPtr) |
+ { |
+ return reinterpret_cast<CSSPrimitiveValue*&>(taggedPtr); |
+ } |
+ |
+ inline CSSTaggedPtrValue toTaggedPtr() const |
+ { |
+ CSSPrimitiveValue* nonConstThis = const_cast<CSSPrimitiveValue*>(this); |
+ return reinterpret_cast<CSSTaggedPtrValue&&>(nonConstThis); |
+ } |
+ |
+ inline UnitType type() const |
+ { |
+ if (!isTaggedPtr()) |
+ return static_cast<UnitType>(m_primitiveUnitType); |
+ return static_cast<UnitType>(toTaggedPtr().type); |
+ } |
+ |
+ inline CSSPrimitiveValueData value() const |
+ { |
+ if (!isTaggedPtr()) |
+ return m_value; |
+ |
+ CSSPrimitiveValueData data; |
+ switch (type()) { |
+ case CSSPrimitiveValue::CSS_PROPERTY_ID: |
+ data.propertyID = static_cast<CSSPropertyID>(toTaggedPtr().value); |
+ break; |
+ case CSSPrimitiveValue::CSS_VALUE_ID: |
+ data.valueID = static_cast<CSSValueID>(toTaggedPtr().value); |
+ break; |
+ case CSSPrimitiveValue::CSS_RGBCOLOR: { |
+ uintptr_t valueRawVar = toTaggedPtr().value; |
+ packedColor color = *reinterpret_cast<packedColor*>(&valueRawVar); |
+ unsigned alpha; |
+#if CPU(32BIT) |
+ alpha = color.alpha == 1 ? 255 : 0; |
+#elif CPU(64BIT) |
+ alpha = color.alpha; |
+#endif |
+ data.rgbcolor = makeRGBA(color.red, color.green, color.blue, alpha); |
+ break; |
+ } |
+ default: |
+ uint64_t shiftedValue = toTaggedPtr().value; |
+ shiftedValue = shiftedValue << doubleShiftAmount; |
+ data.num = *reinterpret_cast<double*>(&shiftedValue); |
+ break; |
+ } |
+ return data; |
+ } |
+ |
+ CSSPrimitiveValueData m_value; |
}; |
typedef CSSPrimitiveValue::CSSLengthArray CSSLengthArray; |
@@ -366,4 +502,19 @@ DEFINE_CSS_VALUE_TYPE_CASTS(CSSPrimitiveValue, isPrimitiveValue()); |
} // namespace blink |
+namespace WTF { |
+ |
+#if !ENABLE(OILPAN) |
+// Must be defined *after* CSSPrimitiveValue to compile with the correct adopted() method. |
+template<> inline PassRefPtr<blink::CSSPrimitiveValue> adoptRef<blink::CSSPrimitiveValue>(blink::CSSPrimitiveValue* p) |
+{ |
+ // Immediates (non-pointers) end in a 1. |
+ if (!(reinterpret_cast<uintptr_t>(p) & 1)) |
+ adopted(p); |
+ return PassRefPtr<blink::CSSPrimitiveValue>(p, PassRefPtr<blink::CSSPrimitiveValue>::AdoptRef); |
+} |
+#endif |
+ |
+} // namespace WTF |
+ |
#endif // CSSPrimitiveValue_h |