diff options
Diffstat (limited to 'Source/WebCore/bindings/js/JSNodeCustom.cpp')
-rw-r--r-- | Source/WebCore/bindings/js/JSNodeCustom.cpp | 246 |
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 |