Changeset 143112 in webkit
- Timestamp:
- Feb 16, 2013 2:57:02 PM (11 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r143108 r143112 1 2013-02-16 Andreas Kling <akling@apple.com> 2 3 Element: Avoid unrelated attribute synchronization on other attribute access. 4 <http://webkit.org/b/110025> 5 6 Reviewed by Darin Adler. 7 8 We've been extremely trigger happy with re-serializing the style attribute (and SVG animatables) 9 whenever any Element attribute API was used. This patch narrows this down to (almost always) 10 only synchronizing an attribute when someone specifically wants to read/update it. 11 12 Also removed two more confusing ElementData accessors: 13 14 - Element::elementDataWithSynchronizedAttributes() 15 - Element::ensureElementDataWithSynchronizedAttributes() 16 17 * dom/Element.h: 18 * dom/Element.cpp: 19 (WebCore::Element::hasAttributes): 20 (WebCore::Element::hasEquivalentAttributes): 21 (WebCore::Element::cloneAttributesFromElement): 22 (WebCore::Element::synchronizeAllAttributes): 23 24 Renamed updateInvalidAttributes() to synchronizeAllAttributes(). 25 This function should only be used when we need every single attribute to be up-to-date. 26 27 (WebCore::Element::synchronizeAttribute): 28 29 Broke out logic for synchronizing a specific attribute, given either a full QualifiedName 30 or a localName. 31 32 (WebCore::Element::setSynchronizedLazyAttribute): 33 34 Don't call ensureUniqueElementData() indisciminately here. This avoids converting the attribute 35 storage when re-serializing the inline style yields the same CSS text that was already in the 36 style attribute. 37 38 (WebCore::Element::hasAttribute): 39 (WebCore::Element::hasAttributeNS): 40 (WebCore::Element::getAttribute): 41 (WebCore::Element::getAttributeNode): 42 (WebCore::Element::getAttributeNodeNS): 43 (WebCore::Element::setAttribute): 44 (WebCore::Element::setAttributeNode): 45 (WebCore::Element::removeAttributeNode): 46 47 Only synchronize the attribute in question. 48 49 * dom/Node.cpp: 50 (WebCore::Node::compareDocumentPosition): 51 52 Call synchronizeAllAttributes() when comparing two Attr nodes on the same Element instead 53 of relying on the side-effects of another function doing this. 54 1 55 2013-02-16 Seokju Kwon <seokju.kwon@gmail.com> 2 56 -
trunk/Source/WebCore/dom/Element.cpp
r143089 r143112 95 95 using namespace HTMLNames; 96 96 using namespace XMLNames; 97 98 static inline bool shouldIgnoreAttributeCase(const Element* e) 99 { 100 return e && e->document()->isHTMLDocument() && e->isHTMLElement(); 101 } 97 102 98 103 class StyleResolverParentPusher { … … 332 337 } 333 338 334 const AtomicString& Element::getAttribute(const QualifiedName& name) const339 void Element::synchronizeAllAttributes() const 335 340 { 336 341 if (!elementData()) 337 return nullAtom; 338 339 if (UNLIKELY(name == styleAttr && elementData()->m_styleAttributeIsDirty)) 342 return; 343 if (elementData()->m_styleAttributeIsDirty) 340 344 updateStyleAttribute(); 341 345 #if ENABLE(SVG) 346 if (elementData()->m_animatedSVGAttributesAreDirty) 347 updateAnimatedSVGAttribute(anyQName()); 348 #endif 349 } 350 351 inline void Element::synchronizeAttribute(const QualifiedName& name) const 352 { 353 if (!elementData()) 354 return; 355 if (UNLIKELY(name == styleAttr && elementData()->m_styleAttributeIsDirty)) { 356 updateStyleAttribute(); 357 return; 358 } 342 359 #if ENABLE(SVG) 343 360 if (UNLIKELY(elementData()->m_animatedSVGAttributesAreDirty)) 344 361 updateAnimatedSVGAttribute(name); 345 362 #endif 346 363 } 364 365 inline void Element::synchronizeAttribute(const AtomicString& localName) const 366 { 367 // This version of synchronizeAttribute() is streamlined for the case where you don't have a full QualifiedName, 368 // e.g when called from DOM API. 369 if (!elementData()) 370 return; 371 if (elementData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(localName, styleAttr.localName(), shouldIgnoreAttributeCase(this))) { 372 updateStyleAttribute(); 373 return; 374 } 375 #if ENABLE(SVG) 376 if (elementData()->m_animatedSVGAttributesAreDirty) { 377 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well. 378 updateAnimatedSVGAttribute(QualifiedName(nullAtom, localName, nullAtom)); 379 } 380 #endif 381 } 382 383 const AtomicString& Element::getAttribute(const QualifiedName& name) const 384 { 385 if (!elementData()) 386 return nullAtom; 387 synchronizeAttribute(name); 347 388 if (const Attribute* attribute = getAttributeItem(name)) 348 389 return attribute->value(); … … 699 740 } 700 741 701 static inline bool shouldIgnoreAttributeCase(const Element* e) 702 { 703 return e && e->document()->isHTMLDocument() && e->isHTMLElement(); 704 } 705 706 const AtomicString& Element::getAttribute(const AtomicString& name) const 742 const AtomicString& Element::getAttribute(const AtomicString& localName) const 707 743 { 708 744 if (!elementData()) 709 745 return nullAtom; 710 711 bool ignoreCase = shouldIgnoreAttributeCase(this); 712 713 // Update the 'style' attribute if it's invalid and being requested: 714 if (elementData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(name, styleAttr.localName(), ignoreCase)) 715 updateStyleAttribute(); 716 717 #if ENABLE(SVG) 718 if (elementData()->m_animatedSVGAttributesAreDirty) { 719 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well. 720 updateAnimatedSVGAttribute(QualifiedName(nullAtom, name, nullAtom)); 721 } 722 #endif 723 724 if (const Attribute* attribute = elementData()->getAttributeItem(name, ignoreCase)) 746 synchronizeAttribute(localName); 747 if (const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase(this))) 725 748 return attribute->value(); 726 749 return nullAtom; … … 732 755 } 733 756 734 void Element::setAttribute(const AtomicString& name, const AtomicString& value, ExceptionCode& ec)735 { 736 if (!Document::isValidName( name)) {757 void Element::setAttribute(const AtomicString& localName, const AtomicString& value, ExceptionCode& ec) 758 { 759 if (!Document::isValidName(localName)) { 737 760 ec = INVALID_CHARACTER_ERR; 738 761 return; 739 762 } 740 763 741 const AtomicString& localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; 742 743 size_t index = ensureElementDataWithSynchronizedAttributes()->getAttributeItemIndex(localName, false); 744 const QualifiedName& qName = index != notFound ? attributeItem(index)->name() : QualifiedName(nullAtom, localName, nullAtom); 764 synchronizeAttribute(localName); 765 const AtomicString& caseAdjustedLocalName = shouldIgnoreAttributeCase(this) ? localName.lower() : localName; 766 767 size_t index = elementData() ? elementData()->getAttributeItemIndex(caseAdjustedLocalName, false) : notFound; 768 const QualifiedName& qName = index != notFound ? attributeItem(index)->name() : QualifiedName(nullAtom, caseAdjustedLocalName, nullAtom); 745 769 setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute); 746 770 } … … 748 772 void Element::setAttribute(const QualifiedName& name, const AtomicString& value) 749 773 { 750 setAttributeInternal(ensureElementDataWithSynchronizedAttributes()->getAttributeItemIndex(name), name, value, NotInSynchronizationOfLazyAttribute); 774 synchronizeAttribute(name); 775 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : notFound; 776 setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute); 751 777 } 752 778 753 779 void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value) 754 780 { 755 setAttributeInternal(ensureUniqueElementData()->getAttributeItemIndex(name), name, value, InSynchronizationOfLazyAttribute); 781 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : notFound; 782 setAttributeInternal(index, name, value, InSynchronizationOfLazyAttribute); 756 783 } 757 784 … … 1033 1060 bool Element::hasAttributes() const 1034 1061 { 1035 updateInvalidAttributes();1062 synchronizeAllAttributes(); 1036 1063 return elementData() && elementData()->length(); 1037 1064 } … … 1039 1066 bool Element::hasEquivalentAttributes(const Element* other) const 1040 1067 { 1041 const ElementData* elementData = elementDataWithSynchronizedAttributes();1042 const ElementData* otherElementData = other->elementDataWithSynchronizedAttributes();1043 if (elementData == otherElementData)1068 synchronizeAllAttributes(); 1069 other->synchronizeAllAttributes(); 1070 if (elementData() == other->elementData()) 1044 1071 return true; 1045 if (elementData )1046 return elementData ->isEquivalent(otherElementData);1047 if (other ElementData)1048 return other ElementData->isEquivalent(elementData);1072 if (elementData()) 1073 return elementData()->isEquivalent(other->elementData()); 1074 if (other->elementData()) 1075 return other->elementData()->isEquivalent(elementData()); 1049 1076 return true; 1050 1077 } … … 1686 1713 } 1687 1714 1688 updateInvalidAttributes();1715 synchronizeAllAttributes(); 1689 1716 UniqueElementData* elementData = ensureUniqueElementData(); 1690 1717 … … 1723 1750 ASSERT(document() == attr->document()); 1724 1751 1725 const ElementData* elementData = elementDataWithSynchronizedAttributes(); 1726 ASSERT(elementData); 1727 1728 size_t index = elementData->getAttributeItemIndex(attr->qualifiedName()); 1752 synchronizeAttribute(attr->qualifiedName()); 1753 1754 size_t index = elementData()->getAttributeItemIndex(attr->qualifiedName()); 1729 1755 if (index == notFound) { 1730 1756 ec = NOT_FOUND_ERR; … … 1814 1840 } 1815 1841 1816 PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& name) 1817 { 1818 const ElementData* elementData = elementDataWithSynchronizedAttributes(); 1819 if (!elementData) 1842 PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& localName) 1843 { 1844 if (!elementData()) 1820 1845 return 0; 1821 const Attribute* attribute = elementData->getAttributeItem(name, shouldIgnoreAttributeCase(this)); 1846 synchronizeAttribute(localName); 1847 const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase(this)); 1822 1848 if (!attribute) 1823 1849 return 0; … … 1827 1853 PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName) 1828 1854 { 1829 const ElementData* elementData = elementDataWithSynchronizedAttributes(); 1830 if (!elementData) 1855 if (!elementData()) 1831 1856 return 0; 1832 const Attribute* attribute = elementData->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI)); 1857 QualifiedName qName(nullAtom, localName, namespaceURI); 1858 synchronizeAttribute(qName); 1859 const Attribute* attribute = elementData()->getAttributeItem(qName); 1833 1860 if (!attribute) 1834 1861 return 0; … … 1836 1863 } 1837 1864 1838 bool Element::hasAttribute(const AtomicString& name) const1865 bool Element::hasAttribute(const AtomicString& localName) const 1839 1866 { 1840 1867 if (!elementData()) 1841 1868 return false; 1842 1843 // This call to String::lower() seems to be required but 1844 // there may be a way to remove it. 1845 AtomicString localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; 1846 return elementDataWithSynchronizedAttributes()->getAttributeItem(localName, false); 1869 synchronizeAttribute(localName); 1870 return elementData()->getAttributeItem(shouldIgnoreAttributeCase(this) ? localName.lower() : localName, false); 1847 1871 } 1848 1872 1849 1873 bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const 1850 1874 { 1851 const ElementData* elementData = elementDataWithSynchronizedAttributes(); 1852 if (!elementData) 1875 if (!elementData()) 1853 1876 return false; 1854 return elementData->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI)); 1877 QualifiedName qName(nullAtom, localName, namespaceURI); 1878 synchronizeAttribute(qName); 1879 return elementData()->getAttributeItem(qName); 1855 1880 } 1856 1881 … … 2744 2769 detachAllAttrNodesFromElement(); 2745 2770 2746 other. updateInvalidAttributes();2771 other.synchronizeAllAttributes(); 2747 2772 if (!other.m_elementData) { 2748 2773 m_elementData.clear(); -
trunk/Source/WebCore/dom/Element.h
r143054 r143112 370 370 371 371 const ElementData* elementData() const { return m_elementData.get(); } 372 const ElementData* elementDataWithSynchronizedAttributes() const;373 const ElementData* ensureElementDataWithSynchronizedAttributes() const;374 372 UniqueElementData* ensureUniqueElementData(); 373 374 void synchronizeAllAttributes() const; 375 375 376 376 // Clones attributes only. … … 648 648 void didRemoveAttribute(const QualifiedName&); 649 649 650 void updateInvalidAttributes() const; 650 void synchronizeAttribute(const QualifiedName&) const; 651 void synchronizeAttribute(const AtomicString& localName) const; 651 652 652 653 void scrollByUnits(int units, ScrollGranularity); … … 775 776 } 776 777 777 inline const ElementData* Element::elementDataWithSynchronizedAttributes() const778 {779 updateInvalidAttributes();780 return elementData();781 }782 783 inline const ElementData* Element::ensureElementDataWithSynchronizedAttributes() const784 {785 updateInvalidAttributes();786 if (elementData())787 return elementData();788 return const_cast<Element*>(this)->ensureUniqueElementData();789 }790 791 778 inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName) 792 779 { … … 900 887 ASSERT(elementData()); 901 888 return elementData()->getAttributeItem(name); 902 }903 904 inline void Element::updateInvalidAttributes() const905 {906 if (!elementData())907 return;908 909 if (elementData()->m_styleAttributeIsDirty)910 updateStyleAttribute();911 912 #if ENABLE(SVG)913 if (elementData()->m_animatedSVGAttributesAreDirty)914 updateAnimatedSVGAttribute(anyQName());915 #endif916 889 } 917 890 -
trunk/Source/WebCore/dom/Node.cpp
r142858 r143112 1754 1754 // We are comparing two attributes on the same node. Crawl our attribute map and see which one we hit first. 1755 1755 Element* owner1 = attr1->ownerElement(); 1756 owner1-> elementDataWithSynchronizedAttributes(); // Force update invalid attributes.1756 owner1->synchronizeAllAttributes(); 1757 1757 unsigned length = owner1->attributeCount(); 1758 1758 for (unsigned i = 0; i < length; ++i) {
Note: See TracChangeset
for help on using the changeset viewer.