Index: Source/core/css/CSSValue.h |
diff --git a/Source/core/css/CSSValue.h b/Source/core/css/CSSValue.h |
index 7bec2acc42b668100407563f551f0c63e2ee7c00..609dcbc85afcae15a768dc5b5debdca568aa6112 100644 |
--- a/Source/core/css/CSSValue.h |
+++ b/Source/core/css/CSSValue.h |
@@ -22,231 +22,335 @@ |
#define CSSValue_h |
#include "core/CoreExport.h" |
+#include "core/css/CSSValueObject.h" |
#include "platform/heap/Handle.h" |
-#include "platform/weborigin/KURL.h" |
-#include "wtf/HashMap.h" |
-#include "wtf/ListHashSet.h" |
#include "wtf/RefCounted.h" |
#include "wtf/RefPtr.h" |
namespace blink { |
-class CORE_EXPORT CSSValue : public RefCountedWillBeGarbageCollectedFinalized<CSSValue> { |
+// A non-nullable container for CSSValueObject. Takes ownership of the passed |
+// CSSValueObject. |
+class CORE_EXPORT CSSValue { |
+ ALLOW_ONLY_INLINE_ALLOCATION(); |
+ friend class NullableCSSValue; |
public: |
-#if ENABLE(OILPAN) |
- // Override operator new to allocate CSSValue subtype objects onto |
- // a dedicated heap. |
- GC_PLUGIN_IGNORE("crbug.com/443854") |
- void* operator new(size_t size) |
- { |
- return allocateObject(size, false); |
- } |
- static void* allocateObject(size_t size, bool isEager) |
- { |
- ThreadState* state = ThreadStateFor<ThreadingTrait<CSSValue>::Affinity>::state(); |
- return Heap::allocateOnHeapIndex(state, size, isEager ? ThreadState::EagerSweepHeapIndex : ThreadState::CSSValueHeapIndex, GCInfoTrait<CSSValue>::index()); |
- } |
-#else |
- // Override RefCounted's deref() to ensure operator delete is called on |
- // the appropriate subclass type. |
- void deref() |
- { |
- if (derefBase()) |
- destroy(); |
- } |
-#endif // !ENABLE(OILPAN) |
- |
- String cssText() const; |
- |
- bool isPrimitiveValue() const { return m_classType == PrimitiveClass; } |
- bool isValueList() const { return m_classType >= ValueListClass; } |
- |
- bool isBaseValueList() const { return m_classType == ValueListClass; } |
- |
- bool isBorderImageSliceValue() const { return m_classType == BorderImageSliceClass; } |
- bool isCanvasValue() const { return m_classType == CanvasClass; } |
- bool isCursorImageValue() const { return m_classType == CursorImageClass; } |
- bool isCrossfadeValue() const { return m_classType == CrossfadeClass; } |
- bool isFontFeatureValue() const { return m_classType == FontFeatureClass; } |
- bool isFontFaceSrcValue() const { return m_classType == FontFaceSrcClass; } |
- bool isFunctionValue() const { return m_classType == FunctionClass; } |
- bool isImageGeneratorValue() const { return m_classType >= CanvasClass && m_classType <= RadialGradientClass; } |
- bool isGradientValue() const { return m_classType >= LinearGradientClass && m_classType <= RadialGradientClass; } |
- bool isImageSetValue() const { return m_classType == ImageSetClass; } |
- bool isImageValue() const { return m_classType == ImageClass; } |
- bool isImplicitInitialValue() const; |
- bool isInheritedValue() const { return m_classType == InheritedClass; } |
- bool isInitialValue() const { return m_classType == InitialClass; } |
- bool isUnsetValue() const { return m_classType == UnsetClass; } |
- bool isCSSWideKeyword() const { return m_classType >= InheritedClass && m_classType <= UnsetClass; } |
- bool isLinearGradientValue() const { return m_classType == LinearGradientClass; } |
- bool isPathValue() const { return m_classType == PathClass; } |
- bool isRadialGradientValue() const { return m_classType == RadialGradientClass; } |
- bool isReflectValue() const { return m_classType == ReflectClass; } |
- bool isShadowValue() const { return m_classType == ShadowClass; } |
- bool isCubicBezierTimingFunctionValue() const { return m_classType == CubicBezierTimingFunctionClass; } |
- bool isStepsTimingFunctionValue() const { return m_classType == StepsTimingFunctionClass; } |
- bool isLineBoxContainValue() const { return m_classType == LineBoxContainClass; } |
- bool isCalcValue() const {return m_classType == CalculationClass; } |
- bool isGridTemplateAreasValue() const { return m_classType == GridTemplateAreasClass; } |
- bool isSVGDocumentValue() const { return m_classType == CSSSVGDocumentClass; } |
- bool isContentDistributionValue() const { return m_classType == CSSContentDistributionClass; } |
- bool isUnicodeRangeValue() const { return m_classType == UnicodeRangeClass; } |
- bool isGridLineNamesValue() const { return m_classType == GridLineNamesClass; } |
- |
- bool hasFailedOrCanceledSubresources() const; |
- |
- bool equals(const CSSValue&) const; |
- |
- void finalizeGarbageCollectedObject(); |
- DEFINE_INLINE_TRACE_AFTER_DISPATCH() { } |
- DECLARE_TRACE(); |
- |
- // ~CSSValue should be public, because non-public ~CSSValue causes C2248 |
- // error: 'blink::CSSValue::~CSSValue' : cannot access protected member |
- // declared in class 'blink::CSSValue' when compiling |
- // 'source\wtf\refcounted.h' by using msvc. |
- ~CSSValue() { } |
- |
-protected: |
- |
- static const size_t ClassTypeBits = 6; |
- enum ClassType { |
- PrimitiveClass, |
- |
- // Image classes. |
- ImageClass, |
- CursorImageClass, |
- |
- // Image generator classes. |
- CanvasClass, |
- CrossfadeClass, |
- LinearGradientClass, |
- RadialGradientClass, |
- |
- // Timing function classes. |
- CubicBezierTimingFunctionClass, |
- StepsTimingFunctionClass, |
- |
- // Other class types. |
- BorderImageSliceClass, |
- FontFeatureClass, |
- FontFaceSrcClass, |
- |
- InheritedClass, |
- InitialClass, |
- UnsetClass, |
- |
- ReflectClass, |
- ShadowClass, |
- UnicodeRangeClass, |
- LineBoxContainClass, |
- CalculationClass, |
- GridTemplateAreasClass, |
- PathClass, |
- |
- // SVG classes. |
- CSSSVGDocumentClass, |
- |
- CSSContentDistributionClass, |
- |
- // List class types must appear after ValueListClass. |
- ValueListClass, |
- FunctionClass, |
- ImageSetClass, |
- GridLineNamesClass, |
- // Do not append non-list class types here. |
- }; |
+ // Not explicit to allow for casting. |
+ CSSValue(const CSSValueObject& cssValueObject) |
+ : m_data(const_cast<CSSValueObject*>(&cssValueObject)) |
+ { |
+ ASSERT(m_data); |
+ ref(); |
+ } |
- static const size_t ValueListSeparatorBits = 2; |
- enum ValueListSeparator { |
- SpaceSeparator, |
- CommaSeparator, |
- SlashSeparator |
- }; |
+ // TODO(sashab): Remove these; construction should only be available with |
+ // CSSValueObject&. |
+ template<class T> CSSValue(PassRefPtrWillBeRawPtr<T> cssValueObject) |
+ : m_data(cssValueObject.leakRef()) |
+ { |
+ static_assert(WTF::IsSubclass<T, CSSValueObject>::value, "Parameter must be a container for CSSValueObject"); |
+ ASSERT(m_data); |
+ } |
+ |
+#if !ENABLE(OILPAN) |
+ template<class T> CSSValue(RefPtrWillBeRawPtr<T> cssValueObject) |
+ : m_data(cssValueObject.release().leakRef()) |
+ { |
+ static_assert(WTF::IsSubclass<T, CSSValueObject>::value, "Parameter must be a container for CSSValueObject"); |
+ ASSERT(m_data); |
+ } |
+#endif |
+ |
+ CSSValue(const CSSValue& cssValue) |
+ : m_data(cssValue.m_data) |
+ { |
+ ref(); |
+ } |
+ |
+ ~CSSValue() |
+ { |
+ deref(); |
+ } |
+ |
+ CSSValue& operator=(const CSSValue& rhs) |
+ { |
+ rhs.ref(); |
+ deref(); |
+ m_data = rhs.m_data; |
+ return *this; |
+ } |
+ |
+ bool operator==(const CSSValue& other) const |
+ { |
+ return m_data->equals(*other.m_data); |
+ } |
- ClassType classType() const { return static_cast<ClassType>(m_classType); } |
+ // TODO: Remove this and update callsites to use operator== instead. |
+ bool equals(const CSSValue& other) const |
+ { |
+ return m_data->equals(*other.m_data); |
+ } |
- explicit CSSValue(ClassType classType) |
- : m_primitiveUnitType(0) |
- , m_hasCachedCSSText(false) |
- , m_isQuirkValue(false) |
- , m_valueListSeparator(SpaceSeparator) |
- , m_classType(classType) |
+ bool ptrEquals(const CSSValue& other) const |
{ |
+ return m_data == other.m_data; |
} |
- // NOTE: This class is non-virtual for memory and performance reasons. |
- // Don't go making it virtual again unless you know exactly what you're doing! |
+ // Methods that proxy to CSSValueObject. |
+ String cssText() const { return m_data->cssText(); } |
+ bool hasFailedOrCanceledSubresources() const { return m_data->hasFailedOrCanceledSubresources(); }; |
+ bool isPrimitiveValue() const { return m_data->isPrimitiveValue(); } |
+ bool isValueList() const { return m_data->isValueList(); } |
+ bool isBaseValueList() const { return m_data->isBaseValueList(); } |
+ bool isBorderImageSliceValue() const { return m_data->isBorderImageSliceValue(); } |
+ bool isCanvasValue() const { return m_data->isCanvasValue(); } |
+ bool isCursorImageValue() const { return m_data->isCursorImageValue(); } |
+ bool isCrossfadeValue() const { return m_data->isCrossfadeValue(); } |
+ bool isFontFeatureValue() const { return m_data->isFontFeatureValue(); } |
+ bool isFontFaceSrcValue() const { return m_data->isFontFaceSrcValue(); } |
+ bool isFunctionValue() const { return m_data->isFunctionValue(); } |
+ bool isImageGeneratorValue() const { return m_data->isImageGeneratorValue(); } |
+ bool isGradientValue() const { return m_data->isGradientValue(); } |
+ bool isImageSetValue() const { return m_data->isImageSetValue(); } |
+ bool isImageValue() const { return m_data->isImageValue(); } |
+ bool isImplicitInitialValue() const { return m_data->isImplicitInitialValue(); }; |
+ bool isInheritedValue() const { return m_data->isInheritedValue(); }; |
+ bool isInitialValue() const { return m_data->isInitialValue(); }; |
+ bool isUnsetValue() const { return m_data->isUnsetValue(); }; |
+ bool isCSSWideKeyword() const { return m_data->isCSSWideKeyword(); }; |
+ bool isLinearGradientValue() const { return m_data->isLinearGradientValue(); }; |
+ bool isPathValue() const { return m_data->isPathValue(); }; |
+ bool isRadialGradientValue() const { return m_data->isRadialGradientValue(); }; |
+ bool isReflectValue() const { return m_data->isReflectValue(); }; |
+ bool isShadowValue() const { return m_data->isShadowValue(); }; |
+ bool isCubicBezierTimingFunctionValue() const { return m_data->isCubicBezierTimingFunctionValue(); }; |
+ bool isStepsTimingFunctionValue() const { return m_data->isStepsTimingFunctionValue(); }; |
+ bool isLineBoxContainValue() const { return m_data->isLineBoxContainValue(); }; |
+ bool isCalcValue() const { return m_data->isCalcValue(); }; |
+ bool isGridTemplateAreasValue() const { return m_data->isGridTemplateAreasValue(); }; |
+ bool isSVGDocumentValue() const { return m_data->isSVGDocumentValue(); }; |
+ bool isContentDistributionValue() const { return m_data->isContentDistributionValue(); }; |
+ bool isUnicodeRangeValue() const { return m_data->isUnicodeRangeValue(); }; |
+ bool isGridLineNamesValue() const { return m_data->isGridLineNamesValue(); }; |
+ |
+ DEFINE_INLINE_TRACE() |
+ { |
+ ASSERT(m_data); |
+ visitor->trace(m_data); |
+ } |
+ |
+ // Only for use by the toFooCSSValue() macros. Don't use this. |
+ // TODO(sashab): Remove this and use value.to<Type> and value.isValid<Type> |
+ // like WebNode. |
+ CSSValueObject* get() const |
+ { |
+ return m_data.get(); |
+ } |
private: |
- void destroy(); |
+ CSSValue() = delete; // compile-time guard |
+ CSSValue(std::nullptr_t) = delete; // compile-time guard |
+ |
+ void ref() const |
+ { |
+#if !ENABLE(OILPAN) |
+ if (m_data) |
+ m_data->ref(); |
+#endif |
+ } |
+ |
+ void deref() const |
+ { |
+#if !ENABLE(OILPAN) |
+ if (m_data) |
+ m_data->deref(); |
+#endif |
+ } |
+ |
+ RawPtrWillBeMember<CSSValueObject> m_data; |
+}; |
+ |
+// A nullable container for CSSValueObject. Contents are the same as CSSValue. |
+// Behavior is similar to a CSSValue*. |
+class CORE_EXPORT NullableCSSValue { |
+ ALLOW_ONLY_INLINE_ALLOCATION(); |
+public: |
+ // Not explicit to allow for casting. |
+ NullableCSSValue() |
+ : m_data(nullptr) |
+ { |
+ } |
+ |
+ NullableCSSValue(const CSSValueObject* cssValueObject) |
+ : m_data(const_cast<CSSValueObject*>(cssValueObject)) |
+ { |
+ ref(); |
+ } |
+ |
+ NullableCSSValue(const CSSValueObject& cssValueObject) |
+ : m_data(const_cast<CSSValueObject*>(&cssValueObject)) |
+ { |
+ ref(); |
+ } |
+ |
+ // TODO(sashab): Remove these; construction should only be available with |
+ // CSSValueObject& or CSSValueObject*. |
+ template <class T> NullableCSSValue(PassRefPtrWillBeRawPtr<T> cssValueObject) |
+ : m_data(cssValueObject.leakRef()) |
+ { |
+ static_assert(WTF::IsSubclass<T, CSSValueObject>::value, "Parameter must be a container for CSSValueObject"); |
+ } |
+ |
+#if !ENABLE(OILPAN) |
+ template <class T> NullableCSSValue(RefPtrWillBeRawPtr<T> cssValueObject) |
+ : m_data(cssValueObject.release().leakRef()) |
+ { |
+ static_assert(WTF::IsSubclass<T, CSSValueObject>::value, "Parameter must be a container for CSSValueObject"); |
+ } |
+#endif |
+ |
+ NullableCSSValue(const NullableCSSValue& cssValue) |
+ : m_data(cssValue.m_data) |
+ { |
+ ref(); |
+ } |
+ |
+ NullableCSSValue(const CSSValue& cssValue) |
+ : m_data(cssValue.m_data) |
+ { |
+ ref(); |
+ } |
+ |
+ ~NullableCSSValue() |
+ { |
+ deref(); |
+ }; |
+ |
+ operator bool() const |
+ { |
+ return m_data; |
+ } |
+ |
+ NullableCSSValue& operator=(const NullableCSSValue& rhs) |
+ { |
+ rhs.ref(); |
+ deref(); |
+ m_data = rhs.m_data; |
+ return *this; |
+ } |
+ |
+ bool operator==(const NullableCSSValue& rhs) |
+ { |
+ return m_data ? rhs.m_data && m_data->equals(*rhs.m_data) : !bool(rhs.m_data); |
+ } |
+ |
+ bool operator!=(const NullableCSSValue& rhs) |
+ { |
+ return !(*this == rhs); |
+ } |
+ |
+ CSSValue& operator*() |
+ { |
+ ASSERT(m_data); |
+ // reinterpret_casts used to avoid ref-churn. |
+ return *reinterpret_cast<CSSValue*>(this); |
+ } |
+ |
+ const CSSValue& operator*() const |
+ { |
+ ASSERT(m_data); |
+ return *reinterpret_cast<const CSSValue*>(this); |
+ } |
+ |
+ CSSValue* operator->() |
+ { |
+ ASSERT(m_data); |
+ return reinterpret_cast<CSSValue*>(this); |
+ } |
+ |
+ const CSSValue* operator->() const |
+ { |
+ ASSERT(m_data); |
+ return reinterpret_cast<const CSSValue*>(this); |
+ } |
-protected: |
- // The bits in this section are only used by specific subclasses but kept here |
- // to maximize struct packing. |
+ void swap(NullableCSSValue& rhs) |
+ { |
+ std::swap(this->m_data, rhs.m_data); |
+ } |
- // CSSPrimitiveValue bits: |
- unsigned m_primitiveUnitType : 7; // CSSPrimitiveValue::UnitType |
- mutable unsigned m_hasCachedCSSText : 1; |
- unsigned m_isQuirkValue : 1; |
+ DEFINE_INLINE_TRACE() |
+ { |
+ visitor->trace(m_data); |
+ } |
- unsigned m_valueListSeparator : ValueListSeparatorBits; |
+ // Only for use by the toFooCSSValue() macros. Don't use this. |
+ // TODO(sashab): Remove this and use value.to<Type> and value.isValid<Type> |
+ // like WebNode. |
+ CSSValueObject* get() const |
+ { |
+ return m_data.get(); |
+ } |
private: |
- unsigned m_classType : ClassTypeBits; // ClassType |
+ void ref() const |
+ { |
+#if !ENABLE(OILPAN) |
+ if (m_data) |
+ m_data->ref(); |
+#endif |
+ } |
+ |
+ void deref() const |
+ { |
+#if !ENABLE(OILPAN) |
+ if (m_data) |
+ m_data->deref(); |
+#endif |
+ } |
+ |
+ RawPtrWillBeMember<CSSValueObject> m_data; |
}; |
-template<typename CSSValueType, size_t inlineCapacity> |
-inline bool compareCSSValueVector(const WillBeHeapVector<RefPtrWillBeMember<CSSValueType>, inlineCapacity>& firstVector, const WillBeHeapVector<RefPtrWillBeMember<CSSValueType>, inlineCapacity>& secondVector) |
+static_assert(sizeof(CSSValue) == sizeof(void*), "CSSValue should be pointer-sized"); |
+static_assert(sizeof(NullableCSSValue) == sizeof(void*), "CSSValue should be pointer-sized"); |
+static_assert(sizeof(CSSValue) == sizeof(NullableCSSValue), "Both CSSValue containers must contain the same data"); |
+ |
+template<size_t inlineCapacity> |
+inline bool compareCSSValueVector(const WillBeHeapVector<CSSValue, inlineCapacity>& firstVector, const WillBeHeapVector<CSSValue, inlineCapacity>& secondVector) |
{ |
size_t size = firstVector.size(); |
if (size != secondVector.size()) |
return false; |
for (size_t i = 0; i < size; i++) { |
- const RefPtrWillBeMember<CSSValueType>& firstPtr = firstVector[i]; |
- const RefPtrWillBeMember<CSSValueType>& secondPtr = secondVector[i]; |
- if (firstPtr == secondPtr || (firstPtr && secondPtr && firstPtr->equals(*secondPtr))) |
+ const CSSValue& firstPtr = firstVector[i]; |
+ const CSSValue& secondPtr = secondVector[i]; |
+ if (firstPtr.ptrEquals(secondPtr) || firstPtr.equals(secondPtr)) |
continue; |
return false; |
} |
return true; |
} |
-template<typename CSSValueType> |
-inline bool compareCSSValuePtr(const RefPtr<CSSValueType>& first, const RefPtr<CSSValueType>& second) |
-{ |
- if (first == second) |
- return true; |
- if (!first || !second) |
- return false; |
- return first->equals(*second); |
-} |
- |
-template<typename CSSValueType> |
-inline bool compareCSSValuePtr(const RawPtr<CSSValueType>& first, const RawPtr<CSSValueType>& second) |
-{ |
- if (first == second) |
- return true; |
- if (!first || !second) |
- return false; |
- return first->equals(*second); |
-} |
- |
-template<typename CSSValueType> |
-inline bool compareCSSValuePtr(const Member<CSSValueType>& first, const Member<CSSValueType>& second) |
-{ |
- if (first == second) |
- return true; |
- if (!first || !second) |
- return false; |
- return first->equals(*second); |
-} |
- |
#define DEFINE_CSS_VALUE_TYPE_CASTS(thisType, predicate) \ |
- DEFINE_TYPE_CASTS(thisType, CSSValue, value, value->predicate, value.predicate) |
+ DEFINE_TYPE_CASTS(thisType, CSSValueObject, value, value->predicate, value.predicate); \ |
+ inline thisType& to##thisType(const CSSValue& value) \ |
+ { \ |
+ ASSERT_WITH_SECURITY_IMPLICATION(value.predicate); \ |
+ return *static_cast<thisType*>(value.get()); \ |
+ } \ |
+ inline thisType* to##thisType(const NullableCSSValue& value) \ |
+ { \ |
+ if (!value) \ |
+ return nullptr; \ |
+ ASSERT_WITH_SECURITY_IMPLICATION(value->predicate); \ |
+ return static_cast<thisType*>(value.get()); \ |
+ } |
} // namespace blink |
+WTF_ALLOW_CLEAR_UNUSED_SLOTS_WITH_MEM_FUNCTIONS(blink::CSSValue); |
+WTF_ALLOW_CLEAR_UNUSED_SLOTS_WITH_MEM_FUNCTIONS(blink::NullableCSSValue); |
+ |
#endif // CSSValue_h |