summaryrefslogtreecommitdiff
path: root/Source/WebCore/dom/Element.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/dom/Element.cpp')
-rw-r--r--Source/WebCore/dom/Element.cpp325
1 files changed, 176 insertions, 149 deletions
diff --git a/Source/WebCore/dom/Element.cpp b/Source/WebCore/dom/Element.cpp
index a4f7d72af..b7d0e5993 100644
--- a/Source/WebCore/dom/Element.cpp
+++ b/Source/WebCore/dom/Element.cpp
@@ -305,18 +305,19 @@ bool Element::hasAttribute(const QualifiedName& name) const
const AtomicString& Element::getAttribute(const QualifiedName& name) const
{
- if (UNLIKELY(name == styleAttr) && attributeData() && attributeData()->m_styleAttributeIsDirty)
+ if (!attributeData())
+ return nullAtom;
+
+ if (UNLIKELY(name == styleAttr && attributeData()->m_styleAttributeIsDirty))
updateStyleAttribute();
#if ENABLE(SVG)
- if (UNLIKELY(!areSVGAttributesValid()))
+ if (UNLIKELY(attributeData()->m_animatedSVGAttributesAreDirty))
updateAnimatedSVGAttribute(name);
#endif
- if (attributeData()) {
- if (const Attribute* attribute = getAttributeItem(name))
- return attribute->value();
- }
+ if (const Attribute* attribute = getAttributeItem(name))
+ return attribute->value();
return nullAtom;
}
@@ -660,24 +661,24 @@ static inline bool shouldIgnoreAttributeCase(const Element* e)
const AtomicString& Element::getAttribute(const AtomicString& name) const
{
+ if (!attributeData())
+ return nullAtom;
+
bool ignoreCase = shouldIgnoreAttributeCase(this);
// Update the 'style' attribute if it's invalid and being requested:
- if (attributeData() && attributeData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(name, styleAttr.localName(), ignoreCase))
+ if (attributeData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(name, styleAttr.localName(), ignoreCase))
updateStyleAttribute();
#if ENABLE(SVG)
- if (!areSVGAttributesValid()) {
+ if (attributeData()->m_animatedSVGAttributesAreDirty) {
// We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
updateAnimatedSVGAttribute(QualifiedName(nullAtom, name, nullAtom));
}
#endif
- if (attributeData()) {
- if (const Attribute* attribute = attributeData()->getAttributeItem(name, ignoreCase))
- return attribute->value();
- }
-
+ if (const Attribute* attribute = attributeData()->getAttributeItem(name, ignoreCase))
+ return attribute->value();
return nullAtom;
}
@@ -824,49 +825,23 @@ static inline bool classStringHasClassName(const AtomicString& newClassString)
return classStringHasClassName(newClassString.characters16(), length);
}
-struct HasSelectorForClassStyleFunctor {
- explicit HasSelectorForClassStyleFunctor(StyleResolver* resolver)
- : styleResolver(resolver)
- { }
-
- bool operator()(const AtomicString& className) const
- {
- return styleResolver->hasSelectorForClass(className);
- }
-
- StyleResolver* styleResolver;
-};
-
-struct HasSelectorForClassDistributionFunctor {
- explicit HasSelectorForClassDistributionFunctor(ElementShadow* elementShadow)
- : elementShadow(elementShadow)
- { }
-
- bool operator()(const AtomicString& className) const
- {
- return elementShadow->selectRuleFeatureSet().hasSelectorForClass(className);
- }
-
- ElementShadow* elementShadow;
-};
-
-template<typename Functor>
-static bool checkFunctorForClassChange(const SpaceSplitString& changedClasses, Functor functor)
+template<typename Checker>
+static bool checkSelectorForClassChange(const SpaceSplitString& changedClasses, const Checker& checker)
{
unsigned changedSize = changedClasses.size();
for (unsigned i = 0; i < changedSize; ++i) {
- if (functor(changedClasses[i]))
+ if (checker.hasSelectorForClass(changedClasses[i]))
return true;
}
return false;
}
-template<typename Functor>
-static bool checkFunctorForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, Functor functor)
+template<typename Checker>
+static bool checkSelectorForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, const Checker& checker)
{
unsigned oldSize = oldClasses.size();
if (!oldSize)
- return checkFunctorForClassChange(newClasses, functor);
+ return checkSelectorForClassChange(newClasses, checker);
BitVector remainingClassBits;
remainingClassBits.ensureSize(oldSize);
// Class vectors tend to be very short. This is faster than using a hash table.
@@ -878,39 +853,19 @@ static bool checkFunctorForClassChange(const SpaceSplitString& oldClasses, const
continue;
}
}
- if (functor(newClasses[i]))
+ if (checker.hasSelectorForClass(newClasses[i]))
return true;
}
for (unsigned i = 0; i < oldSize; ++i) {
// If the bit is not set the the corresponding class has been removed.
if (remainingClassBits.quickGet(i))
continue;
- if (functor(oldClasses[i]))
+ if (checker.hasSelectorForClass(oldClasses[i]))
return true;
}
return false;
}
-static inline bool checkNeedsStyleInvalidationForClassChange(const SpaceSplitString& changedClasses, StyleResolver* styleResolver)
-{
- return checkFunctorForClassChange(changedClasses, HasSelectorForClassStyleFunctor(styleResolver));
-}
-
-static inline bool checkNeedsStyleInvalidationForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, StyleResolver* styleResolver)
-{
- return checkFunctorForClassChange(oldClasses, newClasses, HasSelectorForClassStyleFunctor(styleResolver));
-}
-
-static inline bool checkNeedsDistributionInvalidationForClassChange(const SpaceSplitString& changedClasses, ElementShadow* elementShadow)
-{
- return checkFunctorForClassChange(changedClasses, HasSelectorForClassDistributionFunctor(elementShadow));
-}
-
-static inline bool checkNeedsDistributionInvalidationForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, ElementShadow* elementShadow)
-{
- return checkFunctorForClassChange(oldClasses, newClasses, HasSelectorForClassDistributionFunctor(elementShadow));
-}
-
void Element::classAttributeChanged(const AtomicString& newClassString)
{
StyleResolver* styleResolver = document()->styleResolverIfExists();
@@ -925,10 +880,10 @@ void Element::classAttributeChanged(const AtomicString& newClassString)
attributeData->setClass(newClassString, shouldFoldCase);
const SpaceSplitString& newClasses = attributeData->classNames();
- shouldInvalidateStyle = testShouldInvalidateStyle && checkNeedsStyleInvalidationForClassChange(oldClasses, newClasses, styleResolver);
+ shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, newClasses, *styleResolver);
} else if (const ElementAttributeData* attributeData = this->attributeData()) {
const SpaceSplitString& oldClasses = attributeData->classNames();
- shouldInvalidateStyle = testShouldInvalidateStyle && checkNeedsStyleInvalidationForClassChange(oldClasses, styleResolver);
+ shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, *styleResolver);
attributeData->clearClass();
}
@@ -963,11 +918,11 @@ bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* el
const bool shouldFoldCase = document()->inQuirksMode();
const SpaceSplitString& oldClasses = attributeData->classNames();
const SpaceSplitString newClasses(newClassString, shouldFoldCase);
- if (checkNeedsDistributionInvalidationForClassChange(oldClasses, newClasses, elementShadow))
+ if (checkSelectorForClassChange(oldClasses, newClasses, elementShadow->selectRuleFeatureSet()))
return true;
} else if (const ElementAttributeData* attributeData = this->attributeData()) {
const SpaceSplitString& oldClasses = attributeData->classNames();
- if (checkNeedsDistributionInvalidationForClassChange(oldClasses, elementShadow))
+ if (checkSelectorForClassChange(oldClasses, elementShadow->selectRuleFeatureSet()))
return true;
}
}
@@ -1197,34 +1152,34 @@ void Element::createRendererIfNeeded()
void Element::attach()
{
suspendPostAttachCallbacks();
- WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
-
- createRendererIfNeeded();
+ {
+ WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
+ createRendererIfNeeded();
- StyleResolverParentPusher parentPusher(this);
+ StyleResolverParentPusher parentPusher(this);
- if (parentElement() && parentElement()->isInCanvasSubtree())
- setIsInCanvasSubtree(true);
+ if (parentElement() && parentElement()->isInCanvasSubtree())
+ setIsInCanvasSubtree(true);
- // When a shadow root exists, it does the work of attaching the children.
- if (ElementShadow* shadow = this->shadow()) {
- parentPusher.push();
- shadow->attach();
- } else {
- if (firstChild())
+ // When a shadow root exists, it does the work of attaching the children.
+ if (ElementShadow* shadow = this->shadow()) {
parentPusher.push();
- }
- ContainerNode::attach();
+ shadow->attach();
+ } else {
+ if (firstChild())
+ parentPusher.push();
+ }
+ ContainerNode::attach();
- if (hasRareData()) {
- ElementRareData* data = elementRareData();
- if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
- if (isFocusable() && document()->focusedNode() == this)
- document()->updateFocusAppearanceSoon(false /* don't restore selection */);
- data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
+ if (hasRareData()) {
+ ElementRareData* data = elementRareData();
+ if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
+ if (isFocusable() && document()->focusedNode() == this)
+ document()->updateFocusAppearanceSoon(false /* don't restore selection */);
+ data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
+ }
}
}
-
resumePostAttachCallbacks();
}
@@ -1243,6 +1198,7 @@ void Element::detach()
ElementRareData* data = elementRareData();
data->setIsInCanvasSubtree(false);
data->resetComputedStyle();
+ data->resetDynamicRestyleObservations();
}
if (ElementShadow* shadow = this->shadow()) {
@@ -1310,15 +1266,12 @@ void Element::recalcStyle(StyleChange change)
// Ref currentStyle in case it would otherwise be deleted when setting the new style in the renderer.
RefPtr<RenderStyle> currentStyle(renderStyle());
bool hasParentStyle = parentNodeForRenderingAndStyle() ? static_cast<bool>(parentNodeForRenderingAndStyle()->renderStyle()) : false;
- bool hasDirectAdjacentRules = currentStyle && currentStyle->childrenAffectedByDirectAdjacentRules();
- bool hasIndirectAdjacentRules = currentStyle && currentStyle->childrenAffectedByForwardPositionalRules();
+ bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
+ bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
if ((change > NoChange || needsStyleRecalc())) {
- if (hasRareData()) {
- ElementRareData* data = elementRareData();
- data->resetComputedStyle();
- data->setStyleAffectedByEmpty(false);
- }
+ if (hasRareData())
+ elementRareData()->resetComputedStyle();
}
if (hasParentStyle && (change >= Inherit || needsStyleRecalc())) {
RefPtr<RenderStyle> newStyle = styleForRenderer();
@@ -1335,27 +1288,6 @@ void Element::recalcStyle(StyleChange change)
return;
}
- if (currentStyle) {
- // Preserve "affected by" bits that were propagated to us from descendants in the case where we didn't do a full
- // style change (e.g., only inline style changed).
- if (currentStyle->affectedByHoverRules())
- newStyle->setAffectedByHoverRules(true);
- if (currentStyle->affectedByActiveRules())
- newStyle->setAffectedByActiveRules(true);
- if (currentStyle->affectedByDragRules())
- newStyle->setAffectedByDragRules(true);
- if (currentStyle->childrenAffectedByForwardPositionalRules())
- newStyle->setChildrenAffectedByForwardPositionalRules();
- if (currentStyle->childrenAffectedByBackwardPositionalRules())
- newStyle->setChildrenAffectedByBackwardPositionalRules();
- if (currentStyle->childrenAffectedByFirstChildRules())
- newStyle->setChildrenAffectedByFirstChildRules();
- if (currentStyle->childrenAffectedByLastChildRules())
- newStyle->setChildrenAffectedByLastChildRules();
- if (currentStyle->childrenAffectedByDirectAdjacentRules())
- newStyle->setChildrenAffectedByDirectAdjacentRules();
- }
-
if (RenderObject* renderer = this->renderer()) {
if (ch != NoChange || pseudoStyleCacheIsInvalid(currentStyle.get(), newStyle.get()) || (change == Force && renderer->requiresForcedStyleRecalcPropagation()) || styleChangeType() == SyntheticStyleChange)
renderer->setAnimatableStyle(newStyle.get());
@@ -1483,7 +1415,7 @@ static void checkForEmptyStyleChange(Element* element, RenderStyle* style)
if (!style && !element->styleAffectedByEmpty())
return;
- if (!style || (style->affectedByEmpty() && (!style->emptyState() || element->hasChildNodes())))
+ if (!style || (element->styleAffectedByEmpty() && (!style->emptyState() || element->hasChildNodes())))
element->setNeedsStyleRecalc();
}
@@ -1493,13 +1425,13 @@ static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool fin
// :empty selector.
checkForEmptyStyleChange(e, style);
- if (!style || (e->needsStyleRecalc() && style->childrenAffectedByPositionalRules()))
+ if (!style || (e->needsStyleRecalc() && e->childrenAffectedByPositionalRules()))
return;
// :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
// In the DOM case, we only need to do something if |afterChange| is not 0.
// |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
- if (style->childrenAffectedByFirstChildRules() && afterChange) {
+ if (e->childrenAffectedByFirstChildRules() && afterChange) {
// Find our new first child.
Node* newFirstChild = 0;
for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {};
@@ -1522,7 +1454,7 @@ static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool fin
// :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
// In the DOM case, we only need to do something if |afterChange| is not 0.
- if (style->childrenAffectedByLastChildRules() && beforeChange) {
+ if (e->childrenAffectedByLastChildRules() && beforeChange) {
// Find our new last child.
Node* newLastChild = 0;
for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {};
@@ -1545,7 +1477,7 @@ static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool fin
// The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
// that could be affected by this DOM change.
- if (style->childrenAffectedByDirectAdjacentRules() && afterChange) {
+ if (e->childrenAffectedByDirectAdjacentRules() && afterChange) {
Node* firstElementAfterInsertion = 0;
for (firstElementAfterInsertion = afterChange;
firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
@@ -1561,8 +1493,8 @@ static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool fin
// |afterChange| is 0 in the parser callback case, so we won't do any work for the forward case if we don't have to.
// For performance reasons we just mark the parent node as changed, since we don't want to make childrenChanged O(n^2) by crawling all our kids
// here. recalcStyle will then force a walk of the children when it sees that this has happened.
- if ((style->childrenAffectedByForwardPositionalRules() && afterChange) ||
- (style->childrenAffectedByBackwardPositionalRules() && beforeChange))
+ if ((e->childrenAffectedByForwardPositionalRules() && afterChange)
+ || (e->childrenAffectedByBackwardPositionalRules() && beforeChange))
e->setNeedsStyleRecalc();
}
@@ -1969,9 +1901,115 @@ void Element::setStyleAffectedByEmpty()
ensureElementRareData()->setStyleAffectedByEmpty(true);
}
-bool Element::styleAffectedByEmpty() const
+void Element::setChildrenAffectedByHover(bool value)
+{
+ if (value || hasRareData())
+ ensureElementRareData()->setChildrenAffectedByHover(value);
+}
+
+void Element::setChildrenAffectedByActive(bool value)
+{
+ if (value || hasRareData())
+ ensureElementRareData()->setChildrenAffectedByActive(value);
+}
+
+void Element::setChildrenAffectedByDrag(bool value)
+{
+ if (value || hasRareData())
+ ensureElementRareData()->setChildrenAffectedByDrag(value);
+}
+
+void Element::setChildrenAffectedByFirstChildRules()
+{
+ ensureElementRareData()->setChildrenAffectedByFirstChildRules(true);
+}
+
+void Element::setChildrenAffectedByLastChildRules()
+{
+ ensureElementRareData()->setChildrenAffectedByLastChildRules(true);
+}
+
+void Element::setChildrenAffectedByDirectAdjacentRules()
+{
+ ensureElementRareData()->setChildrenAffectedByDirectAdjacentRules(true);
+}
+
+void Element::setChildrenAffectedByForwardPositionalRules()
+{
+ ensureElementRareData()->setChildrenAffectedByForwardPositionalRules(true);
+}
+
+void Element::setChildrenAffectedByBackwardPositionalRules()
+{
+ ensureElementRareData()->setChildrenAffectedByBackwardPositionalRules(true);
+}
+
+void Element::setChildIndex(unsigned index)
+{
+ ElementRareData* rareData = ensureElementRareData();
+ if (RenderStyle* style = renderStyle())
+ style->setUnique();
+ rareData->setChildIndex(index);
+}
+
+bool Element::rareDataStyleAffectedByEmpty() const
+{
+ ASSERT(hasRareData());
+ return elementRareData()->styleAffectedByEmpty();
+}
+
+bool Element::rareDataChildrenAffectedByHover() const
+{
+ ASSERT(hasRareData());
+ return elementRareData()->childrenAffectedByHover();
+}
+
+bool Element::rareDataChildrenAffectedByActive() const
+{
+ ASSERT(hasRareData());
+ return elementRareData()->childrenAffectedByActive();
+}
+
+bool Element::rareDataChildrenAffectedByDrag() const
+{
+ ASSERT(hasRareData());
+ return elementRareData()->childrenAffectedByDrag();
+}
+
+bool Element::rareDataChildrenAffectedByFirstChildRules() const
+{
+ ASSERT(hasRareData());
+ return elementRareData()->childrenAffectedByFirstChildRules();
+}
+
+bool Element::rareDataChildrenAffectedByLastChildRules() const
+{
+ ASSERT(hasRareData());
+ return elementRareData()->childrenAffectedByLastChildRules();
+}
+
+bool Element::rareDataChildrenAffectedByDirectAdjacentRules() const
+{
+ ASSERT(hasRareData());
+ return elementRareData()->childrenAffectedByDirectAdjacentRules();
+}
+
+bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
+{
+ ASSERT(hasRareData());
+ return elementRareData()->childrenAffectedByForwardPositionalRules();
+}
+
+bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
+{
+ ASSERT(hasRareData());
+ return elementRareData()->childrenAffectedByBackwardPositionalRules();
+}
+
+unsigned Element::rareDataChildIndex() const
{
- return hasRareData() && elementRareData()->styleAffectedByEmpty();
+ ASSERT(hasRareData());
+ return elementRareData()->childIndex();
}
void Element::setIsInCanvasSubtree(bool isInCanvasSubtree)
@@ -2430,41 +2468,30 @@ void Element::updateExtraNamedItemRegistration(const AtomicString& oldId, const
PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
{
- return ensureElementRareData()->ensureCachedHTMLCollection(this, type);
-}
-
-PassRefPtr<HTMLCollection> ElementRareData::ensureCachedHTMLCollection(Element* element, CollectionType type)
-{
if (HTMLCollection* collection = cachedHTMLCollection(type))
return collection;
RefPtr<HTMLCollection> collection;
if (type == TableRows) {
- ASSERT(element->hasTagName(tableTag));
- return ensureNodeLists()->addCacheWithAtomicName<HTMLTableRowsCollection>(element, type);
+ ASSERT(hasTagName(tableTag));
+ return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
} else if (type == SelectOptions) {
- ASSERT(element->hasTagName(selectTag));
- return ensureNodeLists()->addCacheWithAtomicName<HTMLOptionsCollection>(element, type);
+ ASSERT(hasTagName(selectTag));
+ return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
} else if (type == FormControls) {
- ASSERT(element->hasTagName(formTag) || element->hasTagName(fieldsetTag));
- return ensureNodeLists()->addCacheWithAtomicName<HTMLFormControlsCollection>(element, type);
+ ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
+ return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
#if ENABLE(MICRODATA)
} else if (type == ItemProperties) {
- return ensureNodeLists()->addCacheWithAtomicName<HTMLPropertiesCollection>(element, type);
+ return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLPropertiesCollection>(this, type);
#endif
}
- return ensureNodeLists()->addCacheWithAtomicName<HTMLCollection>(element, type);
+ return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLCollection>(this, type);
}
HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
{
- return hasRareData() ? elementRareData()->cachedHTMLCollection(type) : 0;
-}
-
-void Element::removeCachedHTMLCollection(HTMLCollection* collection, CollectionType type)
-{
- ASSERT(hasRareData());
- elementRareData()->removeCachedHTMLCollection(collection, type);
+ return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0;
}
IntSize Element::savedLayerScrollOffset() const