summaryrefslogtreecommitdiff
path: root/Source/WebCore/bindings/js/JSNodeCustom.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/bindings/js/JSNodeCustom.cpp')
-rw-r--r--Source/WebCore/bindings/js/JSNodeCustom.cpp246
1 files changed, 118 insertions, 128 deletions
diff --git a/Source/WebCore/bindings/js/JSNodeCustom.cpp b/Source/WebCore/bindings/js/JSNodeCustom.cpp
index 3c2468cd8..32548720c 100644
--- a/Source/WebCore/bindings/js/JSNodeCustom.cpp
+++ b/Source/WebCore/bindings/js/JSNodeCustom.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2009-2010, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -32,8 +32,6 @@
#include "Document.h"
#include "DocumentFragment.h"
#include "DocumentType.h"
-#include "Entity.h"
-#include "EntityReference.h"
#include "ExceptionCode.h"
#include "HTMLAudioElement.h"
#include "HTMLCanvasElement.h"
@@ -51,29 +49,22 @@
#include "JSDocument.h"
#include "JSDocumentFragment.h"
#include "JSDocumentType.h"
-#include "JSEntity.h"
-#include "JSEntityReference.h"
#include "JSEventListener.h"
#include "JSHTMLElement.h"
#include "JSHTMLElementWrapperFactory.h"
-#include "JSNotation.h"
#include "JSProcessingInstruction.h"
+#include "JSSVGElementWrapperFactory.h"
+#include "JSShadowRoot.h"
#include "JSText.h"
#include "Node.h"
-#include "Notation.h"
#include "ProcessingInstruction.h"
#include "RegisteredEventListener.h"
+#include "SVGElement.h"
+#include "ScriptState.h"
#include "ShadowRoot.h"
#include "StyleSheet.h"
#include "StyledElement.h"
#include "Text.h"
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefPtr.h>
-
-#if ENABLE(SVG)
-#include "JSSVGElementWrapperFactory.h"
-#include "SVGElement.h"
-#endif
using namespace JSC;
@@ -81,40 +72,28 @@ namespace WebCore {
using namespace HTMLNames;
-static inline bool isObservable(JSNode* jsNode, Node* node)
+static inline bool isReachableFromDOM(Node* node, SlotVisitor& visitor)
{
- // The root node keeps the tree intact.
- if (!node->parentNode())
- return true;
-
- if (jsNode->hasCustomProperties())
- return true;
-
- // A node's JS wrapper is responsible for marking its JS event listeners.
- if (node->hasEventListeners())
- return true;
-
- return false;
-}
+ if (!node->isConnected()) {
+ if (is<Element>(*node)) {
+ auto& element = downcast<Element>(*node);
-static inline bool isReachableFromDOM(JSNode* jsNode, Node* node, SlotVisitor& visitor)
-{
- if (!node->inDocument()) {
- // If a wrapper is the last reference to an image element
- // that is loading but not in the document, the wrapper is observable
- // because it is the only thing keeping the image element alive, and if
- // the element is destroyed, its load event will not fire.
- // FIXME: The DOM should manage this issue without the help of JavaScript wrappers.
- if (isHTMLImageElement(node)) {
- if (toHTMLImageElement(node)->hasPendingActivity())
- return true;
- }
- #if ENABLE(VIDEO)
- else if (isHTMLAudioElement(node)) {
- if (!toHTMLAudioElement(node)->paused())
- return true;
+ // If a wrapper is the last reference to an image element
+ // that is loading but not in the document, the wrapper is observable
+ // because it is the only thing keeping the image element alive, and if
+ // the element is destroyed, its load event will not fire.
+ // FIXME: The DOM should manage this issue without the help of JavaScript wrappers.
+ if (is<HTMLImageElement>(element)) {
+ if (downcast<HTMLImageElement>(element).hasPendingActivity())
+ return true;
+ }
+#if ENABLE(VIDEO)
+ else if (is<HTMLAudioElement>(element)) {
+ if (!downcast<HTMLAudioElement>(element).paused())
+ return true;
+ }
+#endif
}
- #endif
// If a node is firing event listeners, its wrapper is observable because
// its wrapper is responsible for marking those event listeners.
@@ -122,144 +101,155 @@ static inline bool isReachableFromDOM(JSNode* jsNode, Node* node, SlotVisitor& v
return true;
}
- return isObservable(jsNode, node) && visitor.containsOpaqueRoot(root(node));
+ return visitor.containsOpaqueRoot(root(node));
}
bool JSNodeOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
{
- JSNode* jsNode = jsCast<JSNode*>(handle.get().asCell());
- return isReachableFromDOM(jsNode, &jsNode->impl(), visitor);
+ JSNode* jsNode = jsCast<JSNode*>(handle.slot()->asCell());
+ return isReachableFromDOM(&jsNode->wrapped(), visitor);
}
-JSValue JSNode::insertBefore(ExecState* exec)
+JSValue JSNode::insertBefore(ExecState& state)
{
- ExceptionCode ec = 0;
- bool ok = impl().insertBefore(toNode(exec->argument(0)), toNode(exec->argument(1)), ec);
- setDOMException(exec, ec);
- if (ok)
- return exec->argument(0);
- return jsNull();
+ VM& vm = state.vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ if (UNLIKELY(state.argumentCount() < 2))
+ return throwException(&state, scope, createNotEnoughArgumentsError(&state));
+
+ JSValue newChildValue = state.uncheckedArgument(0);
+ auto* newChild = JSNode::toWrapped(vm, newChildValue);
+ if (UNLIKELY(!newChild))
+ return JSValue::decode(throwArgumentTypeError(state, scope, 0, "node", "Node", "insertBefore", "Node"));
+
+ propagateException(state, scope, wrapped().insertBefore(*newChild, JSNode::toWrapped(vm, state.uncheckedArgument(1))));
+ return newChildValue;
}
-JSValue JSNode::replaceChild(ExecState* exec)
+JSValue JSNode::replaceChild(ExecState& state)
{
- ExceptionCode ec = 0;
- bool ok = impl().replaceChild(toNode(exec->argument(0)), toNode(exec->argument(1)), ec);
- setDOMException(exec, ec);
- if (ok)
- return exec->argument(1);
- return jsNull();
+ VM& vm = state.vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ if (UNLIKELY(state.argumentCount() < 2))
+ return throwException(&state, scope, createNotEnoughArgumentsError(&state));
+
+ auto* newChild = JSNode::toWrapped(vm, state.uncheckedArgument(0));
+ JSValue oldChildValue = state.uncheckedArgument(1);
+ auto* oldChild = JSNode::toWrapped(vm, oldChildValue);
+ if (UNLIKELY(!newChild || !oldChild)) {
+ if (!newChild)
+ return JSValue::decode(throwArgumentTypeError(state, scope, 0, "node", "Node", "replaceChild", "Node"));
+ return JSValue::decode(throwArgumentTypeError(state, scope, 1, "child", "Node", "replaceChild", "Node"));
+ }
+
+ propagateException(state, scope, wrapped().replaceChild(*newChild, *oldChild));
+ return oldChildValue;
}
-JSValue JSNode::removeChild(ExecState* exec)
+JSValue JSNode::removeChild(ExecState& state)
{
- ExceptionCode ec = 0;
- bool ok = impl().removeChild(toNode(exec->argument(0)), ec);
- setDOMException(exec, ec);
- if (ok)
- return exec->argument(0);
- return jsNull();
+ VM& vm = state.vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ JSValue childValue = state.argument(0);
+ auto* child = JSNode::toWrapped(vm, childValue);
+ if (UNLIKELY(!child))
+ return JSValue::decode(throwArgumentTypeError(state, scope, 0, "child", "Node", "removeChild", "Node"));
+
+ propagateException(state, scope, wrapped().removeChild(*child));
+ return childValue;
}
-JSValue JSNode::appendChild(ExecState* exec)
+JSValue JSNode::appendChild(ExecState& state)
{
- ExceptionCode ec = 0;
- bool ok = impl().appendChild(toNode(exec->argument(0)), ec);
- setDOMException(exec, ec);
- if (ok)
- return exec->argument(0);
- return jsNull();
+ VM& vm = state.vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ JSValue newChildValue = state.argument(0);
+ auto newChild = JSNode::toWrapped(vm, newChildValue);
+ if (UNLIKELY(!newChild))
+ return JSValue::decode(throwArgumentTypeError(state, scope, 0, "node", "Node", "appendChild", "Node"));
+
+ propagateException(state, scope, wrapped().appendChild(*newChild));
+ return newChildValue;
}
JSScope* JSNode::pushEventHandlerScope(ExecState* exec, JSScope* node) const
{
- if (inherits(JSHTMLElement::info()))
+ if (inherits(exec->vm(), JSHTMLElement::info()))
return jsCast<const JSHTMLElement*>(this)->pushEventHandlerScope(exec, node);
return node;
}
-void JSNode::visitChildren(JSCell* cell, SlotVisitor& visitor)
+void JSNode::visitAdditionalChildren(SlotVisitor& visitor)
{
- JSNode* thisObject = jsCast<JSNode*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
- Base::visitChildren(thisObject, visitor);
-
- Node& node = thisObject->impl();
- node.visitJSEventListeners(visitor);
-
- visitor.addOpaqueRoot(root(node));
+ visitor.addOpaqueRoot(root(wrapped()));
}
-static ALWAYS_INLINE JSValue createWrapperInline(ExecState* exec, JSDOMGlobalObject* globalObject, Node* node)
+static ALWAYS_INLINE JSValue createWrapperInline(ExecState* exec, JSDOMGlobalObject* globalObject, Ref<Node>&& node)
{
- ASSERT(node);
- ASSERT(!getCachedWrapper(currentWorld(exec), node));
+ ASSERT(!getCachedWrapper(globalObject->world(), node));
- JSDOMWrapper* wrapper;
+ JSDOMObject* wrapper;
switch (node->nodeType()) {
case Node::ELEMENT_NODE:
- if (node->isHTMLElement())
- wrapper = createJSHTMLWrapper(exec, globalObject, toHTMLElement(node));
-#if ENABLE(SVG)
- else if (node->isSVGElement())
- wrapper = createJSSVGWrapper(exec, globalObject, toSVGElement(node));
-#endif
+ if (is<HTMLElement>(node.get()))
+ wrapper = createJSHTMLWrapper(globalObject, static_reference_cast<HTMLElement>(WTFMove(node)));
+ else if (is<SVGElement>(node.get()))
+ wrapper = createJSSVGWrapper(globalObject, static_reference_cast<SVGElement>(WTFMove(node)));
else
- wrapper = CREATE_DOM_WRAPPER(exec, globalObject, Element, node);
+ wrapper = createWrapper<Element>(globalObject, WTFMove(node));
break;
case Node::ATTRIBUTE_NODE:
- wrapper = CREATE_DOM_WRAPPER(exec, globalObject, Attr, node);
+ wrapper = createWrapper<Attr>(globalObject, WTFMove(node));
break;
case Node::TEXT_NODE:
- wrapper = CREATE_DOM_WRAPPER(exec, globalObject, Text, node);
+ wrapper = createWrapper<Text>(globalObject, WTFMove(node));
break;
case Node::CDATA_SECTION_NODE:
- wrapper = CREATE_DOM_WRAPPER(exec, globalObject, CDATASection, node);
- break;
- case Node::ENTITY_NODE:
- wrapper = CREATE_DOM_WRAPPER(exec, globalObject, Entity, node);
+ wrapper = createWrapper<CDATASection>(globalObject, WTFMove(node));
break;
case Node::PROCESSING_INSTRUCTION_NODE:
- wrapper = CREATE_DOM_WRAPPER(exec, globalObject, ProcessingInstruction, node);
+ wrapper = createWrapper<ProcessingInstruction>(globalObject, WTFMove(node));
break;
case Node::COMMENT_NODE:
- wrapper = CREATE_DOM_WRAPPER(exec, globalObject, Comment, node);
+ wrapper = createWrapper<Comment>(globalObject, WTFMove(node));
break;
case Node::DOCUMENT_NODE:
// we don't want to cache the document itself in the per-document dictionary
- return toJS(exec, globalObject, toDocument(node));
+ return toJS(exec, globalObject, downcast<Document>(node.get()));
case Node::DOCUMENT_TYPE_NODE:
- wrapper = CREATE_DOM_WRAPPER(exec, globalObject, DocumentType, node);
- break;
- case Node::NOTATION_NODE:
- wrapper = CREATE_DOM_WRAPPER(exec, globalObject, Notation, node);
+ wrapper = createWrapper<DocumentType>(globalObject, WTFMove(node));
break;
case Node::DOCUMENT_FRAGMENT_NODE:
- wrapper = CREATE_DOM_WRAPPER(exec, globalObject, DocumentFragment, node);
- break;
- case Node::ENTITY_REFERENCE_NODE:
- wrapper = CREATE_DOM_WRAPPER(exec, globalObject, EntityReference, node);
+ if (node->isShadowRoot())
+ wrapper = createWrapper<ShadowRoot>(globalObject, WTFMove(node));
+ else
+ wrapper = createWrapper<DocumentFragment>(globalObject, WTFMove(node));
break;
default:
- wrapper = CREATE_DOM_WRAPPER(exec, globalObject, Node, node);
+ wrapper = createWrapper<Node>(globalObject, WTFMove(node));
}
- return wrapper;
+ return wrapper;
}
-JSValue createWrapper(ExecState* exec, JSDOMGlobalObject* globalObject, Node* node)
+JSValue createWrapper(ExecState* exec, JSDOMGlobalObject* globalObject, Ref<Node>&& node)
{
- return createWrapperInline(exec, globalObject, node);
+ return createWrapperInline(exec, globalObject, WTFMove(node));
}
-JSValue toJSNewlyCreated(ExecState* exec, JSDOMGlobalObject* globalObject, Node* node)
+JSValue toJSNewlyCreated(ExecState* exec, JSDOMGlobalObject* globalObject, Ref<Node>&& node)
{
- if (!node)
- return jsNull();
-
- return createWrapperInline(exec, globalObject, node);
+ return createWrapperInline(exec, globalObject, WTFMove(node));
+}
+
+JSC::JSObject* getOutOfLineCachedWrapper(JSDOMGlobalObject* globalObject, Node& node)
+{
+ ASSERT(!globalObject->world().isNormal());
+ return globalObject->world().m_wrappers.get(&node);
}
void willCreatePossiblyOrphanedTreeByRemovalSlowCase(Node* root)
@@ -269,7 +259,7 @@ void willCreatePossiblyOrphanedTreeByRemovalSlowCase(Node* root)
return;
JSLockHolder lock(scriptState);
- toJS(scriptState, static_cast<JSDOMGlobalObject*>(scriptState->lexicalGlobalObject()), root);
+ toJS(scriptState, static_cast<JSDOMGlobalObject*>(scriptState->lexicalGlobalObject()), *root);
}
} // namespace WebCore