Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / dom / Element.cpp
index efb167d..7ea8de5 100644 (file)
 #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"
@@ -41,7 +44,7 @@
 #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"
@@ -53,7 +56,7 @@
 #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"
@@ -140,7 +143,6 @@ Element::Element(const QualifiedName& tagName, Document* document, ConstructionT
     : ContainerNode(document, type)
     , m_tagName(tagName)
 {
-    ScriptWrappable::init(this);
 }
 
 Element::~Element()
@@ -237,7 +239,9 @@ bool Element::rendererIsFocusable() const
         // 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.
@@ -608,13 +612,13 @@ int Element::clientHeight()
     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;
     }
 
@@ -624,20 +628,20 @@ int Element::scrollLeft()
 
         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;
     }
 
@@ -647,14 +651,14 @@ int Element::scrollTop()
 
         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();
 
@@ -690,7 +694,7 @@ void Element::setScrollLeft(const Dictionary& scrollOptionsHorizontal, Exception
         }
     }
 
-    int position;
+    double position;
     if (!DictionaryHelper::get(scrollOptionsHorizontal, "x", position)) {
         exceptionState.throwTypeError("ScrollOptionsHorizontal must include an 'x' member.");
         return;
@@ -700,7 +704,7 @@ void Element::setScrollLeft(const Dictionary& scrollOptionsHorizontal, Exception
     setScrollLeft(position);
 }
 
-void Element::setScrollTop(int newTop)
+void Element::setScrollTop(double newTop)
 {
     document().updateLayoutIgnorePendingStylesheets();
 
@@ -736,7 +740,7 @@ void Element::setScrollTop(const Dictionary& scrollOptionsVertical, ExceptionSta
         }
     }
 
-    int position;
+    double position;
     if (!DictionaryHelper::get(scrollOptionsVertical, "y", position)) {
         exceptionState.throwTypeError("ScrollOptionsVertical must include a 'y' member.");
         return;
@@ -1250,7 +1254,7 @@ Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertio
         elementRareData()->clearClassListValueForQuirksMode();
 
     if (isUpgradedCustomElement() && inDocument())
-        CustomElement::didEnterDocument(this, document());
+        CustomElement::didAttach(this, document());
 
     TreeScope& scope = insertionPoint->treeScope();
     if (scope != treeScope())
@@ -1279,7 +1283,7 @@ void Element::removedFrom(ContainerNode* insertionPoint)
     if (containsFullScreenElement())
         setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
 
-    if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExists(document()))
+    if (Fullscreen* fullscreen = Fullscreen::fromIfExists(document()))
         fullscreen->elementRemoved(*this);
 
     if (document().page())
@@ -1303,7 +1307,7 @@ void Element::removedFrom(ContainerNode* insertionPoint)
             document().accessSVGExtensions().removeElementFromPendingResources(this);
 
         if (isUpgradedCustomElement())
-            CustomElement::didLeaveDocument(this, insertionPoint->document());
+            CustomElement::didDetach(this, insertionPoint->document());
     }
 
     document().removeFromTopLayer(this);
@@ -1323,9 +1327,6 @@ void Element::attach(const AttachContext& context)
     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();
@@ -1364,11 +1365,9 @@ void Element::detach(const AttachContext& context)
         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) {
@@ -1477,7 +1476,6 @@ void Element::recalcStyle(StyleRecalcChange change, Text* nextTextSibling)
     if (change >= Inherit || needsStyleRecalc()) {
         if (hasRareData()) {
             ElementRareData* data = elementRareData();
-            data->resetStyleState();
             data->clearComputedStyle();
 
             if (change >= Inherit) {
@@ -1492,7 +1490,21 @@ void Element::recalcStyle(StyleRecalcChange change, Text* nextTextSibling)
 
     // 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();
     }
 
@@ -1555,53 +1567,6 @@ StyleRecalcChange Element::recalcOwnStyle(StyleRecalcChange change)
     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;
@@ -1633,11 +1598,15 @@ ElementShadow& Element::ensureShadow()
     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)
@@ -1753,9 +1722,15 @@ void Element::checkForEmptyStyleChange()
 
     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)
@@ -2085,7 +2060,7 @@ void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
 {
     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;
 
@@ -2164,7 +2139,7 @@ bool Element::isMouseFocusable() const
     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()));
@@ -2176,7 +2151,7 @@ void Element::dispatchBlurEvent(Element* newFocusedElement)
     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);
@@ -2277,12 +2252,12 @@ Node* Element::insertAdjacent(const String& where, Node* newChild, ExceptionStat
 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;
@@ -2391,7 +2366,7 @@ const AtomicString& Element::shadowPseudoId() const
 
 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);
 }
 
@@ -2427,26 +2402,32 @@ RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
     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
@@ -2623,7 +2604,7 @@ KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) 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)
@@ -2631,11 +2612,6 @@ 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
@@ -3102,7 +3078,7 @@ inline void Element::setInlineStyleFromString(const AtomicString& newStyleString
         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());
@@ -3239,7 +3215,7 @@ bool Element::supportsStyleSharing() const
     // 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;
 }
@@ -3254,4 +3230,41 @@ void Element::trace(Visitor* visitor)
     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