Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * Copyright (C) 2014 Apple Inc. All rights reserved. | 3 * Copyright (C) 2014 Apple Inc. All rights reserved. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions are | 6 * modification, are permitted provided that the following conditions are |
| 7 * met: | 7 * met: |
| 8 * | 8 * |
| 9 * * Redistributions of source code must retain the above copyright | 9 * * Redistributions of source code must retain the above copyright |
| 10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 37 #include "platform/heap/Handle.h" | 37 #include "platform/heap/Handle.h" |
| 38 #include "wtf/text/AtomicString.h" | 38 #include "wtf/text/AtomicString.h" |
| 39 | 39 |
| 40 namespace WebCore { | 40 namespace WebCore { |
| 41 | 41 |
| 42 class Attr; | 42 class Attr; |
| 43 class ShareableElementData; | 43 class ShareableElementData; |
| 44 class StylePropertySet; | 44 class StylePropertySet; |
| 45 class UniqueElementData; | 45 class UniqueElementData; |
| 46 | 46 |
| 47 class AttributeCollection { | 47 class AttributeCollection { |
|
Inactive
2014/06/26 22:16:40
Ok, I'll move this to a separate file since it is
| |
| 48 public: | 48 public: |
| 49 typedef const Attribute* const_iterator; | 49 typedef const Attribute* const_iterator; |
| 50 | 50 |
| 51 AttributeCollection(const Attribute* array, unsigned size) | 51 AttributeCollection(const Attribute* array, unsigned size) |
| 52 : m_array(array) | 52 : m_array(array) |
| 53 , m_size(size) | 53 , m_size(size) |
| 54 { } | 54 { } |
| 55 | 55 |
| 56 const Attribute& operator[](unsigned index) const { return at(index); } | |
| 57 const Attribute& at(unsigned index) const | |
| 58 { | |
| 59 RELEASE_ASSERT(index < m_size); | |
| 60 return m_array[index]; | |
| 61 } | |
| 62 | |
| 63 const Attribute* get(const QualifiedName&) const; | |
| 64 const Attribute* get(const AtomicString& name, bool shouldIgnoreCase) const; | |
| 65 size_t find(const QualifiedName&, bool shouldIgnoreCase = false) const; | |
| 66 size_t find(const AtomicString& name, bool shouldIgnoreCase) const; | |
| 67 size_t find(Attr*) const; | |
|
esprehn
2014/06/26 22:03:58
We're going to have to be really careful here, ori
Inactive
2014/06/26 22:16:40
To be fair, they were called getAttributeItem() /
| |
| 68 | |
| 56 const_iterator begin() const { return m_array; } | 69 const_iterator begin() const { return m_array; } |
| 57 const_iterator end() const { return m_array + m_size; } | 70 const_iterator end() const { return m_array + m_size; } |
| 58 | 71 |
| 59 unsigned size() const { return m_size; } | 72 unsigned size() const { return m_size; } |
| 73 bool isEmpty() const { return !m_size; } | |
| 60 | 74 |
| 61 private: | 75 private: |
| 76 size_t findSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase ) const; | |
| 77 | |
| 62 const Attribute* m_array; | 78 const Attribute* m_array; |
| 63 unsigned m_size; | 79 unsigned m_size; |
| 64 }; | 80 }; |
| 65 | 81 |
| 66 // ElementData represents very common, but not necessarily unique to an element, | 82 // ElementData represents very common, but not necessarily unique to an element, |
| 67 // data such as attributes, inline style, and parsed class names and ids. | 83 // data such as attributes, inline style, and parsed class names and ids. |
| 68 class ElementData : public RefCountedWillBeGarbageCollectedFinalized<ElementData > { | 84 class ElementData : public RefCountedWillBeGarbageCollectedFinalized<ElementData > { |
| 69 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED; | 85 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED; |
| 70 public: | 86 public: |
| 71 #if ENABLE(OILPAN) | 87 #if ENABLE(OILPAN) |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 82 void setClass(const AtomicString& className, bool shouldFoldCase) const { m_ classNames.set(className, shouldFoldCase); } | 98 void setClass(const AtomicString& className, bool shouldFoldCase) const { m_ classNames.set(className, shouldFoldCase); } |
| 83 const SpaceSplitString& classNames() const { return m_classNames; } | 99 const SpaceSplitString& classNames() const { return m_classNames; } |
| 84 | 100 |
| 85 const AtomicString& idForStyleResolution() const { return m_idForStyleResolu tion; } | 101 const AtomicString& idForStyleResolution() const { return m_idForStyleResolu tion; } |
| 86 void setIdForStyleResolution(const AtomicString& newId) const { m_idForStyle Resolution = newId; } | 102 void setIdForStyleResolution(const AtomicString& newId) const { m_idForStyle Resolution = newId; } |
| 87 | 103 |
| 88 const StylePropertySet* inlineStyle() const { return m_inlineStyle.get(); } | 104 const StylePropertySet* inlineStyle() const { return m_inlineStyle.get(); } |
| 89 | 105 |
| 90 const StylePropertySet* presentationAttributeStyle() const; | 106 const StylePropertySet* presentationAttributeStyle() const; |
| 91 | 107 |
| 92 // This is not a trivial getter and its return value should be cached for pe rformance. | |
| 93 size_t attributeCount() const; | |
| 94 bool hasAttributes() const { return !!attributeCount(); } | |
| 95 | |
| 96 AttributeCollection attributes() const; | 108 AttributeCollection attributes() const; |
| 97 | 109 |
| 98 const Attribute& attributeAt(unsigned index) const; | |
| 99 const Attribute* findAttributeByName(const QualifiedName&) const; | |
| 100 size_t findAttributeIndexByName(const QualifiedName&, bool shouldIgnoreCase = false) const; | |
| 101 size_t findAttributeIndexByName(const AtomicString& name, bool shouldIgnoreA ttributeCase) const; | |
| 102 size_t findAttrNodeIndex(Attr*) const; | |
| 103 | |
| 104 bool hasID() const { return !m_idForStyleResolution.isNull(); } | 110 bool hasID() const { return !m_idForStyleResolution.isNull(); } |
| 105 bool hasClass() const { return !m_classNames.isNull(); } | 111 bool hasClass() const { return !m_classNames.isNull(); } |
| 106 | 112 |
| 107 bool isEquivalent(const ElementData* other) const; | 113 bool isEquivalent(const ElementData* other) const; |
| 108 | 114 |
| 109 bool isUnique() const { return m_isUnique; } | 115 bool isUnique() const { return m_isUnique; } |
| 110 | 116 |
| 111 void traceAfterDispatch(Visitor*); | 117 void traceAfterDispatch(Visitor*); |
| 112 void trace(Visitor*); | 118 void trace(Visitor*); |
| 113 | 119 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 130 private: | 136 private: |
| 131 friend class Element; | 137 friend class Element; |
| 132 friend class ShareableElementData; | 138 friend class ShareableElementData; |
| 133 friend class UniqueElementData; | 139 friend class UniqueElementData; |
| 134 friend class SVGElement; | 140 friend class SVGElement; |
| 135 | 141 |
| 136 #if !ENABLE(OILPAN) | 142 #if !ENABLE(OILPAN) |
| 137 void destroy(); | 143 void destroy(); |
| 138 #endif | 144 #endif |
| 139 | 145 |
| 140 const Attribute* attributeBase() const; | |
| 141 const Attribute* findAttributeByName(const AtomicString& name, bool shouldIg noreAttributeCase) const; | |
| 142 size_t findAttributeIndexByNameSlowCase(const AtomicString& name, bool shoul dIgnoreAttributeCase) const; | |
| 143 | |
| 144 PassRefPtrWillBeRawPtr<UniqueElementData> makeUniqueCopy() const; | 146 PassRefPtrWillBeRawPtr<UniqueElementData> makeUniqueCopy() const; |
| 145 }; | 147 }; |
| 146 | 148 |
| 147 #if COMPILER(MSVC) | 149 #if COMPILER(MSVC) |
| 148 #pragma warning(push) | 150 #pragma warning(push) |
| 149 #pragma warning(disable: 4200) // Disable "zero-sized array in struct/union" war ning | 151 #pragma warning(disable: 4200) // Disable "zero-sized array in struct/union" war ning |
| 150 #endif | 152 #endif |
| 151 | 153 |
| 152 // SharableElementData is managed by ElementDataCache and is produced by | 154 // SharableElementData is managed by ElementDataCache and is produced by |
| 153 // the parser during page load for elements that have identical attributes. This | 155 // the parser during page load for elements that have identical attributes. This |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 166 // Add support for placement new as ShareableElementData is not allocated | 168 // Add support for placement new as ShareableElementData is not allocated |
| 167 // with a fixed size. Instead the allocated memory size is computed based on | 169 // with a fixed size. Instead the allocated memory size is computed based on |
| 168 // the number of attributes. This requires us to use Heap::allocate directly | 170 // the number of attributes. This requires us to use Heap::allocate directly |
| 169 // with the computed size and subsequently call placement new with the | 171 // with the computed size and subsequently call placement new with the |
| 170 // allocated memory address. | 172 // allocated memory address. |
| 171 void* operator new(std::size_t, void* location) | 173 void* operator new(std::size_t, void* location) |
| 172 { | 174 { |
| 173 return location; | 175 return location; |
| 174 } | 176 } |
| 175 | 177 |
| 178 AttributeCollection attributes() const; | |
| 179 | |
| 176 Attribute m_attributeArray[0]; | 180 Attribute m_attributeArray[0]; |
| 177 }; | 181 }; |
| 178 | 182 |
| 179 #if COMPILER(MSVC) | 183 #if COMPILER(MSVC) |
| 180 #pragma warning(pop) | 184 #pragma warning(pop) |
| 181 #endif | 185 #endif |
| 182 | 186 |
| 183 // UniqueElementData is created when an element needs to mutate its attributes | 187 // UniqueElementData is created when an element needs to mutate its attributes |
| 184 // or gains presentation attribute style (ex. width="10"). It does not need to | 188 // or gains presentation attribute style (ex. width="10"). It does not need to |
| 185 // be created to fill in values in the ElementData that are derived from | 189 // be created to fill in values in the ElementData that are derived from |
| 186 // attributes. For example populating the m_inlineStyle from the style attribute | 190 // attributes. For example populating the m_inlineStyle from the style attribute |
| 187 // doesn't require a UniqueElementData as all elements with the same style | 191 // doesn't require a UniqueElementData as all elements with the same style |
| 188 // attribute will have the same inline style. | 192 // attribute will have the same inline style. |
| 189 class UniqueElementData FINAL : public ElementData { | 193 class UniqueElementData FINAL : public ElementData { |
| 190 public: | 194 public: |
| 191 static PassRefPtrWillBeRawPtr<UniqueElementData> create(); | 195 static PassRefPtrWillBeRawPtr<UniqueElementData> create(); |
| 192 PassRefPtrWillBeRawPtr<ShareableElementData> makeShareableCopy() const; | 196 PassRefPtrWillBeRawPtr<ShareableElementData> makeShareableCopy() const; |
| 193 | 197 |
| 194 // These functions do no error/duplicate checking. | 198 // These functions do no error/duplicate checking. |
| 195 void appendAttribute(const QualifiedName&, const AtomicString&); | 199 void appendAttribute(const QualifiedName&, const AtomicString&); |
| 196 void removeAttributeAt(size_t index); | 200 void removeAttributeAt(size_t index); |
| 197 | 201 |
| 202 AttributeCollection attributes() const; | |
| 203 | |
| 198 Attribute& attributeAt(unsigned index); | 204 Attribute& attributeAt(unsigned index); |
| 199 Attribute* findAttributeByName(const QualifiedName&); | 205 Attribute* findAttributeByName(const QualifiedName&); |
| 200 | 206 |
| 201 UniqueElementData(); | 207 UniqueElementData(); |
| 202 explicit UniqueElementData(const ShareableElementData&); | 208 explicit UniqueElementData(const ShareableElementData&); |
| 203 explicit UniqueElementData(const UniqueElementData&); | 209 explicit UniqueElementData(const UniqueElementData&); |
| 204 | 210 |
| 205 void traceAfterDispatch(Visitor*); | 211 void traceAfterDispatch(Visitor*); |
| 206 | 212 |
| 207 // FIXME: We might want to support sharing element data for elements with | 213 // FIXME: We might want to support sharing element data for elements with |
| 208 // presentation attribute style. Lots of table cells likely have the same | 214 // presentation attribute style. Lots of table cells likely have the same |
| 209 // attributes. Most modern pages don't use presentation attributes though | 215 // attributes. Most modern pages don't use presentation attributes though |
| 210 // so this might not make sense. | 216 // so this might not make sense. |
| 211 mutable RefPtrWillBeMember<StylePropertySet> m_presentationAttributeStyle; | 217 mutable RefPtrWillBeMember<StylePropertySet> m_presentationAttributeStyle; |
| 212 Vector<Attribute, 4> m_attributeVector; | 218 Vector<Attribute, 4> m_attributeVector; |
| 213 }; | 219 }; |
| 214 | 220 |
| 215 #if !ENABLE(OILPAN) | 221 #if !ENABLE(OILPAN) |
| 216 inline void ElementData::deref() | 222 inline void ElementData::deref() |
| 217 { | 223 { |
| 218 if (!derefBase()) | 224 if (!derefBase()) |
| 219 return; | 225 return; |
| 220 destroy(); | 226 destroy(); |
| 221 } | 227 } |
| 222 #endif | 228 #endif |
| 223 | 229 |
| 224 inline size_t ElementData::attributeCount() const | |
| 225 { | |
| 226 if (isUnique()) | |
| 227 return static_cast<const UniqueElementData*>(this)->m_attributeVector.si ze(); | |
| 228 return m_arraySize; | |
| 229 } | |
| 230 | |
| 231 inline const StylePropertySet* ElementData::presentationAttributeStyle() const | 230 inline const StylePropertySet* ElementData::presentationAttributeStyle() const |
| 232 { | 231 { |
| 233 if (!m_isUnique) | 232 if (!m_isUnique) |
| 234 return 0; | 233 return 0; |
| 235 return static_cast<const UniqueElementData*>(this)->m_presentationAttributeS tyle.get(); | 234 return static_cast<const UniqueElementData*>(this)->m_presentationAttributeS tyle.get(); |
| 236 } | 235 } |
| 237 | 236 |
| 238 inline const Attribute* ElementData::findAttributeByName(const AtomicString& nam e, bool shouldIgnoreAttributeCase) const | 237 inline const Attribute* AttributeCollection::get(const AtomicString& name, bool shouldIgnoreCase) const |
| 239 { | 238 { |
| 240 size_t index = findAttributeIndexByName(name, shouldIgnoreAttributeCase); | 239 size_t index = find(name, shouldIgnoreCase); |
| 241 if (index != kNotFound) | 240 return index != kNotFound ? &at(index) : 0; |
| 242 return &attributeAt(index); | |
| 243 return 0; | |
| 244 } | 241 } |
| 245 | 242 |
| 246 inline const Attribute* ElementData::attributeBase() const | 243 inline size_t AttributeCollection::find(const QualifiedName& name, bool shouldIg noreCase) const |
| 247 { | 244 { |
| 248 if (m_isUnique) | 245 const_iterator end = this->end(); |
| 249 return static_cast<const UniqueElementData*>(this)->m_attributeVector.be gin(); | |
| 250 return static_cast<const ShareableElementData*>(this)->m_attributeArray; | |
| 251 } | |
| 252 | |
| 253 inline size_t ElementData::findAttributeIndexByName(const QualifiedName& name, b ool shouldIgnoreCase) const | |
| 254 { | |
| 255 AttributeCollection attributes = this->attributes(); | |
| 256 AttributeCollection::const_iterator end = attributes.end(); | |
| 257 unsigned index = 0; | 246 unsigned index = 0; |
| 258 for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it, ++index) { | 247 for (const_iterator it = begin(); it != end; ++it, ++index) { |
| 259 if (it->name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase)) | 248 if (it->name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase)) |
| 260 return index; | 249 return index; |
| 261 } | 250 } |
| 262 return kNotFound; | 251 return kNotFound; |
| 263 } | 252 } |
| 264 | 253 |
| 265 // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so th at the caller | 254 // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so th at the caller |
| 266 // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not). | 255 // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not). |
| 267 inline size_t ElementData::findAttributeIndexByName(const AtomicString& name, bo ol shouldIgnoreAttributeCase) const | 256 inline size_t AttributeCollection::find(const AtomicString& name, bool shouldIgn oreCase) const |
| 268 { | 257 { |
| 269 bool doSlowCheck = shouldIgnoreAttributeCase; | 258 bool doSlowCheck = shouldIgnoreCase; |
| 270 | 259 |
| 271 // Optimize for the case where the attribute exists and its name exactly mat ches. | 260 // Optimize for the case where the attribute exists and its name exactly mat ches. |
| 272 AttributeCollection attributes = this->attributes(); | 261 const_iterator end = this->end(); |
| 273 AttributeCollection::const_iterator end = attributes.end(); | |
| 274 unsigned index = 0; | 262 unsigned index = 0; |
| 275 for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it, ++index) { | 263 for (const_iterator it = begin(); it != end; ++it, ++index) { |
| 276 // FIXME: Why check the prefix? Namespaces should be all that matter. | 264 // FIXME: Why check the prefix? Namespaces should be all that matter. |
| 277 // Most attributes (all of HTML and CSS) have no namespace. | 265 // Most attributes (all of HTML and CSS) have no namespace. |
| 278 if (!it->name().hasPrefix()) { | 266 if (!it->name().hasPrefix()) { |
| 279 if (name == it->localName()) | 267 if (name == it->localName()) |
| 280 return index; | 268 return index; |
| 281 } else { | 269 } else { |
| 282 doSlowCheck = true; | 270 doSlowCheck = true; |
| 283 } | 271 } |
| 284 } | 272 } |
| 285 | 273 |
| 286 if (doSlowCheck) | 274 if (doSlowCheck) |
| 287 return findAttributeIndexByNameSlowCase(name, shouldIgnoreAttributeCase) ; | 275 return findSlowCase(name, shouldIgnoreCase); |
| 288 return kNotFound; | 276 return kNotFound; |
| 289 } | 277 } |
| 290 | 278 |
| 291 inline AttributeCollection ElementData::attributes() const | 279 inline AttributeCollection ElementData::attributes() const |
| 292 { | 280 { |
| 293 if (isUnique()) { | 281 if (isUnique()) |
| 294 const Vector<Attribute, 4>& attributeVector = static_cast<const UniqueEl ementData*>(this)->m_attributeVector; | 282 return static_cast<const UniqueElementData*>(this)->attributes(); |
| 295 return AttributeCollection(attributeVector.data(), attributeVector.size( )); | 283 return static_cast<const ShareableElementData*>(this)->attributes(); |
| 296 } | |
| 297 return AttributeCollection(static_cast<const ShareableElementData*>(this)->m _attributeArray, m_arraySize); | |
| 298 } | 284 } |
| 299 | 285 |
| 300 inline const Attribute* ElementData::findAttributeByName(const QualifiedName& na me) const | 286 inline AttributeCollection ShareableElementData::attributes() const |
| 301 { | 287 { |
| 302 AttributeCollection attributes = this->attributes(); | 288 return AttributeCollection(m_attributeArray, m_arraySize); |
| 303 AttributeCollection::const_iterator end = attributes.end(); | 289 } |
| 304 for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it) { | 290 |
| 291 inline AttributeCollection UniqueElementData::attributes() const | |
| 292 { | |
| 293 return AttributeCollection(m_attributeVector.data(), m_attributeVector.size( )); | |
| 294 } | |
| 295 | |
| 296 inline const Attribute* AttributeCollection::get(const QualifiedName& name) cons t | |
| 297 { | |
| 298 const_iterator end = this->end(); | |
| 299 for (const_iterator it = begin(); it != end; ++it) { | |
| 305 if (it->name().matches(name)) | 300 if (it->name().matches(name)) |
| 306 return it; | 301 return it; |
| 307 } | 302 } |
| 308 return 0; | 303 return 0; |
| 309 } | 304 } |
| 310 | 305 |
| 311 inline const Attribute& ElementData::attributeAt(unsigned index) const | |
| 312 { | |
| 313 RELEASE_ASSERT(index < attributeCount()); | |
| 314 ASSERT(attributeBase() + index); | |
| 315 return *(attributeBase() + index); | |
| 316 } | |
| 317 | |
| 318 inline void UniqueElementData::appendAttribute(const QualifiedName& attributeNam e, const AtomicString& value) | 306 inline void UniqueElementData::appendAttribute(const QualifiedName& attributeNam e, const AtomicString& value) |
| 319 { | 307 { |
| 320 m_attributeVector.append(Attribute(attributeName, value)); | 308 m_attributeVector.append(Attribute(attributeName, value)); |
| 321 } | 309 } |
| 322 | 310 |
| 323 inline void UniqueElementData::removeAttributeAt(size_t index) | 311 inline void UniqueElementData::removeAttributeAt(size_t index) |
| 324 { | 312 { |
| 325 m_attributeVector.remove(index); | 313 m_attributeVector.remove(index); |
| 326 } | 314 } |
| 327 | 315 |
| 328 inline Attribute& UniqueElementData::attributeAt(unsigned index) | 316 inline Attribute& UniqueElementData::attributeAt(unsigned index) |
| 329 { | 317 { |
| 330 return m_attributeVector.at(index); | 318 return m_attributeVector.at(index); |
| 331 } | 319 } |
| 332 | 320 |
| 333 } // namespace WebCore | 321 } // namespace WebCore |
| 334 | 322 |
| 335 #endif // ElementData_h | 323 #endif // ElementData_h |
| OLD | NEW |