summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/core/dom/Element.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/dom/Element.cpp')
-rw-r--r--chromium/third_party/WebKit/Source/core/dom/Element.cpp1778
1 files changed, 731 insertions, 1047 deletions
diff --git a/chromium/third_party/WebKit/Source/core/dom/Element.cpp b/chromium/third_party/WebKit/Source/core/dom/Element.cpp
index 8be9f406e93..a75add2f8ed 100644
--- a/chromium/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/chromium/third_party/WebKit/Source/core/dom/Element.cpp
@@ -26,37 +26,41 @@
#include "config.h"
#include "core/dom/Element.h"
-#include "CSSValueKeywords.h"
-#include "RuntimeEnabledFeatures.h"
-#include "SVGNames.h"
-#include "XMLNames.h"
+#include "bindings/v8/Dictionary.h"
+#include "bindings/v8/ExceptionMessages.h"
#include "bindings/v8/ExceptionState.h"
+#include "core/CSSValueKeywords.h"
+#include "core/SVGNames.h"
+#include "core/XMLNames.h"
#include "core/accessibility/AXObjectCache.h"
-#include "core/animation/DocumentTimeline.h"
+#include "core/animation/AnimationTimeline.h"
#include "core/animation/css/CSSAnimations.h"
-#include "core/css/CSSParser.h"
+#include "core/css/CSSImageValue.h"
#include "core/css/CSSStyleSheet.h"
#include "core/css/CSSValuePool.h"
#include "core/css/PropertySetCSSStyleDeclaration.h"
#include "core/css/StylePropertySet.h"
+#include "core/css/parser/BisonCSSParser.h"
#include "core/css/resolver/StyleResolver.h"
+#include "core/css/resolver/StyleResolverParentScope.h"
#include "core/dom/Attr.h"
#include "core/dom/CSSSelectorWatch.h"
#include "core/dom/ClientRect.h"
#include "core/dom/ClientRectList.h"
#include "core/dom/DatasetDOMStringMap.h"
-#include "core/dom/DocumentSharedObjectPool.h"
+#include "core/dom/ElementDataCache.h"
#include "core/dom/ElementRareData.h"
+#include "core/dom/ElementTraversal.h"
#include "core/dom/ExceptionCode.h"
#include "core/dom/FullscreenElementStack.h"
#include "core/dom/MutationObserverInterestGroup.h"
#include "core/dom/MutationRecord.h"
#include "core/dom/NamedNodeMap.h"
+#include "core/dom/NoEventDispatchAssertion.h"
#include "core/dom/NodeRenderStyle.h"
-#include "core/dom/NodeRenderingContext.h"
-#include "core/dom/PostAttachCallbacks.h"
#include "core/dom/PresentationAttributeStyle.h"
#include "core/dom/PseudoElement.h"
+#include "core/dom/RenderTreeBuilder.h"
#include "core/dom/ScriptableDocumentParser.h"
#include "core/dom/SelectorQuery.h"
#include "core/dom/Text.h"
@@ -70,14 +74,17 @@
#include "core/editing/markup.h"
#include "core/events/EventDispatcher.h"
#include "core/events/FocusEvent.h"
-#include "core/frame/ContentSecurityPolicy.h"
-#include "core/frame/Frame.h"
#include "core/frame/FrameView.h"
+#include "core/frame/LocalFrame.h"
+#include "core/frame/Settings.h"
+#include "core/frame/UseCounter.h"
+#include "core/frame/csp/ContentSecurityPolicy.h"
#include "core/html/ClassList.h"
#include "core/html/HTMLCollection.h"
#include "core/html/HTMLDocument.h"
#include "core/html/HTMLElement.h"
#include "core/html/HTMLFormControlsCollection.h"
+#include "core/html/HTMLFrameElementBase.h"
#include "core/html/HTMLFrameOwnerElement.h"
#include "core/html/HTMLLabelElement.h"
#include "core/html/HTMLOptionsCollection.h"
@@ -88,15 +95,17 @@
#include "core/page/FocusController.h"
#include "core/page/Page.h"
#include "core/page/PointerLockController.h"
-#include "core/rendering/FlowThreadController.h"
-#include "core/rendering/RenderNamedFlowFragment.h"
+#include "core/rendering/RenderLayer.h"
#include "core/rendering/RenderView.h"
-#include "core/rendering/RenderWidget.h"
+#include "core/rendering/compositing/RenderLayerCompositor.h"
#include "core/svg/SVGDocumentExtensions.h"
#include "core/svg/SVGElement.h"
+#include "platform/RuntimeEnabledFeatures.h"
+#include "platform/scroll/ScrollableArea.h"
#include "wtf/BitVector.h"
#include "wtf/HashFunctions.h"
#include "wtf/text/CString.h"
+#include "wtf/text/StringBuilder.h"
#include "wtf/text/TextPosition.h"
namespace WebCore {
@@ -104,76 +113,7 @@ namespace WebCore {
using namespace HTMLNames;
using namespace XMLNames;
-class StyleResolverParentPusher {
-public:
- explicit StyleResolverParentPusher(Element& parent)
- : m_parent(parent)
- , m_pushedStyleResolver(0)
- {
- }
- void push()
- {
- if (m_pushedStyleResolver)
- return;
- m_pushedStyleResolver = &m_parent.document().ensureStyleResolver();
- m_pushedStyleResolver->pushParentElement(m_parent);
- }
- ~StyleResolverParentPusher()
- {
-
- if (!m_pushedStyleResolver)
- return;
-
- // This tells us that our pushed style selector is in a bad state,
- // so we should just bail out in that scenario.
- ASSERT(m_pushedStyleResolver == m_parent.document().styleResolver());
- if (m_pushedStyleResolver != m_parent.document().styleResolver())
- return;
-
- m_pushedStyleResolver->popParentElement(m_parent);
- }
-
-private:
- Element& m_parent;
- StyleResolver* m_pushedStyleResolver;
-};
-
-typedef Vector<RefPtr<Attr> > AttrNodeList;
-typedef HashMap<Element*, OwnPtr<AttrNodeList> > AttrNodeListMap;
-
-static AttrNodeListMap& attrNodeListMap()
-{
- DEFINE_STATIC_LOCAL(AttrNodeListMap, map, ());
- return map;
-}
-
-static AttrNodeList* attrNodeListForElement(Element* element)
-{
- if (!element->hasSyntheticAttrChildNodes())
- return 0;
- ASSERT(attrNodeListMap().contains(element));
- return attrNodeListMap().get(element);
-}
-
-static AttrNodeList& ensureAttrNodeListForElement(Element* element)
-{
- if (element->hasSyntheticAttrChildNodes()) {
- ASSERT(attrNodeListMap().contains(element));
- return *attrNodeListMap().get(element);
- }
- ASSERT(!attrNodeListMap().contains(element));
- element->setHasSyntheticAttrChildNodes(true);
- AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList));
- return *result.iterator->value;
-}
-
-static void removeAttrNodeListForElement(Element* element)
-{
- ASSERT(element->hasSyntheticAttrChildNodes());
- ASSERT(attrNodeListMap().contains(element));
- attrNodeListMap().remove(element);
- element->setHasSyntheticAttrChildNodes(false);
-}
+typedef WillBeHeapVector<RefPtrWillBeMember<Attr> > AttrNodeList;
static Attr* findAttrNodeInList(const AttrNodeList& attrNodeList, const QualifiedName& name)
{
@@ -185,33 +125,25 @@ static Attr* findAttrNodeInList(const AttrNodeList& attrNodeList, const Qualifie
return 0;
}
-PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document)
+PassRefPtrWillBeRawPtr<Element> Element::create(const QualifiedName& tagName, Document* document)
{
- return adoptRef(new Element(tagName, document, CreateElement));
+ return adoptRefWillBeNoop(new Element(tagName, document, CreateElement));
}
-Element::~Element()
+Element::Element(const QualifiedName& tagName, Document* document, ConstructionType type)
+ : ContainerNode(document, type)
+ , m_tagName(tagName)
{
- // When the document is not destroyed, an element that was part of a named flow
- // content nodes should have been removed from the content nodes collection
- // and the inNamedFlow flag reset.
- ASSERT(!document().renderView() || !inNamedFlow());
-
- if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
- cssomWrapper->clearParentElement();
+ ScriptWrappable::init(this);
+}
- if (hasRareData()) {
- ElementRareData* data = elementRareData();
- data->setPseudoElement(BEFORE, 0);
- data->setPseudoElement(AFTER, 0);
- data->setPseudoElement(BACKDROP, 0);
- data->clearShadow();
+Element::~Element()
+{
+ ASSERT(needsAttach());
- if (RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
- if (ActiveAnimations* activeAnimations = data->activeAnimations())
- activeAnimations->cssAnimations().cancel();
- }
- }
+#if !ENABLE(OILPAN)
+ if (hasRareData())
+ elementRareData()->clearShadow();
if (isCustomElement())
CustomElement::wasDestroyed(this);
@@ -219,10 +151,16 @@ Element::~Element()
if (hasSyntheticAttrChildNodes())
detachAllAttrNodesFromElement();
+ // With Oilpan, either the Element has been removed from the Document
+ // or the Document is dead as well. If the Element has been removed from
+ // the Document the element has already been removed from the pending
+ // resources. If the document is also dead, there is no need to remove
+ // the element from the pending resources.
if (hasPendingResources()) {
- document().accessSVGExtensions()->removeElementFromPendingResources(this);
+ document().accessSVGExtensions().removeElementFromPendingResources(this);
ASSERT(!hasPendingResources());
}
+#endif
}
inline ElementRareData* Element::elementRareData() const
@@ -236,6 +174,25 @@ inline ElementRareData& Element::ensureElementRareData()
return static_cast<ElementRareData&>(ensureRareData());
}
+bool Element::hasElementFlagInternal(ElementFlags mask) const
+{
+ return elementRareData()->hasElementFlag(mask);
+}
+
+void Element::setElementFlag(ElementFlags mask, bool value)
+{
+ if (!hasRareData() && !value)
+ return;
+ ensureElementRareData().setElementFlag(mask, value);
+}
+
+void Element::clearElementFlag(ElementFlags mask)
+{
+ if (!hasRareData())
+ return;
+ elementRareData()->clearElementFlag(mask);
+}
+
void Element::clearTabIndexExplicitlyIfNeeded()
{
if (hasRareData())
@@ -247,9 +204,9 @@ void Element::setTabIndexExplicitly(short tabIndex)
ensureElementRareData().setTabIndexExplicitly(tabIndex);
}
-bool Element::supportsFocus() const
+void Element::setTabIndex(int value)
{
- return hasRareData() && elementRareData()->tabIndexSetExplicitly();
+ setIntegralAttribute(tabindexAttr, value);
}
short Element::tabIndex() const
@@ -272,9 +229,7 @@ bool Element::rendererIsFocusable() const
// FIXME: These asserts should be in Node::isFocusable, but there are some
// callsites like Document::setFocusedElement that would currently fail on
// them. See crbug.com/251163
- if (renderer()) {
- ASSERT(!renderer()->needsLayout());
- } else {
+ if (!renderer()) {
// We can't just use needsStyleRecalc() because if the node is in a
// display:none tree it might say it needs style recalc but the whole
// document is actually up to date.
@@ -289,21 +244,21 @@ bool Element::rendererIsFocusable() const
return true;
}
-PassRefPtr<Node> Element::cloneNode(bool deep)
+PassRefPtrWillBeRawPtr<Node> Element::cloneNode(bool deep)
{
return deep ? cloneElementWithChildren() : cloneElementWithoutChildren();
}
-PassRefPtr<Element> Element::cloneElementWithChildren()
+PassRefPtrWillBeRawPtr<Element> Element::cloneElementWithChildren()
{
- RefPtr<Element> clone = cloneElementWithoutChildren();
+ RefPtrWillBeRawPtr<Element> clone = cloneElementWithoutChildren();
cloneChildNodes(clone.get());
return clone.release();
}
-PassRefPtr<Element> Element::cloneElementWithoutChildren()
+PassRefPtrWillBeRawPtr<Element> Element::cloneElementWithoutChildren()
{
- RefPtr<Element> clone = cloneElementWithoutAttributesAndChildren();
+ RefPtrWillBeRawPtr<Element> clone = cloneElementWithoutAttributesAndChildren();
// This will catch HTML elements in the wrong namespace that are not correctly copied.
// This is a sanity check as HTML overloads some of the DOM methods.
ASSERT(isHTMLElement() == clone->isHTMLElement());
@@ -312,20 +267,20 @@ PassRefPtr<Element> Element::cloneElementWithoutChildren()
return clone.release();
}
-PassRefPtr<Element> Element::cloneElementWithoutAttributesAndChildren()
+PassRefPtrWillBeRawPtr<Element> Element::cloneElementWithoutAttributesAndChildren()
{
return document().createElement(tagQName(), false);
}
-PassRefPtr<Attr> Element::detachAttribute(size_t index)
+PassRefPtrWillBeRawPtr<Attr> Element::detachAttribute(size_t index)
{
ASSERT(elementData());
- const Attribute* attribute = elementData()->attributeItem(index);
- RefPtr<Attr> attrNode = attrIfExists(attribute->name());
+ const Attribute& attribute = elementData()->attributeAt(index);
+ RefPtrWillBeRawPtr<Attr> attrNode = attrIfExists(attribute.name());
if (attrNode)
detachAttrNodeAtIndex(attrNode.get(), index);
else {
- attrNode = Attr::create(document(), attribute->name(), attribute->value());
+ attrNode = Attr::create(document(), attribute.name(), attribute.value());
removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
}
return attrNode.release();
@@ -336,10 +291,9 @@ void Element::detachAttrNodeAtIndex(Attr* attr, size_t index)
ASSERT(attr);
ASSERT(elementData());
- const Attribute* attribute = elementData()->attributeItem(index);
- ASSERT(attribute);
- ASSERT(attribute->name() == attr->qualifiedName());
- detachAttrNodeFromElementWithValue(attr, attribute->value());
+ const Attribute& attribute = elementData()->attributeAt(index);
+ ASSERT(attribute.name() == attr->qualifiedName());
+ detachAttrNodeFromElementWithValue(attr, attribute.value());
removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
}
@@ -348,7 +302,7 @@ void Element::removeAttribute(const QualifiedName& name)
if (!elementData())
return;
- size_t index = elementData()->getAttributeItemIndex(name);
+ size_t index = elementData()->findAttributeIndexByName(name);
if (index == kNotFound)
return;
@@ -363,7 +317,7 @@ void Element::setBooleanAttribute(const QualifiedName& name, bool value)
removeAttribute(name);
}
-NamedNodeMap* Element::attributes() const
+NamedNodeMap* Element::attributesForBindings() const
{
ElementRareData& rareData = const_cast<Element*>(this)->ensureElementRareData();
if (NamedNodeMap* attributeMap = rareData.attributeMap())
@@ -380,19 +334,16 @@ ActiveAnimations* Element::activeAnimations() const
return 0;
}
-ActiveAnimations* Element::ensureActiveAnimations()
+ActiveAnimations& Element::ensureActiveAnimations()
{
ElementRareData& rareData = ensureElementRareData();
if (!rareData.activeAnimations())
- rareData.setActiveAnimations(adoptPtr(new ActiveAnimations()));
- return rareData.activeAnimations();
+ rareData.setActiveAnimations(adoptPtrWillBeNoop(new ActiveAnimations()));
+ return *rareData.activeAnimations();
}
bool Element::hasActiveAnimations() const
{
- if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled())
- return false;
-
if (!hasRareData())
return false;
@@ -414,6 +365,9 @@ void Element::synchronizeAllAttributes() const
{
if (!elementData())
return;
+ // NOTE: anyAttributeMatches in SelectorChecker.cpp
+ // currently assumes that all lazy attributes have a null namespace.
+ // If that ever changes we'll need to fix that code.
if (elementData()->m_styleAttributeIsDirty) {
ASSERT(isStyledElement());
synchronizeStyleAttributeInternal();
@@ -435,6 +389,8 @@ inline void Element::synchronizeAttribute(const QualifiedName& name) const
}
if (UNLIKELY(elementData()->m_animatedSVGAttributesAreDirty)) {
ASSERT(isSVGElement());
+ // See comment in the AtomicString version of synchronizeAttribute()
+ // also.
toSVGElement(this)->synchronizeAnimatedSVGAttribute(name);
}
}
@@ -452,6 +408,16 @@ void Element::synchronizeAttribute(const AtomicString& localName) const
}
if (elementData()->m_animatedSVGAttributesAreDirty) {
// We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
+
+ // FIXME: this code is called regardless of whether name is an
+ // animated SVG Attribute. It would seem we should only call this method
+ // if SVGElement::isAnimatableAttribute is true, but the list of
+ // animatable attributes in isAnimatableAttribute does not suffice to
+ // pass all layout tests. Also, m_animatedSVGAttributesAreDirty stays
+ // dirty unless synchronizeAnimatedSVGAttribute is called with
+ // anyQName(). This means that even if Element::synchronizeAttribute()
+ // is called on all attributes, m_animatedSVGAttributesAreDirty remains
+ // true.
toSVGElement(this)->synchronizeAnimatedSVGAttribute(QualifiedName(nullAtom, localName, nullAtom));
}
}
@@ -461,11 +427,16 @@ const AtomicString& Element::getAttribute(const QualifiedName& name) const
if (!elementData())
return nullAtom;
synchronizeAttribute(name);
- if (const Attribute* attribute = getAttributeItem(name))
+ if (const Attribute* attribute = findAttributeByName(name))
return attribute->value();
return nullAtom;
}
+bool Element::shouldIgnoreAttributeCase() const
+{
+ return isHTMLElement() && document().isHTMLDocument();
+}
+
void Element::scrollIntoView(bool alignToTop)
{
document().updateLayoutIgnorePendingStylesheets();
@@ -546,40 +517,33 @@ static float localZoomForRenderer(RenderObject& renderer)
return zoomFactor;
}
-static int adjustForLocalZoom(LayoutUnit value, RenderObject& renderer)
+static double adjustForLocalZoom(LayoutUnit value, RenderObject& renderer)
{
float zoomFactor = localZoomForRenderer(renderer);
if (zoomFactor == 1)
- return value;
- return lroundf(value / zoomFactor);
+ return value.toDouble();
+ return value.toDouble() / zoomFactor;
}
int Element::offsetLeft()
{
- document().partialUpdateLayoutIgnorePendingStylesheets(this);
+ document().updateLayoutIgnorePendingStylesheets();
if (RenderBoxModelObject* renderer = renderBoxModelObject())
- return adjustForLocalZoom(renderer->pixelSnappedOffsetLeft(), *renderer);
+ return lroundf(adjustForLocalZoom(renderer->offsetLeft(), *renderer));
return 0;
}
int Element::offsetTop()
{
- document().partialUpdateLayoutIgnorePendingStylesheets(this);
+ document().updateLayoutIgnorePendingStylesheets();
if (RenderBoxModelObject* renderer = renderBoxModelObject())
- return adjustForLocalZoom(renderer->pixelSnappedOffsetTop(), *renderer);
+ return lroundf(adjustForLocalZoom(renderer->pixelSnappedOffsetTop(), *renderer));
return 0;
}
int Element::offsetWidth()
{
- document().updateStyleForNodeIfNeeded(this);
-
- if (RenderBox* renderer = renderBox()) {
- if (renderer->canDetermineWidthWithoutLayout())
- return adjustLayoutUnitForAbsoluteZoom(renderer->fixedOffsetWidth(), *renderer).round();
- }
-
- document().partialUpdateLayoutIgnorePendingStylesheets(this);
+ document().updateLayoutIgnorePendingStylesheets();
if (RenderBoxModelObject* renderer = renderBoxModelObject())
return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetWidth(), *renderer).round();
return 0;
@@ -587,13 +551,13 @@ int Element::offsetWidth()
int Element::offsetHeight()
{
- document().partialUpdateLayoutIgnorePendingStylesheets(this);
+ document().updateLayoutIgnorePendingStylesheets();
if (RenderBoxModelObject* renderer = renderBoxModelObject())
return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetHeight(), *renderer).round();
return 0;
}
-Element* Element::bindingsOffsetParent()
+Element* Element::offsetParentForBindings()
{
Element* element = offsetParent();
if (!element || !element->isInShadowTree())
@@ -614,7 +578,7 @@ int Element::clientLeft()
document().updateLayoutIgnorePendingStylesheets();
if (RenderBox* renderer = renderBox())
- return adjustForAbsoluteZoom(roundToInt(renderer->clientLeft()), renderer);
+ return adjustLayoutUnitForAbsoluteZoom(roundToInt(renderer->clientLeft()), *renderer);
return 0;
}
@@ -623,7 +587,7 @@ int Element::clientTop()
document().updateLayoutIgnorePendingStylesheets();
if (RenderBox* renderer = renderBox())
- return adjustForAbsoluteZoom(roundToInt(renderer->clientTop()), renderer);
+ return adjustLayoutUnitForAbsoluteZoom(roundToInt(renderer->clientTop()), *renderer);
return 0;
}
@@ -638,7 +602,7 @@ int Element::clientWidth()
|| (inQuirksMode && isHTMLElement() && document().body() == this)) {
if (FrameView* view = document().view()) {
if (RenderView* renderView = document().renderView())
- return adjustForAbsoluteZoom(view->layoutSize().width(), renderView);
+ return adjustLayoutUnitForAbsoluteZoom(view->layoutSize().width(), *renderView);
}
}
@@ -659,7 +623,7 @@ int Element::clientHeight()
|| (inQuirksMode && isHTMLElement() && document().body() == this)) {
if (FrameView* view = document().view()) {
if (RenderView* renderView = document().renderView())
- return adjustForAbsoluteZoom(view->layoutSize().height(), renderView);
+ return adjustLayoutUnitForAbsoluteZoom(view->layoutSize().height(), *renderView);
}
}
@@ -674,7 +638,7 @@ int Element::scrollLeft()
if (document().documentElement() != this) {
if (RenderBox* rend = renderBox())
- return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
+ return adjustDoubleForAbsoluteZoom(rend->scrollLeft(), *rend);
return 0;
}
@@ -684,7 +648,7 @@ int Element::scrollLeft()
if (FrameView* view = document().view()) {
if (RenderView* renderView = document().renderView())
- return adjustForAbsoluteZoom(view->scrollX(), renderView);
+ return adjustDoubleForAbsoluteZoom(view->scrollX(), *renderView);
}
}
@@ -697,7 +661,7 @@ int Element::scrollTop()
if (document().documentElement() != this) {
if (RenderBox* rend = renderBox())
- return adjustForAbsoluteZoom(rend->scrollTop(), rend);
+ return adjustLayoutUnitForAbsoluteZoom(rend->scrollTop(), *rend);
return 0;
}
@@ -707,7 +671,7 @@ int Element::scrollTop()
if (FrameView* view = document().view()) {
if (RenderView* renderView = document().renderView())
- return adjustForAbsoluteZoom(view->scrollY(), renderView);
+ return adjustDoubleForAbsoluteZoom(view->scrollY(), *renderView);
}
}
@@ -720,7 +684,7 @@ void Element::setScrollLeft(int newLeft)
if (document().documentElement() != this) {
if (RenderBox* rend = renderBox())
- rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
+ rend->setScrollLeft(LayoutUnit::fromFloatRound(newLeft * rend->style()->effectiveZoom()));
return;
}
@@ -728,15 +692,36 @@ void Element::setScrollLeft(int newLeft)
if (document().inQuirksMode())
return;
- Frame* frame = document().frame();
+ LocalFrame* frame = document().frame();
if (!frame)
return;
FrameView* view = frame->view();
if (!view)
return;
- view->setScrollPosition(IntPoint(static_cast<int>(newLeft * frame->pageZoomFactor()), view->scrollY()));
+ view->setScrollPosition(IntPoint(roundf(newLeft * frame->pageZoomFactor()), view->scrollY()));
+ }
+}
+
+void Element::setScrollLeft(const Dictionary& scrollOptionsHorizontal, ExceptionState& exceptionState)
+{
+ String scrollBehaviorString;
+ ScrollBehavior scrollBehavior = ScrollBehaviorAuto;
+ if (scrollOptionsHorizontal.get("behavior", scrollBehaviorString)) {
+ if (!ScrollableArea::scrollBehaviorFromString(scrollBehaviorString, scrollBehavior)) {
+ exceptionState.throwTypeError("The ScrollBehavior provided is invalid.");
+ return;
+ }
+ }
+
+ int position;
+ if (!scrollOptionsHorizontal.get("x", position)) {
+ exceptionState.throwTypeError("ScrollOptionsHorizontal must include an 'x' member.");
+ return;
}
+
+ // FIXME: Use scrollBehavior to decide whether to scroll smoothly or instantly.
+ setScrollLeft(position);
}
void Element::setScrollTop(int newTop)
@@ -745,7 +730,7 @@ void Element::setScrollTop(int newTop)
if (document().documentElement() != this) {
if (RenderBox* rend = renderBox())
- rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
+ rend->setScrollTop(LayoutUnit::fromFloatRound(newTop * rend->style()->effectiveZoom()));
return;
}
@@ -753,22 +738,43 @@ void Element::setScrollTop(int newTop)
if (document().inQuirksMode())
return;
- Frame* frame = document().frame();
+ LocalFrame* frame = document().frame();
if (!frame)
return;
FrameView* view = frame->view();
if (!view)
return;
- view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(newTop * frame->pageZoomFactor())));
+ view->setScrollPosition(IntPoint(view->scrollX(), roundf(newTop * frame->pageZoomFactor())));
}
}
+void Element::setScrollTop(const Dictionary& scrollOptionsVertical, ExceptionState& exceptionState)
+{
+ String scrollBehaviorString;
+ ScrollBehavior scrollBehavior = ScrollBehaviorAuto;
+ if (scrollOptionsVertical.get("behavior", scrollBehaviorString)) {
+ if (!ScrollableArea::scrollBehaviorFromString(scrollBehaviorString, scrollBehavior)) {
+ exceptionState.throwTypeError("The ScrollBehavior provided is invalid.");
+ return;
+ }
+ }
+
+ int position;
+ if (!scrollOptionsVertical.get("y", position)) {
+ exceptionState.throwTypeError("ScrollOptionsVertical must include a 'y' member.");
+ return;
+ }
+
+ // FIXME: Use scrollBehavior to decide whether to scroll smoothly or instantly.
+ setScrollTop(position);
+}
+
int Element::scrollWidth()
{
document().updateLayoutIgnorePendingStylesheets();
if (RenderBox* rend = renderBox())
- return adjustForAbsoluteZoom(rend->scrollWidth(), rend);
+ return adjustLayoutUnitForAbsoluteZoom(rend->scrollWidth(), *rend).toDouble();
return 0;
}
@@ -776,7 +782,7 @@ int Element::scrollHeight()
{
document().updateLayoutIgnorePendingStylesheets();
if (RenderBox* rend = renderBox())
- return adjustForAbsoluteZoom(rend->scrollHeight(), rend);
+ return adjustLayoutUnitForAbsoluteZoom(rend->scrollHeight(), *rend).toDouble();
return 0;
}
@@ -812,7 +818,7 @@ IntRect Element::boundsInRootViewSpace()
return result;
}
-PassRefPtr<ClientRectList> Element::getClientRects()
+PassRefPtrWillBeRawPtr<ClientRectList> Element::getClientRects()
{
document().updateLayoutIgnorePendingStylesheets();
@@ -829,7 +835,7 @@ PassRefPtr<ClientRectList> Element::getClientRects()
return ClientRectList::create(quads);
}
-PassRefPtr<ClientRect> Element::getBoundingClientRect()
+PassRefPtrWillBeRawPtr<ClientRect> Element::getBoundingClientRect()
{
document().updateLayoutIgnorePendingStylesheets();
@@ -871,7 +877,7 @@ const AtomicString& Element::getAttribute(const AtomicString& localName) const
if (!elementData())
return nullAtom;
synchronizeAttribute(localName);
- if (const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase()))
+ if (const Attribute* attribute = elementData()->findAttributeByName(localName, shouldIgnoreAttributeCase()))
return attribute->value();
return nullAtom;
}
@@ -884,28 +890,28 @@ const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, co
void Element::setAttribute(const AtomicString& localName, const AtomicString& value, ExceptionState& exceptionState)
{
if (!Document::isValidName(localName)) {
- exceptionState.throwUninformativeAndGenericDOMException(InvalidCharacterError);
+ exceptionState.throwDOMException(InvalidCharacterError, "'" + localName + "' is not a valid attribute name.");
return;
}
synchronizeAttribute(localName);
const AtomicString& caseAdjustedLocalName = shouldIgnoreAttributeCase() ? localName.lower() : localName;
- size_t index = elementData() ? elementData()->getAttributeItemIndex(caseAdjustedLocalName, false) : kNotFound;
- const QualifiedName& qName = index != kNotFound ? attributeItem(index)->name() : QualifiedName(nullAtom, caseAdjustedLocalName, nullAtom);
+ size_t index = elementData() ? elementData()->findAttributeIndexByName(caseAdjustedLocalName, false) : kNotFound;
+ const QualifiedName& qName = index != kNotFound ? attributeAt(index).name() : QualifiedName(nullAtom, caseAdjustedLocalName, nullAtom);
setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute);
}
void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
{
synchronizeAttribute(name);
- size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : kNotFound;
+ size_t index = elementData() ? elementData()->findAttributeIndexByName(name) : kNotFound;
setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute);
}
void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value)
{
- size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : kNotFound;
+ size_t index = elementData() ? elementData()->findAttributeIndexByName(name) : kNotFound;
setAttributeInternal(index, name, value, InSynchronizationOfLazyAttribute);
}
@@ -918,24 +924,24 @@ ALWAYS_INLINE void Element::setAttributeInternal(size_t index, const QualifiedNa
}
if (index == kNotFound) {
- addAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute);
+ appendAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute);
return;
}
- const Attribute* existingAttribute = attributeItem(index);
- QualifiedName existingAttributeName = existingAttribute->name();
+ const Attribute& existingAttribute = attributeAt(index);
+ QualifiedName existingAttributeName = existingAttribute.name();
if (!inSynchronizationOfLazyAttribute)
- willModifyAttribute(existingAttributeName, existingAttribute->value(), newValue);
+ willModifyAttribute(existingAttributeName, existingAttribute.value(), newValue);
- if (newValue != existingAttribute->value()) {
+ if (newValue != existingAttribute.value()) {
// If there is an Attr node hooked to this attribute, the Attr::setValue() call below
// will write into the ElementData.
// FIXME: Refactor this so it makes some sense.
- if (RefPtr<Attr> attrNode = inSynchronizationOfLazyAttribute ? 0 : attrIfExists(existingAttributeName))
+ if (RefPtrWillBeRawPtr<Attr> attrNode = inSynchronizationOfLazyAttribute ? nullptr : attrIfExists(existingAttributeName))
attrNode->setValue(newValue);
else
- ensureUniqueElementData()->attributeItem(index)->setValue(newValue);
+ ensureUniqueElementData().attributeAt(index).setValue(newValue);
}
if (!inSynchronizationOfLazyAttribute)
@@ -949,16 +955,6 @@ static inline AtomicString makeIdForStyleResolution(const AtomicString& value, b
return value;
}
-static bool checkNeedsStyleInvalidationForIdChange(const AtomicString& oldId, const AtomicString& newId, const RuleFeatureSet& features)
-{
- ASSERT(newId != oldId);
- if (!oldId.isEmpty() && features.hasSelectorForId(oldId))
- return true;
- if (!newId.isEmpty() && features.hasSelectorForId(newId))
- return true;
- return false;
-}
-
void Element::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
{
if (ElementShadow* parentElementShadow = shadowWhereNodeCanBeDistributed(*this)) {
@@ -972,7 +968,6 @@ void Element::attributeChanged(const QualifiedName& name, const AtomicString& ne
StyleResolver* styleResolver = document().styleResolver();
bool testShouldInvalidateStyle = inActiveDocument() && styleResolver && styleChangeType() < SubtreeStyleChange;
- bool shouldInvalidateStyle = false;
if (isStyledElement() && name == styleAttr) {
styleAttributeChanged(newValue, reason);
@@ -986,28 +981,35 @@ void Element::attributeChanged(const QualifiedName& name, const AtomicString& ne
AtomicString newId = makeIdForStyleResolution(newValue, document().inQuirksMode());
if (newId != oldId) {
elementData()->setIdForStyleResolution(newId);
- shouldInvalidateStyle = testShouldInvalidateStyle && checkNeedsStyleInvalidationForIdChange(oldId, newId, styleResolver->ensureRuleFeatureSet());
+ if (testShouldInvalidateStyle)
+ styleResolver->ensureUpdatedRuleFeatureSet().scheduleStyleInvalidationForIdChange(oldId, newId, *this);
}
} else if (name == classAttr) {
classAttributeChanged(newValue);
} else if (name == HTMLNames::nameAttr) {
setHasName(!newValue.isNull());
- } else if (name == HTMLNames::pseudoAttr) {
- shouldInvalidateStyle |= testShouldInvalidateStyle && isInShadowTree();
}
invalidateNodeListCachesInAncestors(&name, this);
// If there is currently no StyleResolver, we can't be sure that this attribute change won't affect style.
- shouldInvalidateStyle |= !styleResolver;
-
- if (shouldInvalidateStyle)
- setNeedsStyleRecalc();
+ if (!styleResolver)
+ setNeedsStyleRecalc(SubtreeStyleChange);
if (AXObjectCache* cache = document().existingAXObjectCache())
cache->handleAttributeChanged(name, this);
}
+bool Element::hasLegalLinkAttribute(const QualifiedName&) const
+{
+ return false;
+}
+
+const QualifiedName& Element::subResourceAttributeName() const
+{
+ return QualifiedName::null();
+}
+
inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
{
if (name == isAttr)
@@ -1042,77 +1044,28 @@ static inline bool classStringHasClassName(const AtomicString& newClassString)
return classStringHasClassName(newClassString.characters16(), length);
}
-template<typename Checker>
-static bool checkSelectorForClassChange(const SpaceSplitString& changedClasses, const Checker& checker)
-{
- unsigned changedSize = changedClasses.size();
- for (unsigned i = 0; i < changedSize; ++i) {
- if (checker.hasSelectorForClass(changedClasses[i]))
- return true;
- }
- return false;
-}
-
-template<typename Checker>
-static bool checkSelectorForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, const Checker& checker)
-{
- if (!oldClasses.size())
- return checkSelectorForClassChange(newClasses, checker);
-
- // Class vectors tend to be very short. This is faster than using a hash table.
- BitVector remainingClassBits;
- remainingClassBits.ensureSize(oldClasses.size());
-
- for (unsigned i = 0; i < newClasses.size(); ++i) {
- bool found = false;
- for (unsigned j = 0; j < oldClasses.size(); ++j) {
- if (newClasses[i] == oldClasses[j]) {
- // Mark each class that is still in the newClasses so we can skip doing
- // an n^2 search below when looking for removals. We can't break from
- // this loop early since a class can appear more than once.
- remainingClassBits.quickSet(j);
- found = true;
- }
- }
- // Class was added.
- if (!found && checker.hasSelectorForClass(newClasses[i]))
- return true;
- }
-
- for (unsigned i = 0; i < oldClasses.size(); ++i) {
- if (remainingClassBits.quickGet(i))
- continue;
- // Class was removed.
- if (checker.hasSelectorForClass(oldClasses[i]))
- return true;
- }
-
- return false;
-}
-
void Element::classAttributeChanged(const AtomicString& newClassString)
{
StyleResolver* styleResolver = document().styleResolver();
bool testShouldInvalidateStyle = inActiveDocument() && styleResolver && styleChangeType() < SubtreeStyleChange;
- bool shouldInvalidateStyle = false;
+ ASSERT(elementData());
if (classStringHasClassName(newClassString)) {
const bool shouldFoldCase = document().inQuirksMode();
const SpaceSplitString oldClasses = elementData()->classNames();
elementData()->setClass(newClassString, shouldFoldCase);
const SpaceSplitString& newClasses = elementData()->classNames();
- shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, newClasses, styleResolver->ensureRuleFeatureSet());
+ if (testShouldInvalidateStyle)
+ styleResolver->ensureUpdatedRuleFeatureSet().scheduleStyleInvalidationForClassChange(oldClasses, newClasses, *this);
} else {
const SpaceSplitString& oldClasses = elementData()->classNames();
- shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, styleResolver->ensureRuleFeatureSet());
+ if (testShouldInvalidateStyle)
+ styleResolver->ensureUpdatedRuleFeatureSet().scheduleStyleInvalidationForClassChange(oldClasses, *this);
elementData()->clearClass();
}
if (hasRareData())
elementRareData()->clearClassListValueForQuirksMode();
-
- if (shouldInvalidateStyle)
- setNeedsStyleRecalc();
}
bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
@@ -1137,11 +1090,11 @@ bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* el
const bool shouldFoldCase = document().inQuirksMode();
const SpaceSplitString& oldClasses = elementData()->classNames();
const SpaceSplitString newClasses(newClassString, shouldFoldCase);
- if (checkSelectorForClassChange(oldClasses, newClasses, featureSet))
+ if (featureSet.checkSelectorsForClassChange(oldClasses, newClasses))
return true;
} else {
const SpaceSplitString& oldClasses = elementData()->classNames();
- if (checkSelectorForClassChange(oldClasses, featureSet))
+ if (featureSet.checkSelectorsForClassChange(oldClasses))
return true;
}
}
@@ -1190,8 +1143,8 @@ void Element::parserSetAttributes(const Vector<Attribute>& attributeVector)
if (attributeVector.isEmpty())
return;
- if (document().sharedObjectPool())
- m_elementData = document().sharedObjectPool()->cachedShareableElementDataWithAttributes(attributeVector);
+ if (document().elementDataCache())
+ m_elementData = document().elementDataCache()->cachedShareableElementDataWithAttributes(attributeVector);
else
m_elementData = ShareableElementData::createWithAttributes(attributeVector);
@@ -1203,7 +1156,7 @@ void Element::parserSetAttributes(const Vector<Attribute>& attributeVector)
bool Element::hasAttributes() const
{
synchronizeAllAttributes();
- return elementData() && elementData()->length();
+ return elementData() && elementData()->hasAttributes();
}
bool Element::hasEquivalentAttributes(const Element* other) const
@@ -1224,23 +1177,57 @@ String Element::nodeName() const
return m_tagName.toString();
}
-String Element::nodeNamePreservingCase() const
-{
- return m_tagName.toString();
-}
-
void Element::setPrefix(const AtomicString& prefix, ExceptionState& exceptionState)
{
- checkSetPrefix(prefix, exceptionState);
+ UseCounter::countDeprecation(document(), UseCounter::ElementSetPrefix);
+
+ if (!prefix.isEmpty() && !Document::isValidName(prefix)) {
+ exceptionState.throwDOMException(InvalidCharacterError, "The prefix '" + prefix + "' is not a valid name.");
+ return;
+ }
+
+ // FIXME: Raise NamespaceError if prefix is malformed per the Namespaces in XML specification.
+
+ const AtomicString& nodeNamespaceURI = namespaceURI();
+ if (nodeNamespaceURI.isEmpty() && !prefix.isEmpty()) {
+ exceptionState.throwDOMException(NamespaceError, "No namespace is set, so a namespace prefix may not be set.");
+ return;
+ }
+
+ if (prefix == xmlAtom && nodeNamespaceURI != XMLNames::xmlNamespaceURI) {
+ exceptionState.throwDOMException(NamespaceError, "The prefix '" + xmlAtom + "' may not be set on namespace '" + nodeNamespaceURI + "'.");
+ return;
+ }
+
if (exceptionState.hadException())
return;
m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
}
+const AtomicString& Element::locateNamespacePrefix(const AtomicString& namespaceToLocate) const
+{
+ if (!prefix().isNull() && namespaceURI() == namespaceToLocate)
+ return prefix();
+
+ if (hasAttributes()) {
+ AttributeCollection attributes = this->attributes();
+ AttributeCollection::const_iterator end = attributes.end();
+ for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it) {
+ if (it->prefix() == xmlnsAtom && it->value() == namespaceToLocate)
+ return it->localName();
+ }
+ }
+
+ if (Element* parent = parentElement())
+ return parent->locateNamespacePrefix(namespaceToLocate);
+
+ return nullAtom;
+}
+
KURL Element::baseURI() const
{
- const AtomicString& baseAttribute = getAttribute(baseAttr);
+ const AtomicString& baseAttribute = fastGetAttribute(baseAttr);
KURL base(KURL(), baseAttribute);
if (!base.protocol().isEmpty())
return base;
@@ -1303,7 +1290,7 @@ Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertio
if (!nameValue.isNull())
updateName(nullAtom, nameValue);
- if (hasTagName(labelTag)) {
+ if (isHTMLLabelElement(*this)) {
if (scope.shouldCacheLabelsByForAttribute())
updateLabel(scope, nullAtom, fastGetAttribute(forAttr));
}
@@ -1337,7 +1324,7 @@ void Element::removedFrom(ContainerNode* insertionPoint)
if (!nameValue.isNull())
updateName(nameValue, nullAtom);
- if (hasTagName(labelTag)) {
+ if (isHTMLLabelElement(*this)) {
TreeScope& treeScope = insertionPoint->treeScope();
if (treeScope.shouldCacheLabelsByForAttribute())
updateLabel(treeScope, fastGetAttribute(forAttr), nullAtom);
@@ -1347,7 +1334,7 @@ void Element::removedFrom(ContainerNode* insertionPoint)
ContainerNode::removedFrom(insertionPoint);
if (wasInDocument) {
if (hasPendingResources())
- document().accessSVGExtensions()->removeElementFromPendingResources(this);
+ document().accessSVGExtensions().removeElementFromPendingResources(this);
if (isUpgradedCustomElement())
CustomElement::didLeaveDocument(this, insertionPoint->document());
@@ -1355,101 +1342,85 @@ void Element::removedFrom(ContainerNode* insertionPoint)
document().removeFromTopLayer(this);
+ clearElementFlag(IsInCanvasSubtree);
+
if (hasRareData())
- elementRareData()->setIsInCanvasSubtree(false);
+ elementRareData()->clearRestyleFlags();
}
void Element::attach(const AttachContext& context)
{
ASSERT(document().inStyleRecalc());
- StyleResolverParentPusher parentPusher(*this);
-
// We've already been through detach when doing an attach, but we might
// need to clear any state that's been added since then.
if (hasRareData() && styleChangeType() == NeedsReattachStyleChange) {
ElementRareData* data = elementRareData();
data->clearComputedStyle();
- data->resetDynamicRestyleObservations();
// Only clear the style state if we're not going to reuse the style from recalcStyle.
if (!context.resolvedStyle)
data->resetStyleState();
}
- NodeRenderingContext(this, context.resolvedStyle).createRendererForElementIfNeeded();
+ RenderTreeBuilder(this, context.resolvedStyle).createRendererForElementIfNeeded();
addCallbackSelectors();
+ StyleResolverParentScope parentScope(*this);
+
createPseudoElementIfNeeded(BEFORE);
// When a shadow root exists, it does the work of attaching the children.
- if (ElementShadow* shadow = this->shadow()) {
- parentPusher.push();
+ if (ElementShadow* shadow = this->shadow())
shadow->attach(context);
- } else if (firstChild()) {
- parentPusher.push();
- }
ContainerNode::attach(context);
createPseudoElementIfNeeded(AFTER);
createPseudoElementIfNeeded(BACKDROP);
- if (hasRareData()) {
- ElementRareData* data = elementRareData();
- if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
- if (isFocusable() && document().focusedElement() == this)
- document().updateFocusAppearanceSoon(false /* don't restore selection */);
- data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
- }
- if (RuntimeEnabledFeatures::webAnimationsCSSEnabled() && !renderer()) {
- if (ActiveAnimations* activeAnimations = data->activeAnimations())
- activeAnimations->cssAnimations().cancel();
+ if (hasRareData() && !renderer()) {
+ if (ActiveAnimations* activeAnimations = elementRareData()->activeAnimations()) {
+ activeAnimations->cssAnimations().cancel();
+ activeAnimations->setAnimationStyleChange(false);
}
}
-
- InspectorInstrumentation::didRecalculateStyleForElement(this);
-}
-
-void Element::unregisterNamedFlowContentNode()
-{
- if (RuntimeEnabledFeatures::cssRegionsEnabled() && inNamedFlow() && document().renderView())
- document().renderView()->flowThreadController()->unregisterNamedFlowContentNode(this);
}
void Element::detach(const AttachContext& context)
{
- RenderWidget::UpdateSuspendScope suspendWidgetHierarchyUpdates;
- unregisterNamedFlowContentNode();
+ HTMLFrameOwnerElement::UpdateSuspendScope suspendWidgetHierarchyUpdates;
cancelFocusAppearanceUpdate();
removeCallbackSelectors();
+ if (svgFilterNeedsLayerUpdate())
+ document().unscheduleSVGFilterLayerUpdateHack(*this);
if (hasRareData()) {
ElementRareData* data = elementRareData();
- data->setPseudoElement(BEFORE, 0);
- data->setPseudoElement(AFTER, 0);
- data->setPseudoElement(BACKDROP, 0);
- data->setIsInsideRegion(false);
+ data->clearPseudoElements();
// attach() will perform the below steps for us when inside recalcStyle.
if (!document().inStyleRecalc()) {
data->resetStyleState();
data->clearComputedStyle();
- data->resetDynamicRestyleObservations();
}
- if (RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
- if (ActiveAnimations* activeAnimations = data->activeAnimations()) {
- if (context.performingReattach) {
- // FIXME: restart compositor animations rather than pull back to the main thread
- activeAnimations->cancelAnimationOnCompositor();
- } else {
- activeAnimations->cssAnimations().cancel();
- }
+ if (ActiveAnimations* activeAnimations = data->activeAnimations()) {
+ if (context.performingReattach) {
+ // FIXME: We call detach from within style recalc, so compositingState is not up to date.
+ // https://code.google.com/p/chromium/issues/detail?id=339847
+ DisableCompositingQueryAsserts disabler;
+
+ // FIXME: restart compositor animations rather than pull back to the main thread
+ activeAnimations->cancelAnimationOnCompositor();
+ } else {
+ activeAnimations->cssAnimations().cancel();
+ activeAnimations->setAnimationStyleChange(false);
}
}
+
+ if (ElementShadow* shadow = data->shadow())
+ shadow->detach(context);
}
- if (ElementShadow* shadow = this->shadow())
- shadow->detach(context);
ContainerNode::detach(context);
}
@@ -1483,7 +1454,7 @@ bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderS
// FIXME: We should do an actual diff to determine whether a repaint vs. layout
// is needed, but for now just assume a layout will be required. The diff code
// in RenderObject::setStyle would need to be factored out so that it could be reused.
- renderer()->setNeedsLayoutAndPrefWidthsRecalc();
+ renderer()->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
}
return true;
}
@@ -1506,12 +1477,15 @@ PassRefPtr<RenderStyle> Element::styleForRenderer()
style = customStyleForRenderer();
if (!style)
style = originalStyleForRenderer();
+ ASSERT(style);
// styleForElement() might add active animations so we need to get it again.
- if (ActiveAnimations* activeAnimations = this->activeAnimations())
+ if (ActiveAnimations* activeAnimations = this->activeAnimations()) {
activeAnimations->cssAnimations().maybeApplyPendingUpdate(this);
+ activeAnimations->updateAnimationFlags(*style);
+ }
- ASSERT(style);
+ document().didRecalculateStyleForElement();
return style.release();
}
@@ -1546,9 +1520,10 @@ void Element::recalcStyle(StyleRecalcChange change, Text* nextTextSibling)
}
// If we reattached we don't need to recalc the style of our descendants anymore.
- if ((change >= Inherit && change < Reattach) || childNeedsStyleRecalc())
+ if ((change >= UpdatePseudoElements && change < Reattach) || childNeedsStyleRecalc()) {
recalcChildStyle(change);
- clearChildNeedsStyleRecalc();
+ clearChildNeedsStyleRecalc();
+ }
if (hasCustomStyleCallbacks())
didRecalcStyle(change);
@@ -1566,27 +1541,28 @@ StyleRecalcChange Element::recalcOwnStyle(StyleRecalcChange change)
RefPtr<RenderStyle> oldStyle = renderStyle();
RefPtr<RenderStyle> newStyle = styleForRenderer();
- StyleRecalcChange localChange = RenderStyle::compare(oldStyle.get(), newStyle.get());
+ StyleRecalcChange localChange = RenderStyle::stylePropagationDiff(oldStyle.get(), newStyle.get());
ASSERT(newStyle);
if (localChange == Reattach) {
AttachContext reattachContext;
reattachContext.resolvedStyle = newStyle.get();
+ bool rendererWillChange = needsAttach() || renderer();
reattach(reattachContext);
- return Reattach;
+ if (rendererWillChange || renderer())
+ return Reattach;
+ return ReattachNoRenderer;
}
ASSERT(oldStyle);
- InspectorInstrumentation::didRecalculateStyleForElement(this);
-
if (localChange != NoChange)
updateCallbackSelectors(oldStyle.get(), newStyle.get());
if (RenderObject* renderer = this->renderer()) {
- if (localChange != NoChange || pseudoStyleCacheIsInvalid(oldStyle.get(), newStyle.get()) || shouldNotifyRendererWithIdenticalStyles()) {
- renderer->setAnimatableStyle(newStyle.get());
+ if (localChange != NoChange || pseudoStyleCacheIsInvalid(oldStyle.get(), newStyle.get()) || svgFilterNeedsLayerUpdate()) {
+ renderer->setStyle(newStyle.get());
} else {
// Although no change occurred, we use the new style so that the cousin style sharing code won't get
// fooled into believing this style is the same.
@@ -1596,98 +1572,63 @@ StyleRecalcChange Element::recalcOwnStyle(StyleRecalcChange change)
}
}
- // If "rem" units are used anywhere in the document, and if the document element's font size changes, then go ahead and force font updating
- // all the way down the tree. This is simpler than having to maintain a cache of objects (and such font size changes should be rare anyway).
- if (document().styleEngine()->usesRemUnits() && document().documentElement() == this && oldStyle->fontSize() != newStyle->fontSize()) {
- // Cached RenderStyles may depend on the re units.
- document().ensureStyleResolver().invalidateMatchedPropertiesCache();
- return Force;
- }
-
if (styleChangeType() >= SubtreeStyleChange)
return Force;
- return max(localChange, change);
+ if (change > Inherit || localChange > Inherit)
+ return max(localChange, change);
+
+ if (localChange < Inherit && (oldStyle->hasPseudoElementStyle() || newStyle->hasPseudoElementStyle()))
+ return UpdatePseudoElements;
+
+ return localChange;
}
void Element::recalcChildStyle(StyleRecalcChange change)
{
ASSERT(document().inStyleRecalc());
- ASSERT(change >= Inherit || childNeedsStyleRecalc());
+ ASSERT(change >= UpdatePseudoElements || childNeedsStyleRecalc());
ASSERT(!needsStyleRecalc());
- StyleResolverParentPusher parentPusher(*this);
+ StyleResolverParentScope parentScope(*this);
- for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
- if (shouldRecalcStyle(change, root)) {
- parentPusher.push();
- root->recalcStyle(change);
+ updatePseudoElement(BEFORE, change);
+
+ if (change > UpdatePseudoElements || childNeedsStyleRecalc()) {
+ for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
+ if (root->shouldCallRecalcStyle(change))
+ root->recalcStyle(change);
}
}
- if (shouldRecalcStyle(change, this))
- updatePseudoElement(BEFORE, change);
-
if (change < Force && hasRareData() && childNeedsStyleRecalc())
checkForChildrenAdjacentRuleChanges();
- // This loop is deliberately backwards because we use insertBefore in the rendering tree, and want to avoid
- // a potentially n^2 loop to find the insertion point while resolving style. Having us start from the last
- // child and work our way back means in the common case, we'll find the insertion point in O(1) time.
- // See crbug.com/288225
- StyleResolver& styleResolver = document().ensureStyleResolver();
- Text* lastTextNode = 0;
- for (Node* child = lastChild(); child; child = child->previousSibling()) {
- if (child->isTextNode()) {
- toText(child)->recalcTextStyle(change, lastTextNode);
- lastTextNode = toText(child);
- } else if (child->isElementNode()) {
- Element* element = toElement(child);
- if (shouldRecalcStyle(change, element)) {
- parentPusher.push();
- element->recalcStyle(change, lastTextNode);
- } else if (element->supportsStyleSharing()) {
- styleResolver.addToStyleSharingList(*element);
+ if (change > UpdatePseudoElements || childNeedsStyleRecalc()) {
+ // This loop is deliberately backwards because we use insertBefore in the rendering tree, and want to avoid
+ // a potentially n^2 loop to find the insertion point while resolving style. Having us start from the last
+ // child and work our way back means in the common case, we'll find the insertion point in O(1) time.
+ // See crbug.com/288225
+ StyleResolver& styleResolver = document().ensureStyleResolver();
+ Text* lastTextNode = 0;
+ for (Node* child = lastChild(); child; child = child->previousSibling()) {
+ if (child->isTextNode()) {
+ toText(child)->recalcTextStyle(change, lastTextNode);
+ lastTextNode = toText(child);
+ } else if (child->isElementNode()) {
+ Element* element = toElement(child);
+ if (element->shouldCallRecalcStyle(change))
+ element->recalcStyle(change, lastTextNode);
+ else if (element->supportsStyleSharing())
+ styleResolver.addToStyleSharingList(*element);
+ if (element->renderer())
+ lastTextNode = 0;
}
- if (element->renderer())
- lastTextNode = 0;
}
}
- if (shouldRecalcStyle(change, this)) {
- updatePseudoElement(AFTER, change);
- updatePseudoElement(BACKDROP, change);
- }
-}
-
-void Element::checkForChildrenAdjacentRuleChanges()
-{
- bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
- bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
-
- if (!hasDirectAdjacentRules && !hasIndirectAdjacentRules)
- return;
-
- unsigned forceCheckOfNextElementCount = 0;
- bool forceCheckOfAnyElementSibling = false;
-
- for (Node* child = firstChild(); child; child = child->nextSibling()) {
- if (!child->isElementNode())
- continue;
- Element* element = toElement(child);
- bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() >= SubtreeStyleChange;
-
- if (forceCheckOfNextElementCount || forceCheckOfAnyElementSibling)
- element->setNeedsStyleRecalc();
-
- if (forceCheckOfNextElementCount)
- forceCheckOfNextElementCount--;
-
- if (childRulesChanged && hasDirectAdjacentRules)
- forceCheckOfNextElementCount = document().styleEngine()->maxDirectAdjacentSelectors();
-
- forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
- }
+ updatePseudoElement(AFTER, change);
+ updatePseudoElement(BACKDROP, change);
}
void Element::updateCallbackSelectors(RenderStyle* oldStyle, RenderStyle* newStyle)
@@ -1723,42 +1664,70 @@ ElementShadow& Element::ensureShadow()
void Element::didAffectSelector(AffectedSelectorMask mask)
{
- setNeedsStyleRecalc();
+ setNeedsStyleRecalc(SubtreeStyleChange);
if (ElementShadow* elementShadow = shadowWhereNodeCanBeDistributed(*this))
elementShadow->didAffectSelector(mask);
}
void Element::setAnimationStyleChange(bool animationStyleChange)
{
+ if (animationStyleChange && document().inStyleRecalc())
+ return;
if (ActiveAnimations* activeAnimations = elementRareData()->activeAnimations())
activeAnimations->setAnimationStyleChange(animationStyleChange);
}
void Element::setNeedsAnimationStyleRecalc()
{
- bool recalcPending = styleChangeType() != NoStyleChange;
- setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer);
+ if (styleChangeType() != NoStyleChange)
+ return;
- if (!recalcPending)
- setAnimationStyleChange(true);
+ setNeedsStyleRecalc(LocalStyleChange);
+ setAnimationStyleChange(true);
+}
+
+void Element::setNeedsCompositingUpdate()
+{
+ if (!document().isActive())
+ return;
+ RenderBoxModelObject* renderer = renderBoxModelObject();
+ if (!renderer)
+ return;
+ if (!renderer->hasLayer())
+ return;
+ renderer->layer()->setNeedsCompositingInputsUpdate();
+ document().renderView()->compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange);
}
-PassRefPtr<ShadowRoot> Element::createShadowRoot(ExceptionState& exceptionState)
+void Element::setCustomElementDefinition(PassRefPtr<CustomElementDefinition> definition)
+{
+ if (!hasRareData() && !definition)
+ return;
+ ASSERT(!customElementDefinition());
+ ensureElementRareData().setCustomElementDefinition(definition);
+}
+
+CustomElementDefinition* Element::customElementDefinition() const
+{
+ if (hasRareData())
+ return elementRareData()->customElementDefinition();
+ return 0;
+}
+
+PassRefPtrWillBeRawPtr<ShadowRoot> Element::createShadowRoot(ExceptionState& exceptionState)
{
if (alwaysCreateUserAgentShadowRoot())
ensureUserAgentShadowRoot();
- if (RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled())
- return PassRefPtr<ShadowRoot>(ensureShadow().addShadowRoot(*this, ShadowRoot::AuthorShadowRoot));
-
- // Since some elements recreates shadow root dynamically, multiple shadow
- // subtrees won't work well in that element. Until they are fixed, we disable
- // adding author shadow root for them.
- if (!areAuthorShadowsAllowed()) {
- exceptionState.throwUninformativeAndGenericDOMException(HierarchyRequestError);
- return 0;
+ // Some elements make assumptions about what kind of renderers they allow
+ // as children so we can't allow author shadows on them for now. An override
+ // flag is provided for testing how author shadows interact on these elements.
+ if (!areAuthorShadowsAllowed() && !RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled()) {
+ exceptionState.throwDOMException(HierarchyRequestError, "Author-created shadow roots are disabled for this element.");
+ return nullptr;
}
- return PassRefPtr<ShadowRoot>(ensureShadow().addShadowRoot(*this, ShadowRoot::AuthorShadowRoot));
+
+ return PassRefPtrWillBeRawPtr<ShadowRoot>(ensureShadow().addShadowRoot(*this, ShadowRoot::AuthorShadowRoot));
}
ShadowRoot* Element::shadowRoot() const
@@ -1772,10 +1741,6 @@ ShadowRoot* Element::shadowRoot() const
return 0;
}
-void Element::didAddShadowRoot(ShadowRoot&)
-{
-}
-
ShadowRoot* Element::userAgentShadowRoot() const
{
if (ElementShadow* elementShadow = shadow()) {
@@ -1812,117 +1777,34 @@ bool Element::childTypeAllowed(NodeType type) const
return false;
}
-void Element::checkForEmptyStyleChange(RenderStyle* style)
+void Element::checkForEmptyStyleChange()
{
- if (!style && !styleAffectedByEmpty())
- return;
-
- if (!style || (styleAffectedByEmpty() && (!style->emptyState() || hasChildNodes())))
- setNeedsStyleRecalc();
-}
-
-void Element::checkForSiblingStyleChanges(bool finishedParsingCallback, Node* beforeChange, Node* afterChange, int childCountDelta)
-{
- if (!inActiveDocument() || document().hasPendingForcedStyleRecalc() || styleChangeType() >= SubtreeStyleChange)
- return;
-
RenderStyle* style = renderStyle();
- // :empty selector.
- checkForEmptyStyleChange(style);
-
- if (!style || (needsStyleRecalc() && childrenAffectedByPositionalRules()))
- return;
-
- // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
- // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
- // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
- // backward case.
- // |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 ((childrenAffectedByForwardPositionalRules() && afterChange) || (childrenAffectedByBackwardPositionalRules() && beforeChange)) {
- setNeedsStyleRecalc();
+ if (!style && !styleAffectedByEmpty())
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 (childrenAffectedByFirstChildRules() && afterChange) {
- // Find our new first child.
- Node* newFirstChild = firstElementChild();
- RenderStyle* newFirstChildStyle = newFirstChild ? newFirstChild->renderStyle() : 0;
-
- // Find the first element node following |afterChange|
- Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling();
- RenderStyle* firstElementAfterInsertionStyle = firstElementAfterInsertion ? firstElementAfterInsertion->renderStyle() : 0;
-
- // This is the insert/append case.
- if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertionStyle && firstElementAfterInsertionStyle->firstChildState())
- firstElementAfterInsertion->setNeedsStyleRecalc();
-
- // We also have to handle node removal.
- if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChildStyle || !newFirstChildStyle->firstChildState()))
- newFirstChild->setNeedsStyleRecalc();
- }
-
- // :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 (childrenAffectedByLastChildRules() && beforeChange) {
- // Find our new last child.
- Node* newLastChild = lastElementChild();
- RenderStyle* newLastChildStyle = newLastChild ? newLastChild->renderStyle() : 0;
- // Find the last element node going backwards from |beforeChange|
- Node* lastElementBeforeInsertion = beforeChange->isElementNode() ? beforeChange : beforeChange->previousElementSibling();
- RenderStyle* lastElementBeforeInsertionStyle = lastElementBeforeInsertion ? lastElementBeforeInsertion->renderStyle() : 0;
-
- if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertionStyle && lastElementBeforeInsertionStyle->lastChildState())
- lastElementBeforeInsertion->setNeedsStyleRecalc();
-
- // We also have to handle node removal. The parser callback case is similar to node removal as well in that we need to change the last child
- // to match now.
- if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChildStyle || !newLastChildStyle->lastChildState()))
- newLastChild->setNeedsStyleRecalc();
- }
-
- // 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 (childrenAffectedByDirectAdjacentRules() && afterChange) {
- if (Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling())
- firstElementAfterInsertion->setNeedsStyleRecalc();
- }
+ if (!style || (styleAffectedByEmpty() && (!style->emptyState() || hasChildren())))
+ setNeedsStyleRecalc(SubtreeStyleChange);
}
void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
{
ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
- if (changedByParser)
- checkForEmptyStyleChange(renderStyle());
- else
+
+ checkForEmptyStyleChange();
+ if (!changedByParser)
checkForSiblingStyleChanges(false, beforeChange, afterChange, childCountDelta);
if (ElementShadow* shadow = this->shadow())
shadow->setNeedsDistributionRecalc();
}
-void Element::removeAllEventListeners()
-{
- ContainerNode::removeAllEventListeners();
- if (ElementShadow* shadow = this->shadow())
- shadow->removeAllEventListeners();
-}
-
-void Element::beginParsingChildren()
-{
- clearIsParsingChildrenFinished();
-}
-
void Element::finishParsingChildren()
{
- setIsParsingChildrenFinished();
- checkForSiblingStyleChanges(this, lastChild(), 0, 0);
+ setIsFinishedParsingChildren(true);
+ checkForEmptyStyleChange();
+ checkForSiblingStyleChanges(true, lastChild(), 0, 0);
}
#ifndef NDEBUG
@@ -1953,81 +1835,127 @@ void Element::formatForDebugger(char* buffer, unsigned length) const
}
#endif
-const Vector<RefPtr<Attr> >& Element::attrNodeList()
+WillBeHeapVector<RefPtrWillBeMember<Attr> >* Element::attrNodeList()
+{
+ return hasRareData() ? elementRareData()->attrNodeList() : 0;
+}
+
+WillBeHeapVector<RefPtrWillBeMember<Attr> >& Element::ensureAttrNodeList()
+{
+ setHasSyntheticAttrChildNodes(true);
+ return ensureElementRareData().ensureAttrNodeList();
+}
+
+void Element::removeAttrNodeList()
{
ASSERT(hasSyntheticAttrChildNodes());
- return *attrNodeListForElement(this);
+ if (hasRareData())
+ elementRareData()->removeAttrNodeList();
+ setHasSyntheticAttrChildNodes(false);
}
-PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionState& exceptionState)
+PassRefPtrWillBeRawPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionState& exceptionState)
{
if (!attrNode) {
- exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
- return 0;
+ exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "Attr"));
+ return nullptr;
}
- RefPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName());
+ RefPtrWillBeRawPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName());
if (oldAttrNode.get() == attrNode)
return attrNode; // This Attr is already attached to the element.
// InUseAttributeError: Raised if node is an Attr that is already an attribute of another Element object.
// The DOM user must explicitly clone Attr nodes to re-use them in other elements.
if (attrNode->ownerElement()) {
- exceptionState.throwUninformativeAndGenericDOMException(InUseAttributeError);
- return 0;
+ exceptionState.throwDOMException(InUseAttributeError, "The node provided is an attribute node that is already an attribute of another Element; attribute nodes must be explicitly cloned.");
+ return nullptr;
}
synchronizeAllAttributes();
- UniqueElementData* elementData = ensureUniqueElementData();
+ UniqueElementData& elementData = ensureUniqueElementData();
- size_t index = elementData->getAttributeItemIndex(attrNode->qualifiedName(), shouldIgnoreAttributeCase());
+ size_t index = elementData.findAttributeIndexByName(attrNode->qualifiedName(), shouldIgnoreAttributeCase());
+ AtomicString localName;
if (index != kNotFound) {
- if (oldAttrNode)
- detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData->attributeItem(index)->value());
- else
- oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), elementData->attributeItem(index)->value());
+ const Attribute& attr = elementData.attributeAt(index);
+
+ // If the name of the ElementData attribute doesn't
+ // (case-sensitively) match that of the Attr node, record it
+ // on the Attr so that it can correctly resolve the value on
+ // the Element.
+ if (!attr.name().matches(attrNode->qualifiedName()))
+ localName = attr.localName();
+
+ if (oldAttrNode) {
+ detachAttrNodeFromElementWithValue(oldAttrNode.get(), attr.value());
+ } else {
+ // FIXME: using attrNode's name rather than the
+ // Attribute's for the replaced Attr is compatible with
+ // all but Gecko (and, arguably, the DOM Level1 spec text.)
+ // Consider switching.
+ oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), attr.value());
+ }
}
setAttributeInternal(index, attrNode->qualifiedName(), attrNode->value(), NotInSynchronizationOfLazyAttribute);
- attrNode->attachToElement(this);
+ attrNode->attachToElement(this, localName);
treeScope().adoptIfNeeded(*attrNode);
- ensureAttrNodeListForElement(this).append(attrNode);
+ ensureAttrNodeList().append(attrNode);
return oldAttrNode.release();
}
-PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionState& exceptionState)
+PassRefPtrWillBeRawPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionState& exceptionState)
{
return setAttributeNode(attr, exceptionState);
}
-PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionState& exceptionState)
+PassRefPtrWillBeRawPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionState& exceptionState)
{
if (!attr) {
- exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
- return 0;
+ exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "Attr"));
+ return nullptr;
}
if (attr->ownerElement() != this) {
- exceptionState.throwUninformativeAndGenericDOMException(NotFoundError);
- return 0;
+ exceptionState.throwDOMException(NotFoundError, "The node provided is owned by another element.");
+ return nullptr;
}
ASSERT(document() == attr->document());
synchronizeAttribute(attr->qualifiedName());
- size_t index = elementData()->getAttrIndex(attr);
+ size_t index = elementData()->findAttrNodeIndex(attr);
if (index == kNotFound) {
- exceptionState.throwUninformativeAndGenericDOMException(NotFoundError);
- return 0;
+ exceptionState.throwDOMException(NotFoundError, "The attribute was not found on this element.");
+ return nullptr;
}
- RefPtr<Attr> guard(attr);
+ RefPtrWillBeRawPtr<Attr> guard(attr);
detachAttrNodeAtIndex(attr, index);
return guard.release();
}
+void Element::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+ if (name == tabindexAttr) {
+ int tabindex = 0;
+ if (value.isEmpty()) {
+ clearTabIndexExplicitlyIfNeeded();
+ if (treeScope().adjustedFocusedElement() == this) {
+ // We might want to call blur(), but it's dangerous to dispatch
+ // events here.
+ document().setNeedsFocusedElementCheck();
+ }
+ } else if (parseHTMLInteger(value, tabindex)) {
+ // Clamp tabindex to the range of 'short' to match Firefox's behavior.
+ setTabIndexExplicitly(max(static_cast<int>(std::numeric_limits<short>::min()), std::min(tabindex, static_cast<int>(std::numeric_limits<short>::max()))));
+ }
+ }
+}
+
bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionState& exceptionState)
{
AtomicString prefix, localName;
@@ -2038,7 +1966,7 @@ bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespa
QualifiedName qName(prefix, localName, namespaceURI);
if (!Document::hasValidNamespaceForAttributes(qName)) {
- exceptionState.throwUninformativeAndGenericDOMException(NamespaceError);
+ exceptionState.throwDOMException(NamespaceError, "'" + namespaceURI + "' is an invalid namespace for attributes.");
return false;
}
@@ -2058,30 +1986,30 @@ void Element::removeAttributeInternal(size_t index, SynchronizationOfLazyAttribu
{
ASSERT_WITH_SECURITY_IMPLICATION(index < attributeCount());
- UniqueElementData* elementData = ensureUniqueElementData();
+ UniqueElementData& elementData = ensureUniqueElementData();
- QualifiedName name = elementData->attributeItem(index)->name();
- AtomicString valueBeingRemoved = elementData->attributeItem(index)->value();
+ QualifiedName name = elementData.attributeAt(index).name();
+ AtomicString valueBeingRemoved = elementData.attributeAt(index).value();
if (!inSynchronizationOfLazyAttribute) {
if (!valueBeingRemoved.isNull())
willModifyAttribute(name, valueBeingRemoved, nullAtom);
}
- if (RefPtr<Attr> attrNode = attrIfExists(name))
- detachAttrNodeFromElementWithValue(attrNode.get(), elementData->attributeItem(index)->value());
+ if (RefPtrWillBeRawPtr<Attr> attrNode = attrIfExists(name))
+ detachAttrNodeFromElementWithValue(attrNode.get(), elementData.attributeAt(index).value());
- elementData->removeAttribute(index);
+ elementData.removeAttributeAt(index);
if (!inSynchronizationOfLazyAttribute)
didRemoveAttribute(name);
}
-void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
+void Element::appendAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
{
if (!inSynchronizationOfLazyAttribute)
willModifyAttribute(name, nullAtom, value);
- ensureUniqueElementData()->addAttribute(name, value);
+ ensureUniqueElementData().appendAttribute(name, value);
if (!inSynchronizationOfLazyAttribute)
didAddAttribute(name, value);
}
@@ -2092,7 +2020,7 @@ void Element::removeAttribute(const AtomicString& name)
return;
AtomicString localName = shouldIgnoreAttributeCase() ? name.lower() : name;
- size_t index = elementData()->getAttributeItemIndex(localName, false);
+ size_t index = elementData()->findAttributeIndexByName(localName, false);
if (index == kNotFound) {
if (UNLIKELY(localName == styleAttr) && elementData()->m_styleAttributeIsDirty && isStyledElement())
removeAllInlineStyleProperties();
@@ -2107,26 +2035,26 @@ void Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicSt
removeAttribute(QualifiedName(nullAtom, localName, namespaceURI));
}
-PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& localName)
+PassRefPtrWillBeRawPtr<Attr> Element::getAttributeNode(const AtomicString& localName)
{
if (!elementData())
- return 0;
+ return nullptr;
synchronizeAttribute(localName);
- const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase());
+ const Attribute* attribute = elementData()->findAttributeByName(localName, shouldIgnoreAttributeCase());
if (!attribute)
- return 0;
+ return nullptr;
return ensureAttr(attribute->name());
}
-PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
+PassRefPtrWillBeRawPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
{
if (!elementData())
- return 0;
+ return nullptr;
QualifiedName qName(nullAtom, localName, namespaceURI);
synchronizeAttribute(qName);
- const Attribute* attribute = elementData()->getAttributeItem(qName);
+ const Attribute* attribute = elementData()->findAttributeByName(qName);
if (!attribute)
- return 0;
+ return nullptr;
return ensureAttr(attribute->name());
}
@@ -2135,7 +2063,7 @@ bool Element::hasAttribute(const AtomicString& localName) const
if (!elementData())
return false;
synchronizeAttribute(localName);
- return elementData()->getAttributeItem(shouldIgnoreAttributeCase() ? localName.lower() : localName, false);
+ return elementData()->findAttributeByName(shouldIgnoreAttributeCase() ? localName.lower() : localName, false);
}
bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
@@ -2144,47 +2072,32 @@ bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicStrin
return false;
QualifiedName qName(nullAtom, localName, namespaceURI);
synchronizeAttribute(qName);
- return elementData()->getAttributeItem(qName);
+ return elementData()->findAttributeByName(qName);
}
-void Element::focus(bool restorePreviousSelection, FocusDirection direction)
+void Element::focus(bool restorePreviousSelection, FocusType type)
{
if (!inDocument())
return;
- Document& doc = document();
- if (doc.focusedElement() == this)
+ if (document().focusedElement() == this)
return;
- // If the stylesheets have already been loaded we can reliably check isFocusable.
- // If not, we continue and set the focused node on the focus controller below so
- // that it can be updated soon after attach.
- if (doc.haveStylesheetsLoaded()) {
- doc.updateLayoutIgnorePendingStylesheets();
- if (!isFocusable())
- return;
- }
+ if (!document().isActive())
+ return;
- if (!supportsFocus())
+ document().updateLayoutIgnorePendingStylesheets();
+ if (!isFocusable())
return;
- RefPtr<Node> protect;
- if (Page* page = doc.page()) {
- // Focus and change event handlers can cause us to lose our last ref.
- // If a focus event handler changes the focus to a different node it
- // does not make sense to continue and update appearence.
- protect = this;
- if (!page->focusController().setFocusedElement(this, doc.frame(), direction))
- return;
- }
+ RefPtrWillBeRawPtr<Node> protect(this);
+ if (!document().page()->focusController().setFocusedElement(this, document().frame(), type))
+ return;
// Setting the focused node above might have invalidated the layout due to scripts.
- doc.updateLayoutIgnorePendingStylesheets();
-
- if (!isFocusable()) {
- ensureElementRareData().setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
+ document().updateLayoutIgnorePendingStylesheets();
+ if (!isFocusable())
return;
- }
cancelFocusAppearanceUpdate();
updateFocusAppearance(restorePreviousSelection);
@@ -2193,7 +2106,8 @@ void Element::focus(bool restorePreviousSelection, FocusDirection direction)
void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
{
if (isRootEditableElement()) {
- Frame* frame = document().frame();
+ // Taking the ownership since setSelection() may release the last reference to |frame|.
+ RefPtr<LocalFrame> frame(document().frame());
if (!frame)
return;
@@ -2203,7 +2117,9 @@ void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
// FIXME: We should restore the previous selection if there is one.
VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
- frame->selection().setSelection(newSelection);
+ // Passing DoNotSetFocus as this function is called after FocusController::setFocusedElement()
+ // and we don't want to change the focus to a new Element.
+ frame->selection().setSelection(newSelection, FrameSelection::DoNotSetFocus);
frame->selection().revealSelection();
} else if (renderer() && !renderer()->isWidget())
renderer()->scrollRectToVisible(boundingBox());
@@ -2217,10 +2133,37 @@ void Element::blur()
if (doc.page())
doc.page()->focusController().setFocusedElement(0, doc.frame());
else
- doc.setFocusedElement(0);
+ doc.setFocusedElement(nullptr);
}
}
+bool Element::supportsFocus() const
+{
+ // FIXME: supportsFocus() can be called when layout is not up to date.
+ // Logic that deals with the renderer should be moved to rendererIsFocusable().
+ // But supportsFocus must return true when the element is editable, or else
+ // it won't be focusable. Furthermore, supportsFocus cannot just return true
+ // always or else tabIndex() will change for all HTML elements.
+ return hasElementFlag(TabIndexWasSetExplicitly) || (rendererIsEditable() && parentNode() && !parentNode()->rendererIsEditable())
+ || supportsSpatialNavigationFocus();
+}
+
+bool Element::supportsSpatialNavigationFocus() const
+{
+ // This function checks whether the element satisfies the extended criteria
+ // for the element to be focusable, introduced by spatial navigation feature,
+ // i.e. checks if click or keyboard event handler is specified.
+ // This is the way to make it possible to navigate to (focus) elements
+ // which web designer meant for being active (made them respond to click events).
+
+ if (!document().settings() || !document().settings()->spatialNavigationEnabled())
+ return false;
+ return hasEventListeners(EventTypeNames::click)
+ || hasEventListeners(EventTypeNames::keydown)
+ || hasEventListeners(EventTypeNames::keypress)
+ || hasEventListeners(EventTypeNames::keyup);
+}
+
bool Element::isFocusable() const
{
return inDocument() && supportsFocus() && !isInert() && rendererIsFocusable();
@@ -2236,15 +2179,15 @@ bool Element::isMouseFocusable() const
return isFocusable();
}
-void Element::dispatchFocusEvent(Element* oldFocusedElement, FocusDirection)
+void Element::dispatchFocusEvent(Element* oldFocusedElement, FocusType)
{
- RefPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::focus, false, false, document().domWindow(), 0, oldFocusedElement);
+ RefPtrWillBeRawPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::focus, false, false, document().domWindow(), 0, oldFocusedElement);
EventDispatcher::dispatchEvent(this, FocusEventDispatchMediator::create(event.release()));
}
void Element::dispatchBlurEvent(Element* newFocusedElement)
{
- RefPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::blur, false, false, document().domWindow(), 0, newFocusedElement);
+ RefPtrWillBeRawPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::blur, false, false, document().domWindow(), 0, newFocusedElement);
EventDispatcher::dispatchEvent(this, BlurEventDispatchMediator::create(event.release()));
}
@@ -2274,9 +2217,9 @@ String Element::outerHTML() const
void Element::setInnerHTML(const String& html, ExceptionState& exceptionState)
{
- if (RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(html, this, AllowScriptingContent, "innerHTML", exceptionState)) {
+ if (RefPtrWillBeRawPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(html, this, AllowScriptingContent, "innerHTML", exceptionState)) {
ContainerNode* container = this;
- if (hasTagName(templateTag))
+ if (isHTMLTemplateElement(*this))
container = toHTMLTemplateElement(this)->content();
replaceChildrenWithFragment(container, fragment.release(), exceptionState);
}
@@ -2285,20 +2228,25 @@ void Element::setInnerHTML(const String& html, ExceptionState& exceptionState)
void Element::setOuterHTML(const String& html, ExceptionState& exceptionState)
{
Node* p = parentNode();
- if (!p || !p->isElementNode()) {
- exceptionState.throwUninformativeAndGenericDOMException(NoModificationAllowedError);
+ if (!p) {
+ exceptionState.throwDOMException(NoModificationAllowedError, "This element has no parent node.");
+ return;
+ }
+ if (!p->isElementNode()) {
+ exceptionState.throwDOMException(NoModificationAllowedError, "This element's parent is of type '" + p->nodeName() + "', which is not an element node.");
return;
}
- RefPtr<Element> parent = toElement(p);
- RefPtr<Node> prev = previousSibling();
- RefPtr<Node> next = nextSibling();
- RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(html, parent.get(), AllowScriptingContent, "outerHTML", exceptionState);
+ RefPtrWillBeRawPtr<Element> parent = toElement(p);
+ RefPtrWillBeRawPtr<Node> prev = previousSibling();
+ RefPtrWillBeRawPtr<Node> next = nextSibling();
+
+ RefPtrWillBeRawPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(html, parent.get(), AllowScriptingContent, "outerHTML", exceptionState);
if (exceptionState.hadException())
return;
parent->replaceChild(fragment.release(), this, exceptionState);
- RefPtr<Node> node = next ? next->previousSibling() : 0;
+ RefPtrWillBeRawPtr<Node> node = next ? next->previousSibling() : 0;
if (!exceptionState.hadException() && node && node->isTextNode())
mergeWithNextTextNode(node.release(), exceptionState);
@@ -2357,13 +2305,30 @@ static Element* contextElementForInsertion(const String& where, Element* element
return 0;
}
+Element* Element::insertAdjacentElement(const String& where, Element* newChild, ExceptionState& exceptionState)
+{
+ if (!newChild) {
+ // IE throws COM Exception E_INVALIDARG; this is the best DOM exception alternative.
+ exceptionState.throwTypeError("The node provided is null.");
+ return 0;
+ }
+
+ Node* returnValue = insertAdjacent(where, newChild, exceptionState);
+ return toElement(returnValue);
+}
+
+void Element::insertAdjacentText(const String& where, const String& text, ExceptionState& exceptionState)
+{
+ insertAdjacent(where, document().createTextNode(text).get(), exceptionState);
+}
+
void Element::insertAdjacentHTML(const String& where, const String& markup, ExceptionState& exceptionState)
{
- RefPtr<Element> contextElement = contextElementForInsertion(where, this, exceptionState);
+ RefPtrWillBeRawPtr<Element> contextElement = contextElementForInsertion(where, this, exceptionState);
if (!contextElement)
return;
- RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(markup, contextElement.get(), AllowScriptingContent, "insertAdjacentHTML", exceptionState);
+ RefPtrWillBeRawPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(markup, contextElement.get(), AllowScriptingContent, "insertAdjacentHTML", exceptionState);
if (!fragment)
return;
insertAdjacent(where, fragment.get(), exceptionState);
@@ -2430,15 +2395,19 @@ String Element::textFromChildren()
return content.toString();
}
-// pseudo is used via shadowPseudoId.
-const AtomicString& Element::pseudo() const
+const AtomicString& Element::shadowPseudoId() const
{
- return getAttribute(pseudoAttr);
+ if (ShadowRoot* root = containingShadowRoot()) {
+ if (root->type() == ShadowRoot::UserAgentShadowRoot)
+ return fastGetAttribute(pseudoAttr);
+ }
+ return nullAtom;
}
-void Element::setPseudo(const AtomicString& value)
+void Element::setShadowPseudoId(const AtomicString& id)
{
- setAttribute(pseudoAttr, value);
+ ASSERT(CSSSelector::parsePseudoType(id) == CSSSelector::PseudoWebKitCustomElement || CSSSelector::parsePseudoType(id) == CSSSelector::PseudoUserAgentCustomElement);
+ setAttribute(pseudoAttr, id);
}
bool Element::isInDescendantTreeOf(const Element* shadowHost) const
@@ -2495,178 +2464,6 @@ RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
return pseudoElementSpecifier ? rareData.computedStyle()->getCachedPseudoStyle(pseudoElementSpecifier) : rareData.computedStyle();
}
-void Element::setStyleAffectedByEmpty()
-{
- ensureElementRareData().setStyleAffectedByEmpty(true);
-}
-
-void Element::setChildrenAffectedByFocus()
-{
- ensureElementRareData().setChildrenAffectedByFocus(true);
-}
-
-void Element::setChildrenAffectedByHover()
-{
- ensureElementRareData().setChildrenAffectedByHover(true);
-}
-
-void Element::setChildrenAffectedByActive()
-{
- ensureElementRareData().setChildrenAffectedByActive(true);
-}
-
-void Element::setChildrenAffectedByDrag()
-{
- ensureElementRareData().setChildrenAffectedByDrag(true);
-}
-
-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::childrenSupportStyleSharing() const
-{
- if (!hasRareData())
- return true;
- return !rareDataChildrenAffectedByFocus()
- && !rareDataChildrenAffectedByHover()
- && !rareDataChildrenAffectedByActive()
- && !rareDataChildrenAffectedByDrag()
- && !rareDataChildrenAffectedByFirstChildRules()
- && !rareDataChildrenAffectedByLastChildRules()
- && !rareDataChildrenAffectedByDirectAdjacentRules()
- && !rareDataChildrenAffectedByForwardPositionalRules()
- && !rareDataChildrenAffectedByBackwardPositionalRules();
-}
-
-bool Element::rareDataStyleAffectedByEmpty() const
-{
- ASSERT(hasRareData());
- return elementRareData()->styleAffectedByEmpty();
-}
-
-bool Element::rareDataChildrenAffectedByFocus() const
-{
- ASSERT(hasRareData());
- return elementRareData()->childrenAffectedByFocus();
-}
-
-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
-{
- ASSERT(hasRareData());
- return elementRareData()->childIndex();
-}
-
-void Element::setIsInCanvasSubtree(bool isInCanvasSubtree)
-{
- ensureElementRareData().setIsInCanvasSubtree(isInCanvasSubtree);
-}
-
-bool Element::isInCanvasSubtree() const
-{
- return hasRareData() && elementRareData()->isInCanvasSubtree();
-}
-
-void Element::setIsInsideRegion(bool value)
-{
- if (value == isInsideRegion())
- return;
-
- ensureElementRareData().setIsInsideRegion(value);
-}
-
-bool Element::isInsideRegion() const
-{
- return hasRareData() ? elementRareData()->isInsideRegion() : false;
-}
-
-void Element::setRegionOversetState(RegionOversetState state)
-{
- ensureElementRareData().setRegionOversetState(state);
-}
-
-RegionOversetState Element::regionOversetState() const
-{
- return hasRareData() ? elementRareData()->regionOversetState() : RegionUndefined;
-}
-
AtomicString Element::computeInheritedLanguage() const
{
const Node* n = this;
@@ -2676,9 +2473,9 @@ AtomicString Element::computeInheritedLanguage() const
if (n->isElementNode()) {
if (const ElementData* elementData = toElement(n)->elementData()) {
// Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7
- if (const Attribute* attribute = elementData->getAttributeItem(XMLNames::langAttr))
+ if (const Attribute* attribute = elementData->findAttributeByName(XMLNames::langAttr))
value = attribute->value();
- else if (const Attribute* attribute = elementData->getAttributeItem(HTMLNames::langAttr))
+ else if (const Attribute* attribute = elementData->findAttributeByName(HTMLNames::langAttr))
value = attribute->value();
}
} else if (n->isDocumentNode()) {
@@ -2699,8 +2496,6 @@ Locale& Element::locale() const
void Element::cancelFocusAppearanceUpdate()
{
- if (hasRareData())
- elementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
if (document().focusedElement() == this)
document().cancelFocusAppearanceUpdate();
}
@@ -2709,16 +2504,20 @@ void Element::normalizeAttributes()
{
if (!hasAttributes())
return;
+ // attributeCount() cannot be cached before the loop because the attributes
+ // list is altered while iterating.
for (unsigned i = 0; i < attributeCount(); ++i) {
- if (RefPtr<Attr> attr = attrIfExists(attributeItem(i)->name()))
+ if (RefPtrWillBeRawPtr<Attr> attr = attrIfExists(attributeAt(i).name()))
attr->normalize();
}
}
void Element::updatePseudoElement(PseudoId pseudoId, StyleRecalcChange change)
{
+ ASSERT(!needsStyleRecalc());
PseudoElement* element = pseudoElement(pseudoId);
- if (element && (needsStyleRecalc() || shouldRecalcStyle(change, element))) {
+ if (element && (change == UpdatePseudoElements || element->shouldCallRecalcStyle(change))) {
+
// Need to clear the cached style if the PseudoElement wants a recalc so it
// computes a new style.
if (element->needsStyleRecalc())
@@ -2727,27 +2526,17 @@ void Element::updatePseudoElement(PseudoId pseudoId, StyleRecalcChange change)
// PseudoElement styles hang off their parent element's style so if we needed
// a style recalc we should Force one on the pseudo.
// FIXME: We should figure out the right text sibling to pass.
- element->recalcStyle(needsStyleRecalc() ? Force : change);
+ element->recalcStyle(change == UpdatePseudoElements ? Force : change);
// Wait until our parent is not displayed or pseudoElementRendererIsNeeded
// is false, otherwise we could continously create and destroy PseudoElements
// when RenderObject::isChildAllowed on our parent returns false for the
// PseudoElement's renderer for each style recalc.
if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
- elementRareData()->setPseudoElement(pseudoId, 0);
- } else if (change >= Inherit || needsStyleRecalc())
+ elementRareData()->setPseudoElement(pseudoId, nullptr);
+ } else if (change >= UpdatePseudoElements) {
createPseudoElementIfNeeded(pseudoId);
-}
-
-bool Element::needsPseudoElement(PseudoId pseudoId, const RenderStyle& style) const
-{
- if (pseudoId == BACKDROP && !isInTopLayer())
- return false;
- if (!renderer() || !pseudoElementRendererIsNeeded(&style))
- return false;
- if (!renderer()->canHaveGeneratedChildren())
- return false;
- return true;
+ }
}
void Element::createPseudoElementIfNeeded(PseudoId pseudoId)
@@ -2755,7 +2544,9 @@ void Element::createPseudoElementIfNeeded(PseudoId pseudoId)
if (isPseudoElement())
return;
- RefPtr<PseudoElement> element = document().ensureStyleResolver().createPseudoElementIfNeeded(*this, pseudoId);
+ // Document::ensureStyleResolver is not inlined and shows up on profiles, avoid it here.
+ StyleEngine* engine = document().styleEngine();
+ RefPtrWillBeRawPtr<PseudoElement> element = engine->ensureResolver().createPseudoElementIfNeeded(*this, pseudoId);
if (!element)
return;
@@ -2781,40 +2572,35 @@ RenderObject* Element::pseudoElementRenderer(PseudoId pseudoId) const
return 0;
}
-bool Element::webkitMatchesSelector(const String& selector, ExceptionState& exceptionState)
+bool Element::matches(const String& selectors, ExceptionState& exceptionState)
{
- if (selector.isEmpty()) {
- exceptionState.throwUninformativeAndGenericDOMException(SyntaxError);
- return false;
- }
-
- SelectorQuery* selectorQuery = document().selectorQueryCache().add(selector, document(), exceptionState);
+ SelectorQuery* selectorQuery = document().selectorQueryCache().add(AtomicString(selectors), document(), exceptionState);
if (!selectorQuery)
return false;
return selectorQuery->matches(*this);
}
-DOMTokenList* Element::classList()
+DOMTokenList& Element::classList()
{
ElementRareData& rareData = ensureElementRareData();
if (!rareData.classList())
rareData.setClassList(ClassList::create(this));
- return rareData.classList();
+ return *rareData.classList();
}
-DOMStringMap* Element::dataset()
+DOMStringMap& Element::dataset()
{
ElementRareData& rareData = ensureElementRareData();
if (!rareData.dataset())
rareData.setDataset(DatasetDOMStringMap::create(this));
- return rareData.dataset();
+ return *rareData.dataset();
}
KURL Element::getURLAttribute(const QualifiedName& name) const
{
-#if !ASSERT_DISABLED
+#if ASSERT_ENABLED
if (elementData()) {
- if (const Attribute* attribute = getAttributeItem(name))
+ if (const Attribute* attribute = findAttributeByName(name))
ASSERT(isURLAttribute(*attribute));
}
#endif
@@ -2823,9 +2609,9 @@ KURL Element::getURLAttribute(const QualifiedName& name) const
KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
{
-#if !ASSERT_DISABLED
+#if ASSERT_ENABLED
if (elementData()) {
- if (const Attribute* attribute = getAttributeItem(name))
+ if (const Attribute* attribute = findAttributeByName(name))
ASSERT(isURLAttribute(*attribute));
}
#endif
@@ -2870,33 +2656,19 @@ void Element::setFloatingPointAttribute(const QualifiedName& attributeName, doub
setAttribute(attributeName, AtomicString::number(value));
}
-bool Element::childShouldCreateRenderer(const Node& child) const
-{
- // Only create renderers for SVG elements whose parents are SVG elements, or for proper <svg xmlns="svgNS"> subdocuments.
- if (child.isSVGElement())
- return child.hasTagName(SVGNames::svgTag) || isSVGElement();
-
- return ContainerNode::childShouldCreateRenderer(child);
-}
-
void Element::webkitRequestFullscreen()
{
- FullscreenElementStack::from(&document())->requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
+ FullscreenElementStack::from(document()).requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
}
void Element::webkitRequestFullScreen(unsigned short flags)
{
- FullscreenElementStack::from(&document())->requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
-}
-
-bool Element::containsFullScreenElement() const
-{
- return hasRareData() && elementRareData()->containsFullScreenElement();
+ FullscreenElementStack::from(document()).requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
}
void Element::setContainsFullScreenElement(bool flag)
{
- ensureElementRareData().setContainsFullScreenElement(flag);
+ setElementFlag(ContainsFullScreenElement, flag);
setNeedsStyleRecalc(SubtreeStyleChange);
}
@@ -2913,16 +2685,11 @@ void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(boo
element->setContainsFullScreenElement(flag);
}
-bool Element::isInTopLayer() const
-{
- return hasRareData() && elementRareData()->isInTopLayer();
-}
-
void Element::setIsInTopLayer(bool inTopLayer)
{
if (isInTopLayer() == inTopLayer)
return;
- ensureElementRareData().setIsInTopLayer(inTopLayer);
+ setElementFlag(IsInTopLayer, inTopLayer);
// We must ensure a reattach occurs so the renderer is inserted in the correct sibling order under RenderView according to its
// top layer position, or in its usual place if not in the top layer.
@@ -2935,9 +2702,15 @@ void Element::webkitRequestPointerLock()
document().page()->pointerLockController().requestPointerLock(this);
}
+void Element::requestPointerLock()
+{
+ if (document().page())
+ document().page()->pointerLockController().requestPointerLock(this);
+}
+
SpellcheckAttributeState Element::spellcheckAttributeState() const
{
- const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
+ const AtomicString& value = fastGetAttribute(spellcheckAttr);
if (value == nullAtom)
return SpellcheckAttributeDefault;
if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
@@ -2964,79 +2737,6 @@ bool Element::isSpellCheckingEnabled() const
return true;
}
-RenderRegion* Element::renderRegion() const
-{
- if (renderer() && renderer()->isRenderNamedFlowFragmentContainer())
- return toRenderBlockFlow(renderer())->renderNamedFlowFragment();
-
- return 0;
-}
-
-bool Element::shouldMoveToFlowThread(RenderStyle* styleToUse) const
-{
- ASSERT(styleToUse);
-
- if (FullscreenElementStack::isActiveFullScreenElement(this))
- return false;
-
- if (isInShadowTree())
- return false;
-
- if (styleToUse->flowThread().isEmpty())
- return false;
-
- return !isRegisteredWithNamedFlow();
-}
-
-const AtomicString& Element::webkitRegionOverset() const
-{
- DEFINE_STATIC_LOCAL(AtomicString, undefinedState, ("undefined", AtomicString::ConstructFromLiteral));
- if (!RuntimeEnabledFeatures::cssRegionsEnabled())
- return undefinedState;
-
- document().updateLayoutIgnorePendingStylesheets();
-
- if (!renderRegion())
- return undefinedState;
-
- switch (renderRegion()->regionOversetState()) {
- case RegionFit: {
- DEFINE_STATIC_LOCAL(AtomicString, fitState, ("fit", AtomicString::ConstructFromLiteral));
- return fitState;
- }
- case RegionEmpty: {
- DEFINE_STATIC_LOCAL(AtomicString, emptyState, ("empty", AtomicString::ConstructFromLiteral));
- return emptyState;
- }
- case RegionOverset: {
- DEFINE_STATIC_LOCAL(AtomicString, overflowState, ("overset", AtomicString::ConstructFromLiteral));
- return overflowState;
- }
- case RegionUndefined:
- return undefinedState;
- }
-
- ASSERT_NOT_REACHED();
- return undefinedState;
-}
-
-Vector<RefPtr<Range> > Element::webkitGetRegionFlowRanges() const
-{
- Vector<RefPtr<Range> > rangeObjects;
- if (!RuntimeEnabledFeatures::cssRegionsEnabled())
- return rangeObjects;
-
- document().updateLayoutIgnorePendingStylesheets();
-
- if (renderer() && renderer()->isRenderNamedFlowFragmentContainer()) {
- RenderNamedFlowFragment* region = toRenderBlockFlow(renderer())->renderNamedFlowFragment();
- if (region->isValid())
- region->getRanges(rangeObjects);
- }
-
- return rangeObjects;
-}
-
#ifndef NDEBUG
bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
{
@@ -3096,7 +2796,7 @@ inline void Element::updateId(TreeScope& scope, const AtomicString& oldId, const
void Element::updateLabel(TreeScope& scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
{
- ASSERT(hasTagName(labelTag));
+ ASSERT(isHTMLLabelElement(this));
if (!inDocument())
return;
@@ -3110,32 +2810,27 @@ void Element::updateLabel(TreeScope& scope, const AtomicString& oldForAttributeV
scope.addLabel(newForAttributeValue, toHTMLLabelElement(this));
}
-static bool hasSelectorForAttribute(Document* document, const AtomicString& localName)
-{
- return document->ensureStyleResolver().ensureRuleFeatureSet().hasSelectorForAttribute(localName);
-}
-
void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
{
- if (isIdAttributeName(name))
+ if (isIdAttributeName(name)) {
updateId(oldValue, newValue);
- else if (name == HTMLNames::nameAttr)
+ } else if (name == HTMLNames::nameAttr) {
updateName(oldValue, newValue);
- else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
+ } else if (name == HTMLNames::forAttr && isHTMLLabelElement(*this)) {
TreeScope& scope = treeScope();
if (scope.shouldCacheLabelsByForAttribute())
updateLabel(scope, oldValue, newValue);
}
if (oldValue != newValue) {
- if (inActiveDocument() && hasSelectorForAttribute(&document(), name.localName()))
- setNeedsStyleRecalc();
+ if (inActiveDocument() && document().styleResolver() && styleChangeType() < SubtreeStyleChange)
+ document().ensureStyleResolver().ensureUpdatedRuleFeatureSet().scheduleStyleInvalidationForAttributeChange(name, *this);
if (isUpgradedCustomElement())
CustomElement::attributeDidChange(this, name.localName(), oldValue, newValue);
}
- if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(*this, name))
+ if (OwnPtrWillBeRawPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(*this, name))
recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue));
InspectorInstrumentation::willModifyDOMAttr(this, oldValue, newValue);
@@ -3162,6 +2857,33 @@ void Element::didRemoveAttribute(const QualifiedName& name)
dispatchSubtreeModifiedEvent();
}
+static bool needsURLResolutionForInlineStyle(const Element& element, const Document& oldDocument, const Document& newDocument)
+{
+ if (oldDocument == newDocument)
+ return false;
+ if (oldDocument.baseURL() == newDocument.baseURL())
+ return false;
+ const StylePropertySet* style = element.inlineStyle();
+ if (!style)
+ return false;
+ for (unsigned i = 0; i < style->propertyCount(); ++i) {
+ // FIXME: Should handle all URL-based properties: CSSImageSetValue, CSSCursorImageValue, etc.
+ if (style->propertyAt(i).value()->isImageValue())
+ return true;
+ }
+ return false;
+}
+
+static void reResolveURLsInInlineStyle(const Document& document, MutableStylePropertySet& style)
+{
+ for (unsigned i = 0; i < style.propertyCount(); ++i) {
+ StylePropertySet::PropertyReference property = style.propertyAt(i);
+ // FIXME: Should handle all URL-based properties: CSSImageSetValue, CSSCursorImageValue, etc.
+ if (property.value()->isImageValue())
+ toCSSImageValue(property.value())->reResolveURL(document);
+ }
+}
+
void Element::didMoveToNewDocument(Document& oldDocument)
{
Node::didMoveToNewDocument(oldDocument);
@@ -3175,6 +2897,9 @@ void Element::didMoveToNewDocument(Document& oldDocument)
if (hasClass())
setAttribute(HTMLNames::classAttr, getClassAttribute());
}
+
+ if (needsURLResolutionForInlineStyle(*this, oldDocument, document()))
+ reResolveURLsInInlineStyle(document(), ensureMutableInlineStyle());
}
void Element::updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName)
@@ -3201,43 +2926,32 @@ void Element::updateExtraNamedItemRegistration(const AtomicString& oldId, const
toHTMLDocument(document()).addExtraNamedItem(newId);
}
-PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
+PassRefPtrWillBeRawPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
{
if (HTMLCollection* collection = cachedHTMLCollection(type))
return collection;
- RefPtr<HTMLCollection> collection;
if (type == TableRows) {
- ASSERT(hasTagName(tableTag));
- return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
+ ASSERT(isHTMLTableElement(this));
+ return ensureRareData().ensureNodeLists().addCache<HTMLTableRowsCollection>(*this, type);
} else if (type == SelectOptions) {
- ASSERT(hasTagName(selectTag));
- return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
+ ASSERT(isHTMLSelectElement(this));
+ return ensureRareData().ensureNodeLists().addCache<HTMLOptionsCollection>(*this, type);
} else if (type == FormControls) {
- ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
- return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
+ ASSERT(isHTMLFormElement(this) || isHTMLFieldSetElement(this));
+ return ensureRareData().ensureNodeLists().addCache<HTMLFormControlsCollection>(*this, type);
}
- return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLCollection>(this, type);
-}
-
-static void scheduleLayerUpdateCallback(Node* node)
-{
- // Notify the renderer even is the styles are identical since it may need to
- // create or destroy a RenderLayer.
- node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer);
+ return ensureRareData().ensureNodeLists().addCache<HTMLCollection>(*this, type);
}
-void Element::scheduleLayerUpdate()
+void Element::scheduleSVGFilterLayerUpdateHack()
{
- if (document().inStyleRecalc())
- PostAttachCallbacks::queueCallback(scheduleLayerUpdateCallback, this);
- else
- scheduleLayerUpdateCallback(this);
+ document().scheduleSVGFilterLayerUpdateHack(*this);
}
HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
{
- return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0;
+ return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cached<HTMLCollection>(type) : 0;
}
IntSize Element::savedLayerScrollOffset() const
@@ -3252,17 +2966,17 @@ void Element::setSavedLayerScrollOffset(const IntSize& size)
ensureElementRareData().setSavedLayerScrollOffset(size);
}
-PassRefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
+PassRefPtrWillBeRawPtr<Attr> Element::attrIfExists(const QualifiedName& name)
{
- if (AttrNodeList* attrNodeList = attrNodeListForElement(this))
+ if (AttrNodeList* attrNodeList = this->attrNodeList())
return findAttrNodeInList(*attrNodeList, name);
- return 0;
+ return nullptr;
}
-PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name)
+PassRefPtrWillBeRawPtr<Attr> Element::ensureAttr(const QualifiedName& name)
{
- AttrNodeList& attrNodeList = ensureAttrNodeListForElement(this);
- RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
+ AttrNodeList& attrNodeList = ensureAttrNodeList();
+ RefPtrWillBeRawPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
if (!attrNode) {
attrNode = Attr::create(*this, name);
treeScope().adoptIfNeeded(*attrNode);
@@ -3276,12 +2990,12 @@ void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicStr
ASSERT(hasSyntheticAttrChildNodes());
attrNode->detachFromElementWithValue(value);
- AttrNodeList* attrNodeList = attrNodeListForElement(this);
- for (unsigned i = 0; i < attrNodeList->size(); ++i) {
- if (attrNodeList->at(i)->qualifiedName() == attrNode->qualifiedName()) {
- attrNodeList->remove(i);
- if (attrNodeList->isEmpty())
- removeAttrNodeListForElement(this);
+ AttrNodeList* list = attrNodeList();
+ for (unsigned i = 0; i < list->size(); ++i) {
+ if (list->at(i)->qualifiedName() == attrNode->qualifiedName()) {
+ list->remove(i);
+ if (list->isEmpty())
+ removeAttrNodeList();
return;
}
}
@@ -3290,16 +3004,17 @@ void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicStr
void Element::detachAllAttrNodesFromElement()
{
- AttrNodeList* attrNodeList = attrNodeListForElement(this);
- ASSERT(attrNodeList);
+ AttrNodeList* list = this->attrNodeList();
+ ASSERT(list);
- for (unsigned i = 0; i < attributeCount(); ++i) {
- const Attribute* attribute = attributeItem(i);
- if (RefPtr<Attr> attrNode = findAttrNodeInList(*attrNodeList, attribute->name()))
- attrNode->detachFromElementWithValue(attribute->value());
+ AttributeCollection attributes = this->attributes();
+ AttributeCollection::const_iterator end = attributes.end();
+ for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it) {
+ if (RefPtrWillBeRawPtr<Attr> attrNode = findAttrNodeInList(*list, it->name()))
+ attrNode->detachFromElementWithValue(it->value());
}
- removeAttrNodeListForElement(this);
+ removeAttrNodeList();
}
void Element::willRecalcStyle(StyleRecalcChange)
@@ -3316,7 +3031,7 @@ void Element::didRecalcStyle(StyleRecalcChange)
PassRefPtr<RenderStyle> Element::customStyleForRenderer()
{
ASSERT(hasCustomStyleCallbacks());
- return 0;
+ return nullptr;
}
void Element::cloneAttributesFromElement(const Element& other)
@@ -3349,23 +3064,21 @@ void Element::cloneAttributesFromElement(const Element& other)
ownerDocumentsHaveDifferentCaseSensitivity = other.document().inQuirksMode() != document().inQuirksMode();
// If 'other' has a mutable ElementData, convert it to an immutable one so we can share it between both elements.
- // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes,
- // and sharing the data won't result in different case sensitivity of class or id.
+ // We can only do this if there are no presentation attributes and sharing the data won't result in different case sensitivity of class or id.
if (other.m_elementData->isUnique()
&& !ownerDocumentsHaveDifferentCaseSensitivity
- && !other.m_elementData->presentationAttributeStyle()
- && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper()))
+ && !other.m_elementData->presentationAttributeStyle())
const_cast<Element&>(other).m_elementData = static_cast<const UniqueElementData*>(other.m_elementData.get())->makeShareableCopy();
- if (!other.m_elementData->isUnique() && !ownerDocumentsHaveDifferentCaseSensitivity)
+ if (!other.m_elementData->isUnique() && !ownerDocumentsHaveDifferentCaseSensitivity && !needsURLResolutionForInlineStyle(other, other.document(), document()))
m_elementData = other.m_elementData;
else
m_elementData = other.m_elementData->makeUniqueCopy();
- for (unsigned i = 0; i < m_elementData->length(); ++i) {
- const Attribute* attribute = const_cast<const ElementData*>(m_elementData.get())->attributeItem(i);
- attributeChangedFromParserOrByCloning(attribute->name(), attribute->value(), ModifiedByCloning);
- }
+ AttributeCollection attributes = m_elementData->attributes();
+ AttributeCollection::const_iterator end = attributes.end();
+ for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it)
+ attributeChangedFromParserOrByCloning(it->name(), it->value(), ModifiedByCloning);
}
void Element::cloneDataFromElement(const Element& other)
@@ -3384,7 +3097,7 @@ void Element::createUniqueElementData()
}
}
-InputMethodContext* Element::inputMethodContext()
+InputMethodContext& Element::inputMethodContext()
{
return ensureElementRareData().ensureInputMethodContext(toHTMLElement(this));
}
@@ -3394,58 +3107,42 @@ bool Element::hasInputMethodContext() const
return hasRareData() && elementRareData()->hasInputMethodContext();
}
-bool Element::hasPendingResources() const
-{
- return hasRareData() && elementRareData()->hasPendingResources();
-}
-
-void Element::setHasPendingResources()
-{
- ensureElementRareData().setHasPendingResources(true);
-}
-
-void Element::clearHasPendingResources()
-{
- ensureElementRareData().setHasPendingResources(false);
-}
-
void Element::synchronizeStyleAttributeInternal() const
{
ASSERT(isStyledElement());
ASSERT(elementData());
ASSERT(elementData()->m_styleAttributeIsDirty);
elementData()->m_styleAttributeIsDirty = false;
- if (const StylePropertySet* inlineStyle = this->inlineStyle())
- const_cast<Element*>(this)->setSynchronizedLazyAttribute(styleAttr, inlineStyle->asText());
+ const StylePropertySet* inlineStyle = this->inlineStyle();
+ const_cast<Element*>(this)->setSynchronizedLazyAttribute(styleAttr,
+ inlineStyle ? AtomicString(inlineStyle->asText()) : nullAtom);
}
CSSStyleDeclaration* Element::style()
{
if (!isStyledElement())
return 0;
- return ensureMutableInlineStyle()->ensureInlineCSSStyleDeclaration(this);
+ return &ensureElementRareData().ensureInlineCSSStyleDeclaration(this);
}
-MutableStylePropertySet* Element::ensureMutableInlineStyle()
+MutableStylePropertySet& Element::ensureMutableInlineStyle()
{
ASSERT(isStyledElement());
- RefPtr<StylePropertySet>& inlineStyle = ensureUniqueElementData()->m_inlineStyle;
+ RefPtr<StylePropertySet>& inlineStyle = ensureUniqueElementData().m_inlineStyle;
if (!inlineStyle) {
CSSParserMode mode = (!isHTMLElement() || document().inQuirksMode()) ? HTMLQuirksMode : HTMLStandardMode;
inlineStyle = MutableStylePropertySet::create(mode);
} else if (!inlineStyle->isMutable()) {
inlineStyle = inlineStyle->mutableCopy();
}
- return toMutableStylePropertySet(inlineStyle);
+ return *toMutableStylePropertySet(inlineStyle);
}
-PropertySetCSSStyleDeclaration* Element::inlineStyleCSSOMWrapper()
+void Element::clearMutableInlineStyleIfEmpty()
{
- if (!inlineStyle() || !inlineStyle()->hasCSSOMWrapper())
- return 0;
- PropertySetCSSStyleDeclaration* cssomWrapper = ensureMutableInlineStyle()->cssStyleDeclaration();
- ASSERT(cssomWrapper && cssomWrapper->parentElement() == this);
- return cssomWrapper;
+ if (ensureMutableInlineStyle().isEmpty()) {
+ ensureUniqueElementData().m_inlineStyle.clear();
+ }
}
inline void Element::setInlineStyleFromString(const AtomicString& newStyleString)
@@ -3463,10 +3160,10 @@ inline void Element::setInlineStyleFromString(const AtomicString& newStyleString
inlineStyle.clear();
if (!inlineStyle) {
- inlineStyle = CSSParser::parseInlineStyleDeclaration(newStyleString, this);
+ inlineStyle = BisonCSSParser::parseInlineStyleDeclaration(newStyleString, this);
} else {
ASSERT(inlineStyle->isMutable());
- static_pointer_cast<MutableStylePropertySet>(inlineStyle)->parseDeclaration(newStyleString, document().elementSheet()->contents());
+ static_pointer_cast<MutableStylePropertySet>(inlineStyle)->parseDeclaration(newStyleString, document().elementSheet().contents());
}
}
@@ -3478,9 +3175,7 @@ void Element::styleAttributeChanged(const AtomicString& newStyleString, Attribut
startLineNumber = document().scriptableDocumentParser()->lineNumber();
if (newStyleString.isNull()) {
- if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
- cssomWrapper->clearParentElement();
- ensureUniqueElementData()->m_inlineStyle.clear();
+ ensureUniqueElementData().m_inlineStyle.clear();
} else if (modificationReason == ModifiedByCloning || document().contentSecurityPolicy()->allowInlineStyle(document().url(), startLineNumber)) {
setInlineStyleFromString(newStyleString);
}
@@ -3503,7 +3198,7 @@ void Element::inlineStyleChanged()
bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
{
ASSERT(isStyledElement());
- ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
+ ensureMutableInlineStyle().setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
inlineStyleChanged();
return true;
}
@@ -3511,15 +3206,15 @@ bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSValueID identi
bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
{
ASSERT(isStyledElement());
- ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
+ ensureMutableInlineStyle().setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
inlineStyleChanged();
return true;
}
-bool Element::setInlineStyleProperty(CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit, bool important)
+bool Element::setInlineStyleProperty(CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitType unit, bool important)
{
ASSERT(isStyledElement());
- ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createValue(value, unit), important);
+ ensureMutableInlineStyle().setProperty(propertyID, cssValuePool().createValue(value, unit), important);
inlineStyleChanged();
return true;
}
@@ -3527,7 +3222,7 @@ bool Element::setInlineStyleProperty(CSSPropertyID propertyID, double value, CSS
bool Element::setInlineStyleProperty(CSSPropertyID propertyID, const String& value, bool important)
{
ASSERT(isStyledElement());
- bool changes = ensureMutableInlineStyle()->setProperty(propertyID, value, important, document().elementSheet()->contents());
+ bool changes = ensureMutableInlineStyle().setProperty(propertyID, value, important, document().elementSheet().contents());
if (changes)
inlineStyleChanged();
return changes;
@@ -3538,7 +3233,7 @@ bool Element::removeInlineStyleProperty(CSSPropertyID propertyID)
ASSERT(isStyledElement());
if (!inlineStyle())
return false;
- bool changes = ensureMutableInlineStyle()->removeProperty(propertyID);
+ bool changes = ensureMutableInlineStyle().removeProperty(propertyID);
if (changes)
inlineStyleChanged();
return changes;
@@ -3547,25 +3242,19 @@ bool Element::removeInlineStyleProperty(CSSPropertyID propertyID)
void Element::removeAllInlineStyleProperties()
{
ASSERT(isStyledElement());
- if (!inlineStyle() || inlineStyle()->isEmpty())
+ if (!inlineStyle())
return;
- ensureMutableInlineStyle()->clear();
+ ensureMutableInlineStyle().clear();
inlineStyleChanged();
}
-void Element::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
-{
- ASSERT(isStyledElement());
- if (const StylePropertySet* inlineStyle = elementData() ? elementData()->inlineStyle() : 0)
- inlineStyle->addSubresourceStyleURLs(urls, document().elementSheet()->contents());
-}
-
void Element::updatePresentationAttributeStyle()
{
+ synchronizeAllAttributes();
// ShareableElementData doesn't store presentation attribute style, so make sure we have a UniqueElementData.
- UniqueElementData* elementData = ensureUniqueElementData();
- elementData->m_presentationAttributeStyleIsDirty = false;
- elementData->m_presentationAttributeStyle = computePresentationAttributeStyle(*this);
+ UniqueElementData& elementData = ensureUniqueElementData();
+ elementData.m_presentationAttributeStyleIsDirty = false;
+ elementData.m_presentationAttributeStyle = computePresentationAttributeStyle(*this);
}
void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, CSSValueID identifier)
@@ -3574,7 +3263,7 @@ void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* s
style->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier));
}
-void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit)
+void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitType unit)
{
ASSERT(isStyledElement());
style->setProperty(propertyID, cssValuePool().createValue(value, unit));
@@ -3588,7 +3277,7 @@ void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* s
bool Element::supportsStyleSharing() const
{
- if (!isStyledElement() || !parentElement())
+ if (!isStyledElement() || !parentOrShadowHostElement())
return false;
// If the element has inline style it is probably unique.
if (inlineStyle())
@@ -3598,17 +3287,12 @@ bool Element::supportsStyleSharing() const
// Ids stop style sharing if they show up in the stylesheets.
if (hasID() && document().ensureStyleResolver().hasRulesForId(idForStyleResolution()))
return false;
- // Active and hovered elements always make a chain towards the document node
- // and no siblings or cousins will have the same state.
- if (hovered())
- return false;
- if (active())
- return false;
- if (focused())
+ // :active and :hover elements always make a chain towards the document node
+ // and no siblings or cousins will have the same state. There's also only one
+ // :focus element per scope so we don't need to attempt to share.
+ if (isUserActionElement())
return false;
- if (!parentElement()->childrenSupportStyleSharing())
- return false;
- if (hasScopedHTMLStyleChild())
+ if (!parentOrShadowHostElement()->childrenSupportStyleSharing())
return false;
if (this == document().cssTarget())
return false;
@@ -3616,26 +3300,26 @@ bool Element::supportsStyleSharing() const
return false;
if (hasActiveAnimations())
return false;
- if (shadow() && shadow()->containsActiveStyles())
- return false;
// Turn off style sharing for elements that can gain layers for reasons outside of the style system.
// See comments in RenderObject::setStyle().
// FIXME: Why does gaining a layer from outside the style system require disabling sharing?
- if (hasTagName(iframeTag)
- || hasTagName(frameTag)
- || hasTagName(embedTag)
- || hasTagName(objectTag)
- || hasTagName(appletTag)
- || hasTagName(canvasTag))
- return false;
- // FIXME: We should share style for option and optgroup whenever possible.
- // Before doing so, we need to resolve issues in HTMLSelectElement::recalcListItems
- // and RenderMenuList::setText. See also https://bugs.webkit.org/show_bug.cgi?id=88405
- if (hasTagName(optionTag) || hasTagName(optgroupTag))
+ if (isHTMLFrameElementBase(*this)
+ || isHTMLEmbedElement(*this)
+ || isHTMLObjectElement(*this)
+ || isHTMLAppletElement(*this)
+ || isHTMLCanvasElement(*this))
return false;
if (FullscreenElementStack::isActiveFullScreenElement(this))
return false;
return true;
}
+void Element::trace(Visitor* visitor)
+{
+ if (hasRareData())
+ visitor->trace(elementRareData());
+
+ ContainerNode::trace(visitor);
+}
+
} // namespace WebCore