Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 * (C) 2001 Peter Kelly (pmk@post.com) | 4 * (C) 2001 Peter Kelly (pmk@post.com) |
| 5 * (C) 2001 Dirk Mueller (mueller@kde.org) | 5 * (C) 2001 Dirk Mueller (mueller@kde.org) |
| 6 * (C) 2007 David Smith (catfish.man@gmail.com) | 6 * (C) 2007 David Smith (catfish.man@gmail.com) |
| 7 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2013 Apple Inc. All rights reserved. | 7 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2013 Apple Inc. All rights reserved. |
| 8 * (C) 2007 Eric Seidel (eric@webkit.org) | 8 * (C) 2007 Eric Seidel (eric@webkit.org) |
| 9 * | 9 * |
| 10 * This library is free software; you can redistribute it and/or | 10 * This library is free software; you can redistribute it and/or |
| (...skipping 645 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 656 | 656 |
| 657 if (isStyledElement() && name == HTMLNames::styleAttr) { | 657 if (isStyledElement() && name == HTMLNames::styleAttr) { |
| 658 styleAttributeChanged(newValue); | 658 styleAttributeChanged(newValue); |
| 659 } | 659 } |
| 660 | 660 |
| 661 if (name == HTMLNames::idAttr) { | 661 if (name == HTMLNames::idAttr) { |
| 662 AtomicString oldId = elementData()->idForStyleResolution(); | 662 AtomicString oldId = elementData()->idForStyleResolution(); |
| 663 AtomicString newId = newValue; | 663 AtomicString newId = newValue; |
| 664 if (newId != oldId) { | 664 if (newId != oldId) { |
| 665 elementData()->setIdForStyleResolution(newId); | 665 elementData()->setIdForStyleResolution(newId); |
| 666 if (testShouldInvalidateStyle) | 666 if (testShouldInvalidateStyle && (affectedByIdSelector(oldId) || aff ectedByIdSelector(newId))) |
| 667 styleResolver->ensureUpdatedRuleFeatureSet().scheduleStyleInvali dationForIdChange(oldId, newId, *this); | 667 setNeedsStyleRecalc(LocalStyleChange); |
| 668 } | 668 } |
| 669 } else if (name == HTMLNames::classAttr) { | 669 } else if (name == HTMLNames::classAttr) { |
| 670 classAttributeChanged(newValue); | 670 classAttributeChanged(newValue); |
| 671 } | 671 } |
| 672 | 672 |
| 673 // If there is currently no StyleResolver, we can't be sure that this attrib ute change won't affect style. | 673 // If there is currently no StyleResolver, we can't be sure that this attrib ute change won't affect style. |
| 674 if (!styleResolver) | 674 if (!styleResolver) |
| 675 setNeedsStyleRecalc(SubtreeStyleChange); | 675 setNeedsStyleRecalc(SubtreeStyleChange); |
| 676 } | 676 } |
| 677 | 677 |
| 678 inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason) | 678 inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason) |
| 679 { | 679 { |
| 680 attributeChanged(name, newValue, reason); | 680 attributeChanged(name, newValue, reason); |
| 681 } | 681 } |
| 682 | 682 |
| 683 template <typename CharacterType> | |
| 684 static inline bool classStringHasClassName(const CharacterType* characters, unsi gned length) | |
| 685 { | |
| 686 ASSERT(length > 0); | |
| 687 | |
| 688 unsigned i = 0; | |
| 689 do { | |
| 690 if (isNotHTMLSpace<CharacterType>(characters[i])) | |
| 691 break; | |
| 692 ++i; | |
| 693 } while (i < length); | |
| 694 | |
| 695 return i < length; | |
| 696 } | |
| 697 | |
| 698 static inline bool classStringHasClassName(const AtomicString& newClassString) | |
| 699 { | |
| 700 unsigned length = newClassString.length(); | |
| 701 | |
| 702 if (!length) | |
| 703 return false; | |
| 704 | |
| 705 if (newClassString.is8Bit()) | |
| 706 return classStringHasClassName(newClassString.characters8(), length); | |
| 707 return classStringHasClassName(newClassString.characters16(), length); | |
| 708 } | |
| 709 | |
| 710 void Element::classAttributeChanged(const AtomicString& newClassString) | 683 void Element::classAttributeChanged(const AtomicString& newClassString) |
| 711 { | 684 { |
| 712 StyleResolver* styleResolver = document().styleResolver(); | 685 StyleResolver* styleResolver = document().styleResolver(); |
| 713 bool testShouldInvalidateStyle = inActiveDocument() && styleResolver && styl eChangeType() < SubtreeStyleChange; | 686 bool testShouldInvalidateStyle = inActiveDocument() && styleResolver && styl eChangeType() < SubtreeStyleChange; |
| 714 | 687 |
| 715 ASSERT(elementData()); | 688 ASSERT(elementData()); |
| 716 if (classStringHasClassName(newClassString)) { | 689 const SpaceSplitString oldClasses = elementData()->classNames(); |
|
ojan
2015/01/07 04:03:27
Include in the change description what this was fo
| |
| 717 const SpaceSplitString oldClasses = elementData()->classNames(); | 690 elementData()->setClass(newClassString, false); |
| 718 elementData()->setClass(newClassString, false); | 691 const SpaceSplitString& newClasses = elementData()->classNames(); |
| 719 const SpaceSplitString& newClasses = elementData()->classNames(); | 692 if (testShouldInvalidateStyle && classChangeNeedsStyleRecalc(oldClasses, new Classes)) |
| 720 if (testShouldInvalidateStyle) | 693 setNeedsStyleRecalc(LocalStyleChange); |
| 721 styleResolver->ensureUpdatedRuleFeatureSet().scheduleStyleInvalidati onForClassChange(oldClasses, newClasses, *this); | 694 if (!newClasses.size()) |
| 722 } else { | |
| 723 const SpaceSplitString& oldClasses = elementData()->classNames(); | |
| 724 if (testShouldInvalidateStyle) | |
| 725 styleResolver->ensureUpdatedRuleFeatureSet().scheduleStyleInvalidati onForClassChange(oldClasses, *this); | |
| 726 elementData()->clearClass(); | 695 elementData()->clearClass(); |
| 696 } | |
| 697 | |
| 698 bool Element::classChangeNeedsStyleRecalc(const SpaceSplitString& oldClasses, co nst SpaceSplitString& newClasses) | |
| 699 { | |
| 700 // Class vectors tend to be very short. This is faster than using a hash tab le. | |
| 701 BitVector remainingClassBits; | |
| 702 remainingClassBits.ensureSize(oldClasses.size()); | |
| 703 | |
| 704 for (unsigned i = 0; i < newClasses.size(); ++i) { | |
| 705 bool found = false; | |
| 706 for (unsigned j = 0; j < oldClasses.size(); ++j) { | |
| 707 if (newClasses[i] == oldClasses[j]) { | |
| 708 // Mark each class that is still in the newClasses so we can ski p doing | |
| 709 // an n^2 search below when looking for removals. We can't break from | |
| 710 // this loop early since a class can appear more than once. | |
| 711 remainingClassBits.quickSet(j); | |
| 712 found = true; | |
| 713 } | |
| 714 } | |
| 715 // Class was added. | |
| 716 if (!found && affectedByClassSelector(newClasses[i])) | |
| 717 return true; | |
| 727 } | 718 } |
| 719 | |
| 720 for (unsigned i = 0; i < oldClasses.size(); ++i) { | |
| 721 if (remainingClassBits.quickGet(i)) | |
| 722 continue; | |
| 723 // Class was removed. | |
| 724 if (affectedByClassSelector(oldClasses[i])) | |
| 725 return true; | |
| 726 } | |
| 727 return false; | |
| 728 } | 728 } |
| 729 | 729 |
| 730 bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* el ementShadow, const QualifiedName& name, const AtomicString& newValue) | 730 bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* el ementShadow, const QualifiedName& name, const AtomicString& newValue) |
| 731 { | 731 { |
| 732 ASSERT(elementShadow); | 732 ASSERT(elementShadow); |
| 733 const SelectRuleFeatureSet& featureSet = elementShadow->ensureSelectFeatureS et(); | 733 const SelectRuleFeatureSet& featureSet = elementShadow->ensureSelectFeatureS et(); |
| 734 | 734 |
| 735 if (name == HTMLNames::idAttr) { | 735 if (name == HTMLNames::idAttr) { |
| 736 AtomicString oldId = elementData()->idForStyleResolution(); | 736 AtomicString oldId = elementData()->idForStyleResolution(); |
| 737 AtomicString newId = newValue; | 737 AtomicString newId = newValue; |
| 738 if (newId != oldId) { | 738 if (newId != oldId) { |
| 739 if (!oldId.isEmpty() && featureSet.hasSelectorForId(oldId)) | 739 if (!oldId.isEmpty() && featureSet.hasSelectorForId(oldId)) |
| 740 return true; | 740 return true; |
| 741 if (!newId.isEmpty() && featureSet.hasSelectorForId(newId)) | 741 if (!newId.isEmpty() && featureSet.hasSelectorForId(newId)) |
| 742 return true; | 742 return true; |
| 743 } | 743 } |
| 744 } | 744 } |
| 745 | 745 |
| 746 if (name == HTMLNames::classAttr) { | 746 if (name == HTMLNames::classAttr) { |
| 747 const AtomicString& newClassString = newValue; | 747 const SpaceSplitString& oldClasses = elementData()->classNames(); |
| 748 if (classStringHasClassName(newClassString)) { | 748 const SpaceSplitString newClasses(newValue, false); |
| 749 const SpaceSplitString& oldClasses = elementData()->classNames(); | 749 if (featureSet.checkSelectorsForClassChange(oldClasses, newClasses)) |
| 750 const SpaceSplitString newClasses(newClassString, false); | 750 return true; |
| 751 if (featureSet.checkSelectorsForClassChange(oldClasses, newClasses)) | |
| 752 return true; | |
| 753 } else { | |
| 754 const SpaceSplitString& oldClasses = elementData()->classNames(); | |
| 755 if (featureSet.checkSelectorsForClassChange(oldClasses)) | |
| 756 return true; | |
| 757 } | |
| 758 } | 751 } |
| 759 | 752 |
| 760 return featureSet.hasSelectorForAttribute(name.localName()); | 753 return featureSet.hasSelectorForAttribute(name.localName()); |
| 761 } | 754 } |
| 762 | 755 |
| 763 void Element::parserSetAttributes(const Vector<Attribute>& attributeVector) | 756 void Element::parserSetAttributes(const Vector<Attribute>& attributeVector) |
| 764 { | 757 { |
| 765 ASSERT(!inDocument()); | 758 ASSERT(!inDocument()); |
| 766 ASSERT(!parentNode()); | 759 ASSERT(!parentNode()); |
| 767 ASSERT(!m_elementData); | 760 ASSERT(!m_elementData); |
| (...skipping 786 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1554 scope.addElementById(newId, this); | 1547 scope.addElementById(newId, this); |
| 1555 } | 1548 } |
| 1556 | 1549 |
| 1557 void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue) | 1550 void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue) |
| 1558 { | 1551 { |
| 1559 if (name == HTMLNames::idAttr) { | 1552 if (name == HTMLNames::idAttr) { |
| 1560 updateId(oldValue, newValue); | 1553 updateId(oldValue, newValue); |
| 1561 } | 1554 } |
| 1562 | 1555 |
| 1563 if (oldValue != newValue) { | 1556 if (oldValue != newValue) { |
| 1564 if (inActiveDocument() && document().styleResolver() && styleChangeType( ) < SubtreeStyleChange) | 1557 if (inActiveDocument() && document().styleResolver() && styleChangeType( ) < SubtreeStyleChange && affectedByAttributeSelector(name.localName())) |
| 1565 document().ensureStyleResolver().ensureUpdatedRuleFeatureSet().sched uleStyleInvalidationForAttributeChange(name, *this); | 1558 setNeedsStyleRecalc(LocalStyleChange); |
| 1566 | 1559 |
| 1567 if (isUpgradedCustomElement()) | 1560 if (isUpgradedCustomElement()) |
| 1568 CustomElement::attributeDidChange(this, name.localName(), oldValue, newValue); | 1561 CustomElement::attributeDidChange(this, name.localName(), oldValue, newValue); |
| 1569 } | 1562 } |
| 1570 | 1563 |
| 1571 if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInter estGroup::createForAttributesMutation(*this, name)) | 1564 if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInter estGroup::createForAttributesMutation(*this, name)) |
| 1572 recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue)); | 1565 recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue)); |
| 1573 } | 1566 } |
| 1574 | 1567 |
| 1575 static bool needsURLResolutionForInlineStyle(const Element& element, const Docum ent& oldDocument, const Document& newDocument) | 1568 static bool needsURLResolutionForInlineStyle(const Element& element, const Docum ent& oldDocument, const Document& newDocument) |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1803 } | 1796 } |
| 1804 | 1797 |
| 1805 bool Element::supportsStyleSharing() const | 1798 bool Element::supportsStyleSharing() const |
| 1806 { | 1799 { |
| 1807 if (!isStyledElement() || !parentOrShadowHostElement()) | 1800 if (!isStyledElement() || !parentOrShadowHostElement()) |
| 1808 return false; | 1801 return false; |
| 1809 // If the element has inline style it is probably unique. | 1802 // If the element has inline style it is probably unique. |
| 1810 if (inlineStyle()) | 1803 if (inlineStyle()) |
| 1811 return false; | 1804 return false; |
| 1812 // Ids stop style sharing if they show up in the stylesheets. | 1805 // Ids stop style sharing if they show up in the stylesheets. |
| 1813 if (hasID() && document().ensureStyleResolver().hasRulesForId(idForStyleReso lution())) | 1806 if (hasID() && affectedByIdSelector(idForStyleResolution())) |
| 1814 return false; | 1807 return false; |
| 1815 // :active and :hover elements always make a chain towards the document node | 1808 // :active and :hover elements always make a chain towards the document node |
| 1816 // and no siblings or cousins will have the same state. There's also only on e | 1809 // and no siblings or cousins will have the same state. There's also only on e |
| 1817 // :focus element per scope so we don't need to attempt to share. | 1810 // :focus element per scope so we don't need to attempt to share. |
| 1818 if (isUserActionElement()) | 1811 if (isUserActionElement()) |
| 1819 return false; | 1812 return false; |
| 1820 if (hasActiveAnimations()) | 1813 if (hasActiveAnimations()) |
| 1821 return false; | 1814 return false; |
| 1822 // Turn off style sharing for elements that can gain layers for reasons outs ide of the style system. | 1815 // Turn off style sharing for elements that can gain layers for reasons outs ide of the style system. |
| 1823 // See comments in RenderObject::setStyle(). | 1816 // See comments in RenderObject::setStyle(). |
| 1824 // FIXME: Why does gaining a layer from outside the style system require dis abling sharing? | 1817 // FIXME: Why does gaining a layer from outside the style system require dis abling sharing? |
| 1825 if (isHTMLCanvasElement(*this)) | 1818 if (isHTMLCanvasElement(*this)) |
| 1826 return false; | 1819 return false; |
| 1827 return true; | 1820 return true; |
| 1828 } | 1821 } |
| 1829 | 1822 |
| 1823 bool Element::affectedByAttributeSelector(const AtomicString& attributeName) con st | |
| 1824 { | |
| 1825 if (attributeName.isEmpty()) | |
| 1826 return false; | |
| 1827 // TODO(esprehn): This makes sure the style system is updated, eventually | |
| 1828 // we'll remove all the global lists and this won't be needed. | |
| 1829 document().ensureStyleResolver(); | |
| 1830 if (treeScope().scopedStyleResolver().features().hasSelectorForAttribute(att ributeName)) | |
| 1831 return true; | |
| 1832 // Host rules could also have effects. | |
| 1833 if (ShadowRoot* shadowRoot = this->shadowRoot()) | |
| 1834 return shadowRoot->scopedStyleResolver().features().hasSelectorForAttrib ute(attributeName); | |
| 1835 return false; | |
| 1836 } | |
| 1837 | |
| 1838 bool Element::affectedByClassSelector(const AtomicString& classValue) const | |
| 1839 { | |
| 1840 if (classValue.isEmpty()) | |
| 1841 return false; | |
| 1842 // TODO(esprehn): This makes sure the style system is updated, eventually | |
| 1843 // we'll remove all the global lists and this won't be needed. | |
| 1844 document().ensureStyleResolver(); | |
| 1845 if (treeScope().scopedStyleResolver().features().hasSelectorForClass(classVa lue)) | |
| 1846 return true; | |
| 1847 // Host rules could also have effects. | |
| 1848 if (ShadowRoot* shadowRoot = this->shadowRoot()) | |
| 1849 return shadowRoot->scopedStyleResolver().features().hasSelectorForClass( classValue); | |
| 1850 return false; | |
| 1851 } | |
| 1852 | |
| 1853 bool Element::affectedByIdSelector(const AtomicString& idValue) const | |
| 1854 { | |
| 1855 if (idValue.isEmpty()) | |
| 1856 return false; | |
| 1857 // TODO(esprehn): This makes sure the style system is updated, eventually | |
| 1858 // we'll remove all the global lists and this won't be needed. | |
| 1859 document().ensureStyleResolver(); | |
| 1860 if (treeScope().scopedStyleResolver().features().hasSelectorForId(idValue)) | |
| 1861 return true; | |
| 1862 // Host rules could also have effects. | |
| 1863 if (ShadowRoot* shadowRoot = this->shadowRoot()) | |
| 1864 return shadowRoot->scopedStyleResolver().features().hasSelectorForId(idV alue); | |
| 1865 return false; | |
| 1866 } | |
| 1867 | |
| 1830 } // namespace blink | 1868 } // namespace blink |
| OLD | NEW |