#include "RuntimeEnabledFeatures.h"
#include "SVGNames.h"
#include "XMLNames.h"
+#include "bindings/v8/Dictionary.h"
#include "bindings/v8/ExceptionState.h"
#include "core/accessibility/AXObjectCache.h"
#include "core/animation/DocumentTimeline.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/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/svg/SVGDocumentExtensions.h"
#include "core/svg/SVGElement.h"
+#include "platform/scroll/ScrollableArea.h"
#include "wtf/BitVector.h"
#include "wtf/HashFunctions.h"
#include "wtf/text/CString.h"
ASSERT(!attrNodeListMap().contains(element));
element->setHasSyntheticAttrChildNodes(true);
AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList));
- return *result.iterator->value;
+ return *result.storedValue->value;
}
static void removeAttrNodeListForElement(Element* element)
Element::~Element()
{
- // 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());
ASSERT(needsAttach());
if (hasRareData())
// 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.
bool Element::hasActiveAnimations() const
{
- if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled())
- return false;
-
if (!hasRareData())
return false;
}
}
+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)
{
document().updateLayoutIgnorePendingStylesheets();
}
}
+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();
shouldInvalidateStyle |= !styleResolver;
if (shouldInvalidateStyle)
- setNeedsStyleRecalc();
+ setNeedsStyleRecalc(SubtreeStyleChange);
if (AXObjectCache* cache = document().existingAXObjectCache())
cache->handleAttributeChanged(name, this);
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->ensureRuleFeatureSet().scheduleStyleInvalidationForClassChange(oldClasses, newClasses, this);
} else {
const SpaceSplitString& oldClasses = elementData()->classNames();
- shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, styleResolver->ensureRuleFeatureSet());
+ if (testShouldInvalidateStyle)
+ styleResolver->ensureRuleFeatureSet().scheduleStyleInvalidationForClassChange(oldClasses, this);
elementData()->clearClass();
}
if (hasRareData())
elementRareData()->clearClassListValueForQuirksMode();
-
- if (shouldInvalidateStyle)
- setNeedsStyleRecalc();
}
bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
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;
}
}
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);
return m_tagName.toString();
}
-String Element::nodeNamePreservingCase() const
-{
- return m_tagName.toString();
-}
-
void Element::setPrefix(const AtomicString& prefix, ExceptionState& exceptionState)
{
UseCounter::count(document(), UseCounter::ElementSetPrefix);
KURL Element::baseURI() const
{
- const AtomicString& baseAttribute = getAttribute(baseAttr);
+ const AtomicString& baseAttribute = fastGetAttribute(baseAttr);
KURL base(KURL(), baseAttribute);
if (!base.protocol().isEmpty())
return base;
document().updateFocusAppearanceSoon(false /* don't restore selection */);
data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
}
- if (RuntimeEnabledFeatures::webAnimationsCSSEnabled() && !renderer()) {
+ if (!renderer()) {
if (ActiveAnimations* activeAnimations = data->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();
cancelFocusAppearanceUpdate();
removeCallbackSelectors();
if (hasRareData()) {
ElementRareData* data = elementRareData();
data->clearPseudoElements();
- data->setIsInsideRegion(false);
// attach() will perform the below steps for us when inside recalcStyle.
if (!document().inStyleRecalc()) {
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();
- activeAnimations->setAnimationStyleChange(false);
- }
+ if (ActiveAnimations* activeAnimations = data->activeAnimations()) {
+ if (context.performingReattach) {
+ // FIXME: We call detach from withing 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 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);
if (RenderObject* renderer = this->renderer()) {
if (localChange != NoChange || pseudoStyleCacheIsInvalid(oldStyle.get(), newStyle.get()) || shouldNotifyRendererWithIdenticalStyles()) {
- renderer->setAnimatableStyle(newStyle.get());
+ 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.
if (styleChangeType() >= SubtreeStyleChange)
return Force;
- if (change <= Inherit)
- return localChange;
+ if (change > Inherit || localChange > Inherit)
+ return max(localChange, change);
+
+ if (localChange < Inherit && (oldStyle->hasPseudoElementStyle() || newStyle->hasPseudoElementStyle()))
+ return UpdatePseudoElements;
- return max(localChange, change);
+ return localChange;
}
void Element::recalcChildStyle(StyleRecalcChange change)
{
ASSERT(document().inStyleRecalc());
- ASSERT(change >= Inherit || childNeedsStyleRecalc());
+ ASSERT(change >= UpdatePseudoElements || childNeedsStyleRecalc());
ASSERT(!needsStyleRecalc());
StyleResolverParentPusher parentPusher(*this);
- for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
- if (root->shouldCallRecalcStyle(change)) {
- parentPusher.push();
- root->recalcStyle(change);
+ if (change > UpdatePseudoElements || childNeedsStyleRecalc()) {
+ for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
+ if (root->shouldCallRecalcStyle(change)) {
+ parentPusher.push();
+ root->recalcStyle(change);
+ }
}
}
- if (shouldCallRecalcStyle(change))
- updatePseudoElement(BEFORE, change);
+ 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 (element->shouldCallRecalcStyle(change)) {
- 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)) {
+ parentPusher.push();
+ element->recalcStyle(change, lastTextNode);
+ } else if (element->supportsStyleSharing()) {
+ styleResolver.addToStyleSharingList(*element);
+ }
+ if (element->renderer())
+ lastTextNode = 0;
}
- if (element->renderer())
- lastTextNode = 0;
}
}
- if (shouldCallRecalcStyle(change)) {
- updatePseudoElement(AFTER, change);
- updatePseudoElement(BACKDROP, change);
- }
+ updatePseudoElement(AFTER, change);
+ updatePseudoElement(BACKDROP, change);
}
void Element::checkForChildrenAdjacentRuleChanges()
bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() >= SubtreeStyleChange;
if (forceCheckOfNextElementCount || forceCheckOfAnyElementSibling)
- element->setNeedsStyleRecalc();
+ element->setNeedsStyleRecalc(SubtreeStyleChange);
if (forceCheckOfNextElementCount)
forceCheckOfNextElementCount--;
void Element::didAffectSelector(AffectedSelectorMask mask)
{
- setNeedsStyleRecalc();
+ setNeedsStyleRecalc(SubtreeStyleChange);
if (ElementShadow* elementShadow = shadowWhereNodeCanBeDistributed(*this))
elementShadow->didAffectSelector(mask);
}
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()) {
+ // 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 0;
}
+
return PassRefPtr<ShadowRoot>(ensureShadow().addShadowRoot(*this, ShadowRoot::AuthorShadowRoot));
}
return;
if (!style || (styleAffectedByEmpty() && (!style->emptyState() || hasChildNodes())))
- setNeedsStyleRecalc();
+ setNeedsStyleRecalc(SubtreeStyleChange);
}
void Element::checkForSiblingStyleChanges(bool finishedParsingCallback, Node* beforeChange, Node* afterChange, int childCountDelta)
// 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();
+ setNeedsStyleRecalc(SubtreeStyleChange);
return;
}
// |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();
+ Element* newFirstChild = ElementTraversal::firstWithin(*this);
RenderStyle* newFirstChildStyle = newFirstChild ? newFirstChild->renderStyle() : 0;
// Find the first element node following |afterChange|
- Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling();
+ Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : ElementTraversal::nextSibling(*afterChange);
RenderStyle* firstElementAfterInsertionStyle = firstElementAfterInsertion ? firstElementAfterInsertion->renderStyle() : 0;
// This is the insert/append case.
if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertionStyle && firstElementAfterInsertionStyle->firstChildState())
- firstElementAfterInsertion->setNeedsStyleRecalc();
+ firstElementAfterInsertion->setNeedsStyleRecalc(SubtreeStyleChange);
// We also have to handle node removal.
if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChildStyle || !newFirstChildStyle->firstChildState()))
- newFirstChild->setNeedsStyleRecalc();
+ newFirstChild->setNeedsStyleRecalc(SubtreeStyleChange);
}
// :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();
+ Node* newLastChild = ElementTraversal::lastWithin(*this);
RenderStyle* newLastChildStyle = newLastChild ? newLastChild->renderStyle() : 0;
// Find the last element node going backwards from |beforeChange|
- Node* lastElementBeforeInsertion = beforeChange->isElementNode() ? beforeChange : beforeChange->previousElementSibling();
+ Node* lastElementBeforeInsertion = beforeChange->isElementNode() ? beforeChange : ElementTraversal::previousSibling(*beforeChange);
RenderStyle* lastElementBeforeInsertionStyle = lastElementBeforeInsertion ? lastElementBeforeInsertion->renderStyle() : 0;
if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertionStyle && lastElementBeforeInsertionStyle->lastChildState())
- lastElementBeforeInsertion->setNeedsStyleRecalc();
+ lastElementBeforeInsertion->setNeedsStyleRecalc(SubtreeStyleChange);
// 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();
+ newLastChild->setNeedsStyleRecalc(SubtreeStyleChange);
}
// 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 (Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : ElementTraversal::nextSibling(*afterChange))
+ firstElementAfterInsertion->setNeedsStyleRecalc(SubtreeStyleChange);
}
}
void Element::finishParsingChildren()
{
- setIsParsingChildrenFinished(true);
+ setIsFinishedParsingChildren(true);
checkForSiblingStyleChanges(this, lastChild(), 0, 0);
}
return oldAttrNode.release();
}
-PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionState& exceptionState)
-{
- return setAttributeNode(attr, exceptionState);
-}
-
PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionState& exceptionState)
{
if (!attr) {
return elementData()->getAttributeItem(qName);
}
-void Element::focus(bool restorePreviousSelection, FocusDirection direction)
+void Element::focus(bool restorePreviousSelection, FocusType type)
{
if (!inDocument())
return;
// 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))
+ if (!page->focusController().setFocusedElement(this, doc.frame(), type))
return;
}
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);
EventDispatcher::dispatchEvent(this, FocusEventDispatchMediator::create(event.release()));
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)
+{
+ RefPtr<Text> textNode = document().createTextNode(text);
+ insertAdjacent(where, textNode.get(), exceptionState);
+}
+
void Element::insertAdjacentHTML(const String& where, const String& markup, ExceptionState& exceptionState)
{
RefPtr<Element> contextElement = contextElementForInsertion(where, this, exceptionState);
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;
void Element::updatePseudoElement(PseudoId pseudoId, StyleRecalcChange change)
{
+ ASSERT(!needsStyleRecalc());
PseudoElement* element = pseudoElement(pseudoId);
- if (element && (needsStyleRecalc() || element->shouldCallRecalcStyle(change))) {
+ 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())
// 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
// PseudoElement's renderer for each style recalc.
if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
elementRareData()->setPseudoElement(pseudoId, 0);
- } else if (change >= Inherit || needsStyleRecalc())
+ } else if (change >= UpdatePseudoElements) {
createPseudoElementIfNeeded(pseudoId);
+ }
}
void Element::createPseudoElementIfNeeded(PseudoId pseudoId)
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, ""))
return true;
}
-RenderRegion* Element::renderRegion() const
-{
- if (renderer() && renderer()->isRenderNamedFlowFragmentContainer())
- return toRenderBlockFlow(renderer())->renderNamedFlowFragment();
-
- return 0;
-}
-
-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
{
if (oldValue != newValue) {
if (inActiveDocument() && hasSelectorForAttribute(&document(), name.localName()))
- setNeedsStyleRecalc();
+ setNeedsStyleRecalc(SubtreeStyleChange);
if (isUpgradedCustomElement())
CustomElement::attributeDidChange(this, name.localName(), oldValue, newValue);
if (HTMLCollection* collection = cachedHTMLCollection(type))
return collection;
- RefPtr<HTMLCollection> collection;
if (type == TableRows) {
ASSERT(hasTagName(tableTag));
- return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
+ return ensureRareData().ensureNodeLists().addCache<HTMLTableRowsCollection>(this, type);
} else if (type == SelectOptions) {
ASSERT(hasTagName(selectTag));
- return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
+ return ensureRareData().ensureNodeLists().addCache<HTMLOptionsCollection>(this, type);
} else if (type == FormControls) {
ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
- return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
+ return ensureRareData().ensureNodeLists().addCache<HTMLFormControlsCollection>(this, type);
}
- return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLCollection>(this, type);
+ return ensureRareData().ensureNodeLists().addCache<HTMLCollection>(this, type);
}
static void scheduleLayerUpdateCallback(Node* node)
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