#include "config.h"
#include "core/dom/Element.h"
+#include "bindings/core/v8/DOMDataStore.h"
#include "bindings/core/v8/Dictionary.h"
#include "bindings/core/v8/ExceptionMessages.h"
#include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/V8DOMWrapper.h"
+#include "bindings/core/v8/V8PerContextData.h"
#include "core/CSSValueKeywords.h"
#include "core/SVGNames.h"
#include "core/XLinkNames.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/parser/CSSParser.h"
#include "core/css/resolver/StyleResolver.h"
#include "core/css/resolver/StyleResolverParentScope.h"
#include "core/dom/Attr.h"
#include "core/dom/ElementRareData.h"
#include "core/dom/ElementTraversal.h"
#include "core/dom/ExceptionCode.h"
-#include "core/dom/FullscreenElementStack.h"
+#include "core/dom/Fullscreen.h"
#include "core/dom/MutationObserverInterestGroup.h"
#include "core/dom/MutationRecord.h"
#include "core/dom/NamedNodeMap.h"
: ContainerNode(document, type)
, m_tagName(tagName)
{
- ScriptWrappable::init(this);
}
Element::~Element()
// 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.
- ASSERT(!document().childNeedsStyleRecalc());
+ // In addition, style cannot be cleared out for non-active documents,
+ // so in that case the childNeedsStyleRecalc check is invalid.
+ ASSERT(!document().isActive() || !document().childNeedsStyleRecalc());
}
// FIXME: Even if we are not visible, we might have a child that is visible.
return 0;
}
-int Element::scrollLeft()
+double Element::scrollLeft()
{
document().updateLayoutIgnorePendingStylesheets();
if (document().documentElement() != this) {
if (RenderBox* rend = renderBox())
- return adjustDoubleForAbsoluteZoom(rend->scrollLeft(), *rend);
+ return adjustScrollForAbsoluteZoom(rend->scrollLeft(), *rend);
return 0;
}
if (FrameView* view = document().view()) {
if (RenderView* renderView = document().renderView())
- return adjustDoubleForAbsoluteZoom(view->scrollX(), *renderView);
+ return adjustScrollForAbsoluteZoom(view->scrollX(), *renderView);
}
}
return 0;
}
-int Element::scrollTop()
+double Element::scrollTop()
{
document().updateLayoutIgnorePendingStylesheets();
if (document().documentElement() != this) {
if (RenderBox* rend = renderBox())
- return adjustLayoutUnitForAbsoluteZoom(rend->scrollTop(), *rend);
+ return adjustScrollForAbsoluteZoom(rend->scrollTop(), *rend);
return 0;
}
if (FrameView* view = document().view()) {
if (RenderView* renderView = document().renderView())
- return adjustDoubleForAbsoluteZoom(view->scrollY(), *renderView);
+ return adjustScrollForAbsoluteZoom(view->scrollY(), *renderView);
}
}
return 0;
}
-void Element::setScrollLeft(int newLeft)
+void Element::setScrollLeft(double newLeft)
{
document().updateLayoutIgnorePendingStylesheets();
}
}
- int position;
+ double position;
if (!DictionaryHelper::get(scrollOptionsHorizontal, "x", position)) {
exceptionState.throwTypeError("ScrollOptionsHorizontal must include an 'x' member.");
return;
setScrollLeft(position);
}
-void Element::setScrollTop(int newTop)
+void Element::setScrollTop(double newTop)
{
document().updateLayoutIgnorePendingStylesheets();
}
}
- int position;
+ double position;
if (!DictionaryHelper::get(scrollOptionsVertical, "y", position)) {
exceptionState.throwTypeError("ScrollOptionsVertical must include a 'y' member.");
return;
elementRareData()->clearClassListValueForQuirksMode();
if (isUpgradedCustomElement() && inDocument())
- CustomElement::didEnterDocument(this, document());
+ CustomElement::didAttach(this, document());
TreeScope& scope = insertionPoint->treeScope();
if (scope != treeScope())
if (containsFullScreenElement())
setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
- if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExists(document()))
+ if (Fullscreen* fullscreen = Fullscreen::fromIfExists(document()))
fullscreen->elementRemoved(*this);
if (document().page())
document().accessSVGExtensions().removeElementFromPendingResources(this);
if (isUpgradedCustomElement())
- CustomElement::didLeaveDocument(this, insertionPoint->document());
+ CustomElement::didDetach(this, insertionPoint->document());
}
document().removeFromTopLayer(this);
if (hasRareData() && styleChangeType() == NeedsReattachStyleChange) {
ElementRareData* data = elementRareData();
data->clearComputedStyle();
- // Only clear the style state if we're not going to reuse the style from recalcStyle.
- if (!context.resolvedStyle)
- data->resetStyleState();
}
RenderTreeBuilder(this, context.resolvedStyle).createRendererForElementIfNeeded();
ElementRareData* data = elementRareData();
data->clearPseudoElements();
- // attach() will perform the below steps for us when inside recalcStyle.
- if (!document().inStyleRecalc()) {
- data->resetStyleState();
+ // attach() will clear the computed style for us when inside recalcStyle.
+ if (!document().inStyleRecalc())
data->clearComputedStyle();
- }
if (ActiveAnimations* activeAnimations = data->activeAnimations()) {
if (context.performingReattach) {
if (change >= Inherit || needsStyleRecalc()) {
if (hasRareData()) {
ElementRareData* data = elementRareData();
- data->resetStyleState();
data->clearComputedStyle();
if (change >= Inherit) {
// If we reattached we don't need to recalc the style of our descendants anymore.
if ((change >= UpdatePseudoElements && change < Reattach) || childNeedsStyleRecalc()) {
- recalcChildStyle(change);
+ StyleResolverParentScope parentScope(*this);
+
+ updatePseudoElement(BEFORE, change);
+
+ if (change > UpdatePseudoElements || childNeedsStyleRecalc()) {
+ for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
+ if (root->shouldCallRecalcStyle(change))
+ root->recalcStyle(change);
+ }
+ recalcChildStyle(change);
+ }
+
+ updatePseudoElement(AFTER, change);
+ updatePseudoElement(BACKDROP, change);
+
clearChildNeedsStyleRecalc();
}
return localChange;
}
-void Element::recalcChildStyle(StyleRecalcChange change)
-{
- ASSERT(document().inStyleRecalc());
- ASSERT(change >= UpdatePseudoElements || childNeedsStyleRecalc());
- ASSERT(!needsStyleRecalc());
-
- StyleResolverParentScope parentScope(*this);
-
- updatePseudoElement(BEFORE, change);
-
- if (change > UpdatePseudoElements || childNeedsStyleRecalc()) {
- for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
- if (root->shouldCallRecalcStyle(change))
- root->recalcStyle(change);
- }
- }
-
- if (change < Force && hasRareData() && childNeedsStyleRecalc())
- checkForChildrenAdjacentRuleChanges();
-
- 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;
- }
- }
- }
-
- updatePseudoElement(AFTER, change);
- updatePseudoElement(BACKDROP, change);
-}
-
void Element::updateCallbackSelectors(RenderStyle* oldStyle, RenderStyle* newStyle)
{
Vector<String> emptyVector;
return ensureElementRareData().ensureShadow();
}
-void Element::didAffectSelector(AffectedSelectorMask mask)
+void Element::pseudoStateChanged(CSSSelector::PseudoType pseudo)
{
- setNeedsStyleRecalc(SubtreeStyleChange);
+ StyleResolver* styleResolver = document().styleResolver();
+
+ if (inActiveDocument() && styleResolver && styleChangeType() < SubtreeStyleChange)
+ styleResolver->ensureUpdatedRuleFeatureSet().scheduleStyleInvalidationForPseudoChange(pseudo, *this);
+
if (ElementShadow* elementShadow = shadowWhereNodeCanBeDistributed(*this))
- elementShadow->didAffectSelector(mask);
+ elementShadow->distributedNodePseudoStateChanged(pseudo);
}
void Element::setAnimationStyleChange(bool animationStyleChange)
if (!style && !styleAffectedByEmpty())
return;
+ if (styleChangeType() >= SubtreeStyleChange)
+ return;
+ if (!inActiveDocument())
+ return;
+ if (!document().styleResolver())
+ return;
if (!style || (styleAffectedByEmpty() && (!style->emptyState() || hasChildren())))
- setNeedsStyleRecalc(SubtreeStyleChange);
+ document().styleResolver()->ensureUpdatedRuleFeatureSet().scheduleStyleInvalidationForPseudoChange(CSSSelector::PseudoEmpty, *this);
}
void Element::childrenChanged(const ChildrenChange& change)
{
if (isRootEditableElement()) {
// Taking the ownership since setSelection() may release the last reference to |frame|.
- RefPtr<LocalFrame> frame(document().frame());
+ RefPtrWillBeRawPtr<LocalFrame> frame(document().frame());
if (!frame)
return;
return isFocusable();
}
-void Element::dispatchFocusEvent(Element* oldFocusedElement, FocusType)
+void Element::dispatchFocusEvent(Element* oldFocusedElement, FocusType type)
{
RefPtrWillBeRawPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::focus, false, false, document().domWindow(), 0, oldFocusedElement);
EventDispatcher::dispatchEvent(this, FocusEventDispatchMediator::create(event.release()));
EventDispatcher::dispatchEvent(this, BlurEventDispatchMediator::create(event.release()));
}
-void Element::dispatchFocusInEvent(const AtomicString& eventType, Element* oldFocusedElement)
+void Element::dispatchFocusInEvent(const AtomicString& eventType, Element* oldFocusedElement, FocusType)
{
ASSERT(!EventDispatchForbiddenScope::isEventDispatchForbidden());
ASSERT(eventType == EventTypeNames::focusin || eventType == EventTypeNames::DOMFocusIn);
static Element* contextElementForInsertion(const String& where, Element* element, ExceptionState& exceptionState)
{
if (equalIgnoringCase(where, "beforeBegin") || equalIgnoringCase(where, "afterEnd")) {
- ContainerNode* parent = element->parentNode();
- if (!parent || !parent->isElementNode()) {
+ Element* parent = element->parentElement();
+ if (!parent) {
exceptionState.throwDOMException(NoModificationAllowedError, "The element has no parent.");
return 0;
}
- return toElement(parent);
+ return parent;
}
if (equalIgnoringCase(where, "afterBegin") || equalIgnoringCase(where, "beforeEnd"))
return element;
void Element::setShadowPseudoId(const AtomicString& id)
{
- ASSERT(CSSSelector::parsePseudoType(id) == CSSSelector::PseudoWebKitCustomElement || CSSSelector::parsePseudoType(id) == CSSSelector::PseudoUserAgentCustomElement);
+ ASSERT(CSSSelector::parsePseudoType(id, false) == CSSSelector::PseudoWebKitCustomElement || CSSSelector::parsePseudoType(id, false) == CSSSelector::PseudoUserAgentCustomElement);
setAttribute(pseudoAttr, id);
}
if (PseudoElement* element = pseudoElement(pseudoElementSpecifier))
return element->computedStyle();
+ if (!inActiveDocument()) {
+ // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
+ // document tree and figure out when to destroy the computed style for such elements.
+ return 0;
+ }
+
// FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
// properties, which are only known by the renderer because it did the layout, will be correct and so that the
// values returned for the ":selection" pseudo-element will be correct.
- if (RenderStyle* usedStyle = renderStyle()) {
- if (pseudoElementSpecifier) {
- RenderStyle* cachedPseudoStyle = usedStyle->getCachedPseudoStyle(pseudoElementSpecifier);
- return cachedPseudoStyle ? cachedPseudoStyle : usedStyle;
- } else
- return usedStyle;
+ RenderStyle* elementStyle = renderStyle();
+ if (!elementStyle) {
+ ElementRareData& rareData = ensureElementRareData();
+ if (!rareData.computedStyle())
+ rareData.setComputedStyle(document().styleForElementIgnoringPendingStylesheets(this));
+ elementStyle = rareData.computedStyle();
}
- if (!inActiveDocument())
- // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
- // document tree and figure out when to destroy the computed style for such elements.
- return 0;
+ if (!pseudoElementSpecifier)
+ return elementStyle;
- ElementRareData& rareData = ensureElementRareData();
- if (!rareData.computedStyle())
- rareData.setComputedStyle(document().styleForElementIgnoringPendingStylesheets(this));
- return pseudoElementSpecifier ? rareData.computedStyle()->getCachedPseudoStyle(pseudoElementSpecifier) : rareData.computedStyle();
+ if (RenderStyle* pseudoElementStyle = elementStyle->getCachedPseudoStyle(pseudoElementSpecifier))
+ return pseudoElementStyle;
+
+ RefPtr<RenderStyle> result = document().ensureStyleResolver().pseudoStyleForElement(this, PseudoStyleRequest(pseudoElementSpecifier, PseudoStyleRequest::ForComputedStyle), elementStyle);
+ ASSERT(result);
+ return elementStyle->addCachedPseudoStyle(result.release());
}
AtomicString Element::computeInheritedLanguage() const
int Element::getIntegralAttribute(const QualifiedName& attributeName) const
{
- return getAttribute(attributeName).string().toInt();
+ return getAttribute(attributeName).toInt();
}
void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
setAttribute(attributeName, AtomicString::number(value));
}
-unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
-{
- return getAttribute(attributeName).string().toUInt();
-}
-
void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
{
// Range restrictions are enforced for unsigned IDL attributes that
inlineStyle.clear();
if (!inlineStyle) {
- inlineStyle = BisonCSSParser::parseInlineStyleDeclaration(newStyleString, this);
+ inlineStyle = CSSParser::parseInlineStyleDeclaration(newStyleString, this);
} else {
ASSERT(inlineStyle->isMutable());
static_cast<MutableStylePropertySet*>(inlineStyle.get())->parseDeclaration(newStyleString, document().elementSheet().contents());
// FIXME: Why does gaining a layer from outside the style system require disabling sharing?
if (isHTMLFrameElementBase(*this) || isHTMLPlugInElement(*this) || isHTMLCanvasElement(*this))
return false;
- if (FullscreenElementStack::isActiveFullScreenElement(*this))
+ if (Fullscreen::isActiveFullScreenElement(*this))
return false;
return true;
}
ContainerNode::trace(visitor);
}
+v8::Handle<v8::Object> Element::wrap(v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
+{
+ if (isCustomElement())
+ return wrapCustomElement(creationContext, isolate);
+ return ContainerNode::wrap(creationContext, isolate);
+}
+
+v8::Handle<v8::Object> Element::wrapCustomElement(v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
+{
+ // It's possible that no one except for the new wrapper owns this object at
+ // this moment, so we have to prevent GC to collect this object until the
+ // object gets associated with the wrapper.
+ RefPtrWillBeRawPtr<Element> protect(this);
+
+ ASSERT(!DOMDataStore::containsWrapperNonTemplate(this, isolate));
+
+ ASSERT(!creationContext.IsEmpty());
+ v8::Handle<v8::Context> context = creationContext->CreationContext();
+
+ if (!isUpgradedCustomElement() || DOMWrapperWorld::world(context).isIsolatedWorld())
+ return ContainerNode::wrap(creationContext, isolate);
+
+ V8PerContextData* perContextData = V8PerContextData::from(context);
+ if (!perContextData)
+ return v8::Handle<v8::Object>();
+
+ CustomElementBinding* binding = perContextData->customElementBinding(customElementDefinition());
+ const WrapperTypeInfo* wrapperType = wrapperTypeInfo();
+ v8::Handle<v8::Object> wrapper = V8DOMWrapper::createWrapper(creationContext, wrapperType, toScriptWrappableBase(), isolate);
+ if (wrapper.IsEmpty())
+ return v8::Handle<v8::Object>();
+
+ wrapper->SetPrototype(binding->prototype());
+
+ return V8DOMWrapper::associateObjectWithWrapperNonTemplate(this, wrapperType, wrapper, isolate);
+}
+
} // namespace blink