Index: Source/core/css/CSSPrimitiveValue.h |
diff --git a/Source/core/css/CSSPrimitiveValue.h b/Source/core/css/CSSPrimitiveValue.h |
index a810b39136c13da67a088033ce8e128cc5ad6347..9f84a36b9bf1b567c16b5a5a641ccb56570fc337 100644 |
--- a/Source/core/css/CSSPrimitiveValue.h |
+++ b/Source/core/css/CSSPrimitiveValue.h |
@@ -109,35 +109,35 @@ public: |
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_CUSTOM_IDENT = 18, |
+ CSS_URI = 19, |
+ CSS_IDENT = 20, |
+ CSS_ATTR = 21, |
+ CSS_COUNTER = 22, |
+ CSS_RECT = 23, |
+ CSS_RGBCOLOR = 24, |
+ CSS_VW = 25, |
+ CSS_VH = 26, |
+ CSS_VMIN = 27, |
+ CSS_VMAX = 28, |
+ CSS_DPPX = 29, |
+ CSS_DPI = 30, |
+ CSS_DPCM = 31, |
+ CSS_FR = 32, |
+ CSS_INTEGER = 33, |
+ CSS_PAIR = 34, |
+ CSS_TURN = 35, |
+ CSS_REMS = 36, |
+ CSS_CHS = 37, |
+ CSS_SHAPE = 38, |
+ CSS_QUAD = 39, |
+ CSS_CALC = 40, |
+ CSS_CALC_PERCENTAGE_WITH_NUMBER = 41, |
+ CSS_CALC_PERCENTAGE_WITH_LENGTH = 42, |
+ CSS_STRING = 43, |
+ CSS_PROPERTY_ID = 44, |
+ CSS_VALUE_ID = 45, |
+ CSS_QEM = 46 |
}; |
enum LengthUnitType { |
@@ -159,6 +159,123 @@ public: |
typedef Vector<double, CSSPrimitiveValue::LengthUnitTypeCount> CSSLengthArray; |
typedef BitVector CSSLengthTypeArray; |
+ struct CSSTaggedPtrValue { |
+ // Variables for accessing parts of the tagged pointer. |
+ // 32 bits = <value 25 bits><type 6 bits><tag 1 bit> |
+ // 64 bits = <value 57 bits><type 6 bits><tag 1 bit> |
+#if CPU(32BIT) |
+ static const uint doubleShiftAmount = 32 + 7; |
+ static const uint64_t mantissaTruncationMask = 0x7fffffffff; |
+#elif CPU(64BIT) |
+ static const uint doubleShiftAmount = 7; |
+ static const uint64_t mantissaTruncationMask = 0x7f; |
+#endif |
+ |
+ unsigned flag : 1; |
+ unsigned type : 6; |
+#if CPU(32BIT) |
+ unsigned long long valueRaw : 25; |
+#elif CPU(64BIT) |
+ unsigned long long valueRaw : 57; |
+#endif |
+ |
+ 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; |
+ |
+ |
+ // Returns true if value can be stored in the value field of the tagged pointer |
+ // without losing information. |
+ inline static bool fitsWithoutDataLoss(double value) |
+ { |
+ union { |
+ double asDouble; |
+ uint64_t asBits; |
+ } interpretableValue; |
+ interpretableValue.asDouble = value; |
+ return (interpretableValue.asBits & mantissaTruncationMask) == 0; |
+ } |
+ |
+ inline static bool fitsWithoutDataLoss(RGBA32 color) |
+ { |
+#if CPU(32BIT) |
+ return alphaChannel(color) == 0 || alphaChannel(color) == 255; |
+#elif CPU(64BIT) |
+ return true; |
+#endif |
+ } |
+ |
+ // Convenience methods for getting/setting the value field, which is truncated. |
+ inline double getValue() const |
+ { |
+ uint64_t shiftedValue = valueRaw; |
+ shiftedValue = shiftedValue << doubleShiftAmount; |
+ return *reinterpret_cast<double*>(&shiftedValue); |
+ } |
+ |
+ inline RGBA32 getColorValue() const |
+ { |
+ uintptr_t valueRawVar = valueRaw; |
+ packedColor color = *reinterpret_cast<packedColor*>(&valueRawVar); |
+ int alpha = color.alpha; |
+#if CPU(32BIT) |
+ alpha = color.alpha == 1 ? 255 : 0; |
+#endif |
+ return makeRGBA(color.red, color.green, color.blue, alpha); |
+ } |
+ |
+ inline CSSPropertyID getPropertyIDValue() const |
+ { |
+ return static_cast<CSSPropertyID>(valueRaw); |
+ } |
+ |
+ inline CSSValueID getValueIDValue() const |
+ { |
+ return static_cast<CSSValueID>(valueRaw); |
+ } |
+ |
+ inline void setValue(double value) |
+ { |
+ union { |
+ double asDouble; |
+ uint64_t asBits; |
+ } interpretableValue; |
+ interpretableValue.asDouble = value; |
+ valueRaw = interpretableValue.asBits >> doubleShiftAmount; |
+ } |
+ |
+ inline void setValue(RGBA32 value) |
+ { |
+ packedColor color; |
+ color.red = static_cast<uintptr_t>(redChannel(value)); |
+ color.green = static_cast<uintptr_t>(greenChannel(value)); |
+ color.blue = static_cast<uintptr_t>(blueChannel(value)); |
+#if CPU(32BIT) |
+ color.alpha = static_cast<uintptr_t>(alphaChannel(value) == 255 ? 1 : 0); |
+#elif CPU(64BIT) |
+ color.alpha = static_cast<uintptr_t>(alphaChannel(value)); |
+#endif |
+ valueRaw = *reinterpret_cast<uintptr_t*>(&color); |
+ } |
+ |
+ inline void setValue(CSSPropertyID propertyID) |
+ { |
+ valueRaw = static_cast<uintptr_t>(propertyID); |
+ } |
+ |
+ inline void setValue(CSSValueID valueID) |
+ { |
+ valueRaw = static_cast<uintptr_t>(valueID); |
+ } |
+ }; |
+ |
// No methods here, don't use this. It's just for large value storage. |
// IMPORTANT: You should never actually make one of these outside the parser. |
class CSSLargePrimitiveValue final : public CSSValueObject { |
@@ -206,6 +323,12 @@ public: |
CSSPrimitiveValueData m_value; |
}; |
+ explicit CSSPrimitiveValue(CSSTaggedPtrValue taggedPtr) |
+ : m_rawValue(taggedPtr) |
+ { |
+ ASSERT(!isObject()); |
+ } |
+ |
explicit CSSPrimitiveValue(const CSSLargePrimitiveValue* object) |
: m_rawValue(const_cast<CSSLargePrimitiveValue*>(object)) |
{ |
@@ -219,7 +342,7 @@ public: |
CSSPrimitiveValue(const CSSPrimitiveValue& other) |
- : m_rawValue(other.m_rawValue) |
+ : m_rawValue(other.m_rawValue.asPtr) |
{ |
ref(); |
} |
@@ -240,7 +363,7 @@ public: |
CSSLargePrimitiveValue* get() const |
{ |
- return m_rawValue; |
+ return m_rawValue.asPtr; |
} |
void accumulateLengthArray(CSSLengthArray&, double multiplier = 1) const; |
@@ -309,18 +432,41 @@ public: |
static CSSPrimitiveValue createIdentifier(CSSValueID valueID) |
{ |
- return CSSPrimitiveValue(adoptRefWillBeNoop(new CSSLargePrimitiveValue(valueID))); |
+ CSSTaggedPtrValue taggedPointer; |
+ taggedPointer.flag = 1; |
+ taggedPointer.type = CSS_VALUE_ID; |
+ taggedPointer.setValue(valueID); |
+ return CSSPrimitiveValue(taggedPointer); |
} |
+ |
static CSSPrimitiveValue createIdentifier(CSSPropertyID propertyID) |
{ |
- return CSSPrimitiveValue(adoptRefWillBeNoop(new CSSLargePrimitiveValue(propertyID))); |
+ CSSTaggedPtrValue taggedPointer; |
+ taggedPointer.flag = 1; |
+ taggedPointer.type = CSS_PROPERTY_ID; |
+ taggedPointer.setValue(propertyID); |
+ return CSSPrimitiveValue(taggedPointer); |
} |
static CSSPrimitiveValue createColor(RGBA32 rgbValue) |
{ |
+ if (CSSTaggedPtrValue::fitsWithoutDataLoss(rgbValue)) { |
+ CSSTaggedPtrValue taggedPointer; |
+ taggedPointer.flag = 1; |
+ taggedPointer.type = CSS_RGBCOLOR; |
+ taggedPointer.setValue(rgbValue); |
+ return CSSPrimitiveValue(taggedPointer); |
+ } |
return CSSPrimitiveValue(adoptRefWillBeNoop(new CSSLargePrimitiveValue(rgbValue))); |
} |
static CSSPrimitiveValue create(double value, UnitType type) |
{ |
+ if (CSSTaggedPtrValue::fitsWithoutDataLoss(value)) { |
+ CSSTaggedPtrValue taggedPointer; |
+ taggedPointer.flag = 1; |
+ taggedPointer.type = type; |
+ taggedPointer.setValue(value); |
+ return CSSPrimitiveValue(taggedPointer); |
+ } |
return CSSPrimitiveValue(adoptRefWillBeNoop(new CSSLargePrimitiveValue(value, type))); |
} |
static CSSPrimitiveValue create(const String& value, UnitType type) |
@@ -391,7 +537,12 @@ public: |
String customCSSText() const; |
String cssText() const { return customCSSText(); } |
- bool isQuirkValue() const { return m_rawValue->m_isQuirkValue; } |
+ bool isQuirkValue() const |
+ { |
+ if (!isObject()) |
+ return false; |
+ return m_rawValue.asPtr->m_isQuirkValue; |
+ } |
bool equals(const CSSPrimitiveValue) const; |
@@ -405,21 +556,22 @@ public: |
DEFINE_INLINE_TRACE() |
{ |
visitor->trace(m_rawValue); |
- m_rawValue->traceAfterDispatch(visitor); |
} |
private: |
void ref() const |
{ |
#if !ENABLE(OILPAN) |
- m_rawValue->ref(); |
+ if (isObject()) |
+ m_rawValue.asPtr->ref(); |
#endif |
} |
void deref() const |
{ |
#if !ENABLE(OILPAN) |
- m_rawValue->deref(); |
+ if (isObject()) |
+ m_rawValue.asPtr->deref(); |
#endif |
} |
@@ -429,22 +581,59 @@ private: |
double computeLengthDouble(const CSSToLengthConversionData&); |
- RawPtrWillBeMember<CSSLargePrimitiveValue> m_rawValue; |
+ union CSSPrimitivePointerValue { |
+ CSSTaggedPtrValue asTaggedPtr; |
+ RawPtrWillBeMember<CSSLargePrimitiveValue> asPtr; |
+ |
+ CSSPrimitivePointerValue(CSSLargePrimitiveValue* ptr) : asPtr(ptr) { } |
+ CSSPrimitivePointerValue(CSSTaggedPtrValue taggedPtr) : asTaggedPtr(taggedPtr) { } |
+ |
+ DEFINE_INLINE_TRACE() |
+ { |
+ if (!(reinterpret_cast<uintptr_t>(asPtr.get()) & 1)) { |
+ visitor->trace(asPtr); |
+ asPtr->traceAfterDispatch(visitor); |
+ } |
+ } |
+ } m_rawValue; |
+ static_assert(sizeof(m_rawValue) == sizeof(void*), "The tagged pointer field in CSSPrimitiveValue must be the size of a pointer"); |
+ |
+ bool isObject() const |
+ { |
+ return m_rawValue.asTaggedPtr.flag == 0; |
+ } |
// Getters/setters for inner class. |
- CSSPrimitiveValueData value() const { return m_rawValue->m_value; } |
- UnitType type() const { return static_cast<UnitType>(m_rawValue->m_primitiveUnitType); } |
- bool hasCachedCSSText() const { return m_rawValue->m_hasCachedCSSText; } |
- |
- void setValue(CSSPrimitiveValueData value) { m_rawValue->m_value = value; } |
- void setType(UnitType primitiveUnitType) { m_rawValue->m_primitiveUnitType = static_cast<unsigned>(primitiveUnitType); } |
- void setHasCachedCSSText(bool hasCachedCSSText) const { m_rawValue->m_hasCachedCSSText = hasCachedCSSText; } |
- void setIsQuirkValue(bool isQuirkValue) { m_rawValue->m_isQuirkValue = isQuirkValue; } |
+ CSSPrimitiveValueData value() const |
+ { |
+ if (isObject()) |
+ return m_rawValue.asPtr->m_value; |
+ |
+ CSSPrimitiveValueData result; |
+ if (m_rawValue.asTaggedPtr.type == CSS_RGBCOLOR) |
+ result.rgbcolor = m_rawValue.asTaggedPtr.getColorValue(); |
+ else if (m_rawValue.asTaggedPtr.type == CSS_PROPERTY_ID) |
+ result.propertyID = m_rawValue.asTaggedPtr.getPropertyIDValue(); |
+ else if (m_rawValue.asTaggedPtr.type == CSS_VALUE_ID) |
+ result.valueID = m_rawValue.asTaggedPtr.getValueIDValue(); |
+ else |
+ result.num = m_rawValue.asTaggedPtr.getValue(); |
+ return result; |
+ } |
+ |
+ UnitType type() const |
+ { |
+ if (isObject()) |
+ return static_cast<UnitType>(m_rawValue.asPtr->m_primitiveUnitType); |
+ return static_cast<UnitType>(m_rawValue.asTaggedPtr.type); |
+ } |
}; |
typedef CSSPrimitiveValue::CSSLengthArray CSSLengthArray; |
typedef CSSPrimitiveValue::CSSLengthTypeArray CSSLengthTypeArray; |
+static_assert(sizeof(CSSPrimitiveValue) == sizeof(void*), "CSSPrimitiveValue must be the size of a pointer"); |
+ |
} // namespace blink |
#endif // CSSPrimitiveValue_h |