diff options
Diffstat (limited to 'WebCore/bindings')
254 files changed, 10185 insertions, 3764 deletions
diff --git a/WebCore/bindings/js/DOMObjectWithSVGContext.h b/WebCore/bindings/js/DOMObjectWithSVGContext.h index 570548d..3d435cb 100644 --- a/WebCore/bindings/js/DOMObjectWithSVGContext.h +++ b/WebCore/bindings/js/DOMObjectWithSVGContext.h @@ -40,7 +40,7 @@ namespace WebCore { SVGElement* context() const { return m_context.get(); } protected: - DOMObjectWithSVGContext(PassRefPtr<JSC::Structure> structure, JSDOMGlobalObject*, SVGElement* context) + DOMObjectWithSVGContext(NonNullPassRefPtr<JSC::Structure> structure, JSDOMGlobalObject*, SVGElement* context) : DOMObject(structure) , m_context(context) { diff --git a/WebCore/bindings/js/JSAbstractWorkerCustom.cpp b/WebCore/bindings/js/JSAbstractWorkerCustom.cpp index 003f544..9411ad8 100644 --- a/WebCore/bindings/js/JSAbstractWorkerCustom.cpp +++ b/WebCore/bindings/js/JSAbstractWorkerCustom.cpp @@ -44,30 +44,17 @@ using namespace JSC; namespace WebCore { -void JSAbstractWorker::markChildren(MarkStack& markStack) -{ - Base::markChildren(markStack); - - markIfNotNull(markStack, m_impl->onerror()); - - typedef AbstractWorker::EventListenersMap EventListenersMap; - typedef AbstractWorker::ListenerVector ListenerVector; - EventListenersMap& eventListeners = m_impl->eventListeners(); - for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) { - for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter) - (*vecIter)->markJSFunction(markStack); - } -} - JSValue JSAbstractWorker::addEventListener(ExecState* exec, const ArgList& args) { JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext()); if (!globalObject) return jsUndefined(); - RefPtr<JSEventListener> listener = globalObject->findOrCreateJSEventListener(args.at(1)); - if (!listener) + + JSValue listener = args.at(1); + if (!listener.isObject()) return jsUndefined(); - impl()->addEventListener(args.at(0).toString(exec), listener.release(), args.at(2).toBoolean(exec)); + + impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false), args.at(2).toBoolean(exec)); return jsUndefined(); } @@ -76,10 +63,12 @@ JSValue JSAbstractWorker::removeEventListener(ExecState* exec, const ArgList& ar JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext()); if (!globalObject) return jsUndefined(); - JSEventListener* listener = globalObject->findJSEventListener(args.at(1)); - if (!listener) + + JSValue listener = args.at(1); + if (!listener.isObject()) return jsUndefined(); - impl()->removeEventListener(args.at(0).toString(exec), listener, args.at(2).toBoolean(exec)); + + impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec)); return jsUndefined(); } diff --git a/WebCore/bindings/js/JSAttrCustom.cpp b/WebCore/bindings/js/JSAttrCustom.cpp index abd5ad5..14457c4 100644 --- a/WebCore/bindings/js/JSAttrCustom.cpp +++ b/WebCore/bindings/js/JSAttrCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,7 +48,8 @@ void JSAttr::setValue(ExecState* exec, JSValue value) Element* ownerElement = imp->ownerElement(); if (ownerElement && (ownerElement->hasTagName(iframeTag) || ownerElement->hasTagName(frameTag))) { if (equalIgnoringCase(imp->name(), "src") && protocolIsJavaScript(deprecatedParseURL(attrValue))) { - if (!checkNodeSecurity(exec, static_cast<HTMLFrameElementBase*>(ownerElement)->contentDocument())) + Document* contentDocument = static_cast<HTMLFrameElementBase*>(ownerElement)->contentDocument(); + if (contentDocument && !checkNodeSecurity(exec, contentDocument)) return; } } @@ -58,4 +59,16 @@ void JSAttr::setValue(ExecState* exec, JSValue value) setDOMException(exec, ec); } +void JSAttr::markChildren(MarkStack& markStack) +{ + Base::markChildren(markStack); + + // Mark the element so that this will work to access the attribute even if the last + // other reference goes away. + if (Element* element = impl()->ownerElement()) { + if (JSNode* wrapper = getCachedDOMNodeWrapper(element->document(), element)) + markStack.append(wrapper); + } +} + } // namespace WebCore diff --git a/WebCore/bindings/js/JSAudioConstructor.cpp b/WebCore/bindings/js/JSAudioConstructor.cpp index 87a3880..174cc11 100644 --- a/WebCore/bindings/js/JSAudioConstructor.cpp +++ b/WebCore/bindings/js/JSAudioConstructor.cpp @@ -34,6 +34,7 @@ #include "JSHTMLAudioElement.h" #include "ScriptExecutionContext.h" #include "Text.h" +#include <runtime/Error.h> using namespace JSC; diff --git a/WebCore/bindings/js/JSCSSRuleListCustom.cpp b/WebCore/bindings/js/JSCSSRuleListCustom.cpp new file mode 100644 index 0000000..be3a9a2 --- /dev/null +++ b/WebCore/bindings/js/JSCSSRuleListCustom.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2009 Apple Inc. All right reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSCSSRuleList.h" + +#include "CSSRuleList.h" + +using namespace JSC; + +namespace WebCore { + +void JSCSSRuleList::markChildren(MarkStack& markStack) +{ + Base::markChildren(markStack); + + CSSRuleList* list = impl(); + JSGlobalData& globalData = *Heap::heap(this)->globalData(); + + unsigned length = list->length(); + for (unsigned i = 0; i < length; ++i) + markDOMObjectWrapper(markStack, globalData, list->item(i)); +} + +} diff --git a/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp b/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp index 280ec93..4a137d3 100644 --- a/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp +++ b/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,8 +27,8 @@ #include "JSCSSStyleDeclarationCustom.h" #include "AtomicString.h" +#include "CSSMutableStyleDeclaration.h" #include "CSSPrimitiveValue.h" -#include "CSSStyleDeclaration.h" #include "CSSValue.h" #include "PlatformString.h" #include <runtime/StringObjectThatMasqueradesAsUndefined.h> @@ -40,6 +40,21 @@ using namespace WTF; namespace WebCore { +void JSCSSStyleDeclaration::markChildren(MarkStack& markStack) +{ + Base::markChildren(markStack); + + CSSStyleDeclaration* declaration = impl(); + JSGlobalData& globalData = *Heap::heap(this)->globalData(); + + if (declaration->isMutableStyleDeclaration()) { + CSSMutableStyleDeclaration* mutableDeclaration = static_cast<CSSMutableStyleDeclaration*>(declaration); + CSSMutableStyleDeclaration::const_iterator end = mutableDeclaration->end(); + for (CSSMutableStyleDeclaration::const_iterator it = mutableDeclaration->begin(); it != end; ++it) + markDOMObjectWrapper(markStack, globalData, it->value()); + } +} + // Check for a CSS prefix. // Passed prefix is all lowercase. // First character of the prefix within the property name may be upper or lowercase. diff --git a/WebCore/bindings/js/JSCallbackData.cpp b/WebCore/bindings/js/JSCallbackData.cpp new file mode 100644 index 0000000..d08f760 --- /dev/null +++ b/WebCore/bindings/js/JSCallbackData.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSCallbackData.h" + +#include "Document.h" +#include "JSDOMBinding.h" + +using namespace JSC; + +namespace WebCore { + +void JSCallbackData::deleteData(void* context) +{ + delete static_cast<JSCallbackData*>(context); +} + +JSValue JSCallbackData::invokeCallback(MarkedArgumentBuffer& args, bool* raisedException) +{ + ASSERT(callback()); + ASSERT(globalObject()); + + ExecState* exec = globalObject()->globalExec(); + + JSValue function = callback()->get(exec, Identifier(exec, "handleEvent")); + CallData callData; + CallType callType = function.getCallData(callData); + if (callType == CallTypeNone) { + callType = callback()->getCallData(callData); + if (callType == CallTypeNone) + return JSValue(); + function = callback(); + } + + globalObject()->globalData()->timeoutChecker.start(); + JSValue result = call(exec, function, callType, callData, callback(), args); + globalObject()->globalData()->timeoutChecker.stop(); + + Document::updateStyleForAllDocuments(); + + if (exec->hadException()) { + reportCurrentException(exec); + if (raisedException) + *raisedException = true; + return result; + } + + return result; +} + +} // namespace WebCore diff --git a/WebCore/bindings/js/JSCallbackData.h b/WebCore/bindings/js/JSCallbackData.h new file mode 100644 index 0000000..4fc9f84 --- /dev/null +++ b/WebCore/bindings/js/JSCallbackData.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSCallbackData_h +#define JSCallbackData_h + +#include "JSDOMGlobalObject.h" +#include <runtime/JSObject.h> +#include <runtime/Protect.h> +#include <wtf/Threading.h> + +namespace WebCore { + +// We have to clean up this data on the main thread because unprotecting a +// JSObject on a non-main thread without synchronization would corrupt the heap +// (and synchronization would be slow). + +class JSCallbackData { +public: + static void deleteData(void*); + + JSCallbackData(JSC::JSObject* callback, JSDOMGlobalObject* globalObject) + : m_callback(callback) + , m_globalObject(globalObject) + { + } + + ~JSCallbackData() + { + ASSERT(isMainThread()); + } + + JSC::JSObject* callback() { return m_callback.get(); } + JSDOMGlobalObject* globalObject() { return m_globalObject.get(); } + + JSC::JSValue invokeCallback(JSC::MarkedArgumentBuffer&, bool* raisedException = 0); + +private: + JSC::ProtectedPtr<JSC::JSObject> m_callback; + JSC::ProtectedPtr<JSDOMGlobalObject> m_globalObject; +}; + +} // namespace WebCore + +#endif // JSCallbackData_h diff --git a/WebCore/bindings/js/JSCanvasArrayBufferConstructor.cpp b/WebCore/bindings/js/JSCanvasArrayBufferConstructor.cpp new file mode 100644 index 0000000..93d53ca --- /dev/null +++ b/WebCore/bindings/js/JSCanvasArrayBufferConstructor.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "JSCanvasArrayBufferConstructor.h" + +#include "Document.h" +#include "CanvasArrayBuffer.h" +#include "JSCanvasArrayBuffer.h" + +namespace WebCore { + +using namespace JSC; + +const ClassInfo JSCanvasArrayBufferConstructor::s_info = { "CanvasArrayBufferConstructor", 0, 0, 0 }; + +JSCanvasArrayBufferConstructor::JSCanvasArrayBufferConstructor(ExecState* exec, JSDOMGlobalObject* globalObject) + : DOMConstructorObject(JSCanvasArrayBufferConstructor::createStructure(globalObject->objectPrototype()), globalObject) +{ + putDirect(exec->propertyNames().prototype, JSCanvasArrayBufferPrototype::self(exec, globalObject), None); + putDirect(exec->propertyNames().length, jsNumber(exec, 2), ReadOnly|DontDelete|DontEnum); +} + +static JSObject* constructCanvasArrayBuffer(ExecState* exec, JSObject* constructor, const ArgList& args) +{ + JSCanvasArrayBufferConstructor* jsConstructor = static_cast<JSCanvasArrayBufferConstructor*>(constructor); + + unsigned int size = 0; + if (args.size() == 1) { + size = (unsigned int)args.at(0).toInt32(exec); + if (isnan(size)) + size = 0; + } + return asObject(toJS(exec, jsConstructor->globalObject(), CanvasArrayBuffer::create(size))); +} + +JSC::ConstructType JSCanvasArrayBufferConstructor::getConstructData(JSC::ConstructData& constructData) +{ + constructData.native.function = constructCanvasArrayBuffer; + return ConstructTypeHost; +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSCanvasArrayBufferConstructor.h b/WebCore/bindings/js/JSCanvasArrayBufferConstructor.h new file mode 100644 index 0000000..5f1254e --- /dev/null +++ b/WebCore/bindings/js/JSCanvasArrayBufferConstructor.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSCanvasArrayBufferConstructor_h +#define JSCanvasArrayBufferConstructor_h + +#include "JSDOMBinding.h" +#include "JSDocument.h" +#include "JSCanvasArrayBuffer.h" +#include <runtime/Error.h> + +namespace WebCore { + + class CanvasArray; + + // Template function used by CanvasXXXArrayConstructors + template<class C, typename T> + PassRefPtr<CanvasArray> construct(JSC::ExecState* exec, const JSC::ArgList& args) + { + // There are 3 constructors: + // + // 1) (in int size) + // 2) (in CanvasArrayBuffer buffer, [Optional] in int offset, [Optional] in unsigned int length) + // 3) (in sequence<T>) - This ends up being a JS "array-like" object + // + RefPtr<C> arrayObject; + + // For the 0 args case, just create an object without a buffer + if (args.size() < 1) + return C::create(0, 0, 0); + + if (args.at(0).isObject()) { + RefPtr<CanvasArrayBuffer> buffer = toCanvasArrayBuffer(args.at(0)); + if (buffer) { + int offset = (args.size() > 1) ? args.at(1).toInt32(exec) : 0; + unsigned int length = (args.size() > 2) ? static_cast<unsigned int>(args.at(2).toInt32(exec)) : 0; + return C::create(buffer, offset, length); + } + + JSC::JSObject* array = asObject(args.at(0)); + int length = array->get(exec, JSC::Identifier(exec, "length")).toInt32(exec); + void* tempValues; + if (!tryFastMalloc(length * sizeof(T)).getValue(tempValues)) { + throwError(exec, JSC::GeneralError); + return 0; + } + + OwnFastMallocPtr<T> values(static_cast<T*>(tempValues)); + for (int i = 0; i < length; ++i) { + JSC::JSValue v = array->get(exec, i); + if (exec->hadException()) + return 0; + values.get()[i] = static_cast<T>(v.toNumber(exec)); + } + + return C::create(values.get(), length); + } + + unsigned size = static_cast<unsigned>(args.at(0).toInt32(exec)); + return C::create(size); + } + + class JSCanvasArrayBufferConstructor : public DOMConstructorObject { + public: + JSCanvasArrayBufferConstructor(JSC::ExecState*, JSDOMGlobalObject*); + static const JSC::ClassInfo s_info; + + private: + virtual JSC::ConstructType getConstructData(JSC::ConstructData&); + virtual const JSC::ClassInfo* classInfo() const { return &s_info; } + }; + +} + +#endif // JSCanvasArrayBufferConstructor_h diff --git a/WebCore/bindings/js/JSCanvasArrayCustom.cpp b/WebCore/bindings/js/JSCanvasArrayCustom.cpp new file mode 100644 index 0000000..4aa1547 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasArrayCustom.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "config.h" +#include "JSCanvasArray.h" + +#include "CanvasArray.h" + +using namespace JSC; + +namespace WebCore { + +JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, CanvasArray* object) +{ + if (!object) + return jsUndefined(); + + + +#if ENABLE(3D_CANVAS) + if (object->is3d()) + return getDOMObjectWrapper<JSCanvasRenderingContext3D>(exec, globalObject, static_cast<CanvasRenderingContext3D*>(object)); +#endif + ASSERT(object->is2d()); + return getDOMObjectWrapper<JSCanvasRenderingContext2D>(exec, globalObject, static_cast<CanvasRenderingContext2D*>(object)); +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSCanvasByteArrayConstructor.cpp b/WebCore/bindings/js/JSCanvasByteArrayConstructor.cpp new file mode 100644 index 0000000..ec1d66d --- /dev/null +++ b/WebCore/bindings/js/JSCanvasByteArrayConstructor.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "JSCanvasByteArrayConstructor.h" + +#include "Document.h" +#include "CanvasByteArray.h" +#include "JSCanvasArrayBuffer.h" +#include "JSCanvasArrayBufferConstructor.h" +#include "JSCanvasByteArray.h" +#include <runtime/Error.h> + +namespace WebCore { + +using namespace JSC; + +const ClassInfo JSCanvasByteArrayConstructor::s_info = { "CanvasByteArrayConstructor", &JSCanvasArray::s_info, 0, 0 }; + +JSCanvasByteArrayConstructor::JSCanvasByteArrayConstructor(ExecState* exec, JSDOMGlobalObject* globalObject) + : DOMConstructorObject(JSCanvasByteArrayConstructor::createStructure(globalObject->objectPrototype()), globalObject) +{ + putDirect(exec->propertyNames().prototype, JSCanvasByteArrayPrototype::self(exec, globalObject), None); + putDirect(exec->propertyNames().length, jsNumber(exec, 2), ReadOnly|DontDelete|DontEnum); +} + +static JSObject* constructCanvasByteArray(ExecState* exec, JSObject* constructor, const ArgList& args) +{ + JSCanvasByteArrayConstructor* jsConstructor = static_cast<JSCanvasByteArrayConstructor*>(constructor); + RefPtr<CanvasByteArray> array = static_cast<CanvasByteArray*>(construct<CanvasByteArray, signed char>(exec, args).get()); + return asObject(toJS(exec, jsConstructor->globalObject(), array.get())); +} + +JSC::ConstructType JSCanvasByteArrayConstructor::getConstructData(JSC::ConstructData& constructData) +{ + constructData.native.function = constructCanvasByteArray; + return ConstructTypeHost; +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSNamedNodesCollection.h b/WebCore/bindings/js/JSCanvasByteArrayConstructor.h index cd6c2cb..4d5dc11 100644 --- a/WebCore/bindings/js/JSNamedNodesCollection.h +++ b/WebCore/bindings/js/JSCanvasByteArrayConstructor.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,44 +23,24 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSNamedNodesCollection_h -#define JSNamedNodesCollection_h +#ifndef JSCanvasByteArrayConstructor_h +#define JSCanvasByteArrayConstructor_h #include "JSDOMBinding.h" -#include <wtf/Vector.h> +#include "JSDocument.h" namespace WebCore { - class Node; - - // Internal class, used for the collection return by e.g. document.forms.myinput - // when multiple nodes have the same name. - class JSNamedNodesCollection : public DOMObjectWithGlobalPointer { + class JSCanvasByteArrayConstructor : public DOMConstructorObject { public: - JSNamedNodesCollection(JSC::ExecState*, JSDOMGlobalObject*, const Vector<RefPtr<Node> >&); - - virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier&, JSC::PropertySlot&); - - virtual const JSC::ClassInfo* classInfo() const { return &s_info; } + JSCanvasByteArrayConstructor(JSC::ExecState*, JSDOMGlobalObject*); static const JSC::ClassInfo s_info; - static JSC::ObjectPrototype* createPrototype(JSC::ExecState*, JSC::JSGlobalObject* globalObject) - { - return globalObject->objectPrototype(); - } - - static PassRefPtr<JSC::Structure> createStructure(JSC::JSValue prototype) - { - return JSC::Structure::create(prototype, JSC::TypeInfo(JSC::ObjectType)); - } - private: - static JSC::JSValue lengthGetter(JSC::ExecState*, const JSC::Identifier&, const JSC::PropertySlot&); - static JSC::JSValue indexGetter(JSC::ExecState*, const JSC::Identifier&, const JSC::PropertySlot&); - - OwnPtr<Vector<RefPtr<Node> > > m_nodes; + virtual JSC::ConstructType getConstructData(JSC::ConstructData&); + virtual const JSC::ClassInfo* classInfo() const { return &s_info; } }; -} // namespace WebCore +} -#endif // JSNamedNodesCollection_h +#endif // JSCanvasByteArrayConstructor_h diff --git a/WebCore/bindings/js/JSCanvasByteArrayCustom.cpp b/WebCore/bindings/js/JSCanvasByteArrayCustom.cpp new file mode 100644 index 0000000..04697ce --- /dev/null +++ b/WebCore/bindings/js/JSCanvasByteArrayCustom.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "JSCanvasByteArray.h" + +#include "CanvasByteArray.h" + +using namespace JSC; + +namespace WebCore { + +void JSCanvasByteArray::indexSetter(JSC::ExecState* exec, unsigned index, JSC::JSValue value) +{ + impl()->set(index, static_cast<signed char>(value.toInt32(exec))); +} + +JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, CanvasByteArray* object) +{ + return getDOMObjectWrapper<JSCanvasByteArray>(exec, globalObject, object); +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSCanvasFloatArrayConstructor.cpp b/WebCore/bindings/js/JSCanvasFloatArrayConstructor.cpp new file mode 100644 index 0000000..15e39c2 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasFloatArrayConstructor.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "JSCanvasFloatArrayConstructor.h" + +#include "Document.h" +#include "CanvasFloatArray.h" +#include "JSCanvasArrayBuffer.h" +#include "JSCanvasArrayBufferConstructor.h" +#include "JSCanvasFloatArray.h" +#include <runtime/Error.h> + +namespace WebCore { + +using namespace JSC; + +const ClassInfo JSCanvasFloatArrayConstructor::s_info = { "CanvasFloatArrayConstructor", &JSCanvasArray::s_info, 0, 0 }; + +JSCanvasFloatArrayConstructor::JSCanvasFloatArrayConstructor(ExecState* exec, JSDOMGlobalObject* globalObject) + : DOMConstructorObject(JSCanvasFloatArrayConstructor::createStructure(globalObject->objectPrototype()), globalObject) +{ + putDirect(exec->propertyNames().prototype, JSCanvasFloatArrayPrototype::self(exec, globalObject), None); + putDirect(exec->propertyNames().length, jsNumber(exec, 2), ReadOnly|DontDelete|DontEnum); +} + +static JSObject* constructCanvasFloatArray(ExecState* exec, JSObject* constructor, const ArgList& args) +{ + JSCanvasFloatArrayConstructor* jsConstructor = static_cast<JSCanvasFloatArrayConstructor*>(constructor); + RefPtr<CanvasFloatArray> array = static_cast<CanvasFloatArray*>(construct<CanvasFloatArray, float>(exec, args).get()); + return asObject(toJS(exec, jsConstructor->globalObject(), array.get())); +} + +JSC::ConstructType JSCanvasFloatArrayConstructor::getConstructData(JSC::ConstructData& constructData) +{ + constructData.native.function = constructCanvasFloatArray; + return ConstructTypeHost; +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSCanvasFloatArrayConstructor.h b/WebCore/bindings/js/JSCanvasFloatArrayConstructor.h new file mode 100644 index 0000000..efea250 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasFloatArrayConstructor.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSCanvasFloatArrayConstructor_h +#define JSCanvasFloatArrayConstructor_h + +#include "JSDOMBinding.h" +#include "JSDocument.h" + +namespace WebCore { + + class JSCanvasFloatArrayConstructor : public DOMConstructorObject { + public: + JSCanvasFloatArrayConstructor(JSC::ExecState*, JSDOMGlobalObject*); + static const JSC::ClassInfo s_info; + + private: + virtual JSC::ConstructType getConstructData(JSC::ConstructData&); + virtual const JSC::ClassInfo* classInfo() const { return &s_info; } + }; + +} + +#endif // JSCanvasFloatArrayConstructor_h diff --git a/WebCore/bindings/js/JSCanvasFloatArrayCustom.cpp b/WebCore/bindings/js/JSCanvasFloatArrayCustom.cpp new file mode 100644 index 0000000..20cd805 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasFloatArrayCustom.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "JSCanvasFloatArray.h" + +#include "CanvasFloatArray.h" + +using namespace JSC; + +namespace WebCore { + +void JSCanvasFloatArray::indexSetter(JSC::ExecState* exec, unsigned index, JSC::JSValue value) +{ + impl()->set(index, static_cast<float>(value.toInt32(exec))); +} + +JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, CanvasFloatArray* object) +{ + return getDOMObjectWrapper<JSCanvasFloatArray>(exec, globalObject, object); +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSCanvasIntArrayConstructor.cpp b/WebCore/bindings/js/JSCanvasIntArrayConstructor.cpp new file mode 100644 index 0000000..6d57912 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasIntArrayConstructor.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "JSCanvasIntArrayConstructor.h" + +#include "Document.h" +#include "CanvasIntArray.h" +#include "JSCanvasArrayBuffer.h" +#include "JSCanvasArrayBufferConstructor.h" +#include "JSCanvasIntArray.h" +#include <runtime/Error.h> + +namespace WebCore { + +using namespace JSC; + +const ClassInfo JSCanvasIntArrayConstructor::s_info = { "CanvasIntArrayConstructor", &JSCanvasArray::s_info, 0, 0 }; + +JSCanvasIntArrayConstructor::JSCanvasIntArrayConstructor(ExecState* exec, JSDOMGlobalObject* globalObject) + : DOMConstructorObject(JSCanvasIntArrayConstructor::createStructure(globalObject->objectPrototype()), globalObject) +{ + putDirect(exec->propertyNames().prototype, JSCanvasIntArrayPrototype::self(exec, globalObject), None); + putDirect(exec->propertyNames().length, jsNumber(exec, 2), ReadOnly|DontDelete|DontEnum); +} + +static JSObject* constructCanvasIntArray(ExecState* exec, JSObject* constructor, const ArgList& args) +{ + JSCanvasIntArrayConstructor* jsConstructor = static_cast<JSCanvasIntArrayConstructor*>(constructor); + RefPtr<CanvasIntArray> array = static_cast<CanvasIntArray*>(construct<CanvasIntArray, int>(exec, args).get()); + return asObject(toJS(exec, jsConstructor->globalObject(), array.get())); +} + +JSC::ConstructType JSCanvasIntArrayConstructor::getConstructData(JSC::ConstructData& constructData) +{ + constructData.native.function = constructCanvasIntArray; + return ConstructTypeHost; +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSCanvasIntArrayConstructor.h b/WebCore/bindings/js/JSCanvasIntArrayConstructor.h new file mode 100644 index 0000000..5e19652 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasIntArrayConstructor.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSCanvasIntArrayConstructor_h +#define JSCanvasIntArrayConstructor_h + +#include "JSDOMBinding.h" +#include "JSDocument.h" + +namespace WebCore { + + class JSCanvasIntArrayConstructor : public DOMConstructorObject { + public: + JSCanvasIntArrayConstructor(JSC::ExecState*, JSDOMGlobalObject*); + static const JSC::ClassInfo s_info; + + private: + virtual JSC::ConstructType getConstructData(JSC::ConstructData&); + virtual const JSC::ClassInfo* classInfo() const { return &s_info; } + }; + +} + +#endif // JSCanvasIntArrayConstructor_h diff --git a/WebCore/bindings/js/JSCanvasIntArrayCustom.cpp b/WebCore/bindings/js/JSCanvasIntArrayCustom.cpp new file mode 100644 index 0000000..8442b87 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasIntArrayCustom.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "JSCanvasIntArray.h" + +#include "CanvasIntArray.h" + +using namespace JSC; + +namespace WebCore { + +void JSCanvasIntArray::indexSetter(JSC::ExecState* exec, unsigned index, JSC::JSValue value) +{ + impl()->set(index, static_cast<signed int>(value.toInt32(exec))); +} + +JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, CanvasIntArray* object) +{ + return getDOMObjectWrapper<JSCanvasIntArray>(exec, globalObject, object); +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSCanvasNumberArrayCustom.cpp b/WebCore/bindings/js/JSCanvasNumberArrayCustom.cpp new file mode 100644 index 0000000..be10ac0 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasNumberArrayCustom.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "JSCanvasNumberArray.h" + +#include "CanvasNumberArray.h" + +using namespace JSC; + +namespace WebCore { + +JSValue JSCanvasNumberArray::getByIndex(JSC::ExecState* exec, unsigned int index) +{ + JSC::JSValue result = jsNumber(exec, impl()->item(index)); + return result; +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp b/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp index 398a6799..bb3500b 100644 --- a/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp +++ b/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp @@ -67,27 +67,31 @@ static PassRefPtr<CanvasStyle> toHTMLCanvasStyle(ExecState*, JSValue value) JSValue JSCanvasRenderingContext2D::strokeStyle(ExecState* exec) const { - return toJS(exec, impl()->strokeStyle()); + CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl()); + return toJS(exec, context->strokeStyle()); } void JSCanvasRenderingContext2D::setStrokeStyle(ExecState* exec, JSValue value) { - impl()->setStrokeStyle(toHTMLCanvasStyle(exec, value)); + CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl()); + context->setStrokeStyle(toHTMLCanvasStyle(exec, value)); } JSValue JSCanvasRenderingContext2D::fillStyle(ExecState* exec) const { - return toJS(exec, impl()->fillStyle()); + CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl()); + return toJS(exec, context->fillStyle()); } void JSCanvasRenderingContext2D::setFillStyle(ExecState* exec, JSValue value) { - impl()->setFillStyle(toHTMLCanvasStyle(exec, value)); + CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl()); + context->setFillStyle(toHTMLCanvasStyle(exec, value)); } JSValue JSCanvasRenderingContext2D::setFillColor(ExecState* exec, const ArgList& args) { - CanvasRenderingContext2D* context = impl(); + CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl()); // string arg = named color // number arg = gray color @@ -124,7 +128,7 @@ JSValue JSCanvasRenderingContext2D::setFillColor(ExecState* exec, const ArgList& JSValue JSCanvasRenderingContext2D::setStrokeColor(ExecState* exec, const ArgList& args) { - CanvasRenderingContext2D* context = impl(); + CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl()); // string arg = named color // number arg = gray color @@ -162,7 +166,7 @@ JSValue JSCanvasRenderingContext2D::setStrokeColor(ExecState* exec, const ArgLis JSValue JSCanvasRenderingContext2D::strokeRect(ExecState* exec, const ArgList& args) { - CanvasRenderingContext2D* context = impl(); + CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl()); if (args.size() <= 4) context->strokeRect(args.at(0).toFloat(exec), args.at(1).toFloat(exec), @@ -176,7 +180,7 @@ JSValue JSCanvasRenderingContext2D::strokeRect(ExecState* exec, const ArgList& a JSValue JSCanvasRenderingContext2D::drawImage(ExecState* exec, const ArgList& args) { - CanvasRenderingContext2D* context = impl(); + CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl()); // DrawImage has three variants: // drawImage(img, dx, dy) @@ -264,7 +268,7 @@ JSValue JSCanvasRenderingContext2D::drawImage(ExecState* exec, const ArgList& ar JSValue JSCanvasRenderingContext2D::drawImageFromRect(ExecState* exec, const ArgList& args) { - CanvasRenderingContext2D* context = impl(); + CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl()); JSValue value = args.at(0); if (!value.isObject()) @@ -284,7 +288,7 @@ JSValue JSCanvasRenderingContext2D::drawImageFromRect(ExecState* exec, const Arg JSValue JSCanvasRenderingContext2D::setShadow(ExecState* exec, const ArgList& args) { - CanvasRenderingContext2D* context = impl(); + CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl()); switch (args.size()) { case 3: @@ -330,7 +334,7 @@ JSValue JSCanvasRenderingContext2D::setShadow(ExecState* exec, const ArgList& ar JSValue JSCanvasRenderingContext2D::createPattern(ExecState* exec, const ArgList& args) { - CanvasRenderingContext2D* context = impl(); + CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl()); JSValue value = args.at(0); if (!value.isObject()) @@ -362,7 +366,7 @@ JSValue JSCanvasRenderingContext2D::putImageData(ExecState* exec, const ArgList& // putImageData has two variants // putImageData(ImageData, x, y) // putImageData(ImageData, x, y, dirtyX, dirtyY, dirtyWidth, dirtyHeight) - CanvasRenderingContext2D* context = impl(); + CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl()); ExceptionCode ec = 0; if (args.size() >= 7) @@ -377,7 +381,7 @@ JSValue JSCanvasRenderingContext2D::putImageData(ExecState* exec, const ArgList& JSValue JSCanvasRenderingContext2D::fillText(ExecState* exec, const ArgList& args) { - CanvasRenderingContext2D* context = impl(); + CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl()); // string arg = text to draw // number arg = x @@ -395,7 +399,7 @@ JSValue JSCanvasRenderingContext2D::fillText(ExecState* exec, const ArgList& arg JSValue JSCanvasRenderingContext2D::strokeText(ExecState* exec, const ArgList& args) { - CanvasRenderingContext2D* context = impl(); + CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl()); // string arg = text to draw // number arg = x diff --git a/WebCore/bindings/js/JSCanvasRenderingContext3DCustom.cpp b/WebCore/bindings/js/JSCanvasRenderingContext3DCustom.cpp new file mode 100644 index 0000000..3938ba1 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasRenderingContext3DCustom.cpp @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "JSCanvasRenderingContext3D.h" + +#include "CanvasRenderingContext3D.h" +#include "ExceptionCode.h" +#include "HTMLCanvasElement.h" +#include "HTMLImageElement.h" +#include "JSCanvasFloatArray.h" +#include "JSCanvasIntArray.h" +#include "JSHTMLCanvasElement.h" +#include "JSHTMLImageElement.h" +#include "JSWebKitCSSMatrix.h" +#include <runtime/Error.h> +#include <wtf/FastMalloc.h> +#include <wtf/OwnFastMallocPtr.h> + +using namespace JSC; + +namespace WebCore { + +JSValue JSCanvasRenderingContext3D::bufferData(JSC::ExecState* exec, JSC::ArgList const& args) +{ + if (args.size() != 3) + return throwError(exec, SyntaxError); + + unsigned target = args.at(0).toInt32(exec); + unsigned usage = args.at(2).toInt32(exec); + + // If argument 1 is a number, we are initializing this buffer to that size + if (!args.at(1).isObject()) { + unsigned int count = args.at(1).toInt32(exec); + static_cast<CanvasRenderingContext3D*>(impl())->bufferData(target, count, usage); + return jsUndefined(); + } + + CanvasArray* array = toCanvasArray(args.at(1)); + + static_cast<CanvasRenderingContext3D*>(impl())->bufferData(target, array, usage); + return jsUndefined(); +} + +JSValue JSCanvasRenderingContext3D::bufferSubData(JSC::ExecState* exec, JSC::ArgList const& args) +{ + if (args.size() != 3) + return throwError(exec, SyntaxError); + + unsigned target = args.at(0).toInt32(exec); + unsigned offset = args.at(1).toInt32(exec); + + CanvasArray* array = toCanvasArray(args.at(2)); + + static_cast<CanvasRenderingContext3D*>(impl())->bufferSubData(target, offset, array); + return jsUndefined(); +} + +// void texImage2DHTML(in unsigned long target, in unsigned long level, in HTMLImageElement image); +JSValue JSCanvasRenderingContext3D::texImage2D(ExecState* exec, const ArgList& args) +{ + if (args.size() < 3) + return throwError(exec, SyntaxError); + + ExceptionCode ec = 0; + CanvasRenderingContext3D* context = static_cast<CanvasRenderingContext3D*>(impl()); + unsigned target = args.at(0).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + + unsigned level = args.at(1).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + + if (args.size() > 5) { + // This must be the bare array case. + if (args.size() != 9) + return throwError(exec, SyntaxError); + + unsigned internalformat = args.at(2).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + + unsigned width = args.at(3).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + + unsigned height = args.at(4).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + + unsigned border = args.at(5).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + + unsigned format = args.at(6).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + + unsigned type = args.at(7).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + + CanvasArray* array = toCanvasArray(args.at(8)); + if (exec->hadException()) + return jsUndefined(); + + if (!array) + return throwError(exec, TypeError); + + // FIXME: Need to check to make sure CanvasArray is a CanvasByteArray or CanvasShortArray, + // depending on the passed type parameter. + + context->texImage2D(target, level, internalformat, width, height, border, format, type, array, ec); + return jsUndefined(); + } + + // The image parameter can be a <img> or <canvas> element. + JSValue value = args.at(2); + if (!value.isObject()) + return throwError(exec, TypeError); + JSObject* o = asObject(value); + + bool flipY = (args.size() > 3) ? args.at(3).toBoolean(exec) : false; + bool premultiplyAlpha = (args.size() > 4) ? args.at(3).toBoolean(exec) : false; + + if (o->inherits(&JSHTMLImageElement::s_info)) { + HTMLImageElement* imgElt = static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(o)->impl()); + context->texImage2D(target, level, imgElt, flipY, premultiplyAlpha, ec); + } else if (o->inherits(&JSHTMLCanvasElement::s_info)) { + HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(static_cast<JSHTMLElement*>(o)->impl()); + context->texImage2D(target, level, canvas, flipY, premultiplyAlpha, ec); + } else { + setDOMException(exec, TYPE_MISMATCH_ERR); + } + + return jsUndefined(); +} + +// void texSubImage2DHTML(in unsigned long target, in unsigned long level, in unsigned long xoff, in unsigned long yoff, in unsigned long width, in unsigned long height, in HTMLImageElement image); +JSValue JSCanvasRenderingContext3D::texSubImage2D(ExecState* exec, const ArgList& args) +{ + if (args.size() < 7 || args.size() > 9) + return throwError(exec, SyntaxError); + + CanvasRenderingContext3D* context = static_cast<CanvasRenderingContext3D*>(impl()); + unsigned target = args.at(0).toInt32(exec); + unsigned level = args.at(1).toInt32(exec); + unsigned xoff = args.at(2).toInt32(exec); + unsigned yoff = args.at(3).toInt32(exec); + unsigned width = args.at(4).toInt32(exec); + unsigned height = args.at(5).toInt32(exec); + + // The image parameter can be a <img> or <canvas> element. + JSValue value = args.at(6); + if (!value.isObject()) + return throwError(exec, TypeError); + JSObject* o = asObject(value); + + bool flipY = (args.size() > 3) ? args.at(3).toBoolean(exec) : false; + bool premultiplyAlpha = (args.size() > 4) ? args.at(3).toBoolean(exec) : false; + + ExceptionCode ec = 0; + if (o->inherits(&JSHTMLImageElement::s_info)) { + HTMLImageElement* imgElt = static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(o)->impl()); + context->texSubImage2D(target, level, xoff, yoff, width, height, imgElt, flipY, premultiplyAlpha, ec); + } else if (o->inherits(&JSHTMLCanvasElement::s_info)) { + HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(static_cast<JSHTMLElement*>(o)->impl()); + context->texSubImage2D(target, level, xoff, yoff, width, height, canvas, flipY, premultiplyAlpha, ec); + } else { + setDOMException(exec, TYPE_MISMATCH_ERR); + } + + return jsUndefined(); +} + +template<typename T> +void toArray(JSC::ExecState* exec, JSC::JSValue value, T*& array, int& size) +{ + array = 0; + + if (!value.isObject()) + return; + + JSC::JSObject* object = asObject(value); + int length = object->get(exec, JSC::Identifier(exec, "length")).toInt32(exec); + void* tempValues; + if (!tryFastMalloc(length * sizeof(T)).getValue(tempValues)) + return; + + T* values = static_cast<T*>(tempValues); + for (int i = 0; i < length; ++i) { + JSC::JSValue v = object->get(exec, i); + if (exec->hadException()) + return; + values[i] = static_cast<T>(v.toNumber(exec)); + } + + array = values; + size = length; +} + +enum DataFunctionToCall { + f_uniform1v, f_uniform2v, f_uniform3v, f_uniform4v, + f_vertexAttrib1v, f_vertexAttrib2v, f_vertexAttrib3v, f_vertexAttrib4v +}; + +enum DataFunctionMatrixToCall { + f_uniformMatrix2fv, f_uniformMatrix3fv, f_uniformMatrix4fv +}; + +static JSC::JSValue dataFunctionf(DataFunctionToCall f, JSC::ExecState* exec, const JSC::ArgList& args, CanvasRenderingContext3D* context) +{ + if (args.size() != 2) + return throwError(exec, SyntaxError); + + long location = args.at(0).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + + RefPtr<CanvasFloatArray> canvasArray = toCanvasFloatArray(args.at(1)); + if (exec->hadException()) + return jsUndefined(); + + if (canvasArray) { + switch(f) { + case f_uniform1v: context->uniform1fv(location, canvasArray.get()); break; + case f_uniform2v: context->uniform2fv(location, canvasArray.get()); break; + case f_uniform3v: context->uniform3fv(location, canvasArray.get()); break; + case f_uniform4v: context->uniform4fv(location, canvasArray.get()); break; + case f_vertexAttrib1v: context->vertexAttrib1fv(location, canvasArray.get()); break; + case f_vertexAttrib2v: context->vertexAttrib2fv(location, canvasArray.get()); break; + case f_vertexAttrib3v: context->vertexAttrib3fv(location, canvasArray.get()); break; + case f_vertexAttrib4v: context->vertexAttrib4fv(location, canvasArray.get()); break; + } + return jsUndefined(); + } + + float* array; + int size; + toArray<float>(exec, args.at(1), array, size); + + if (!array) + return throwError(exec, TypeError); + + switch(f) { + case f_uniform1v: context->uniform1fv(location, array, size); break; + case f_uniform2v: context->uniform2fv(location, array, size); break; + case f_uniform3v: context->uniform3fv(location, array, size); break; + case f_uniform4v: context->uniform4fv(location, array, size); break; + case f_vertexAttrib1v: context->vertexAttrib1fv(location, array, size); break; + case f_vertexAttrib2v: context->vertexAttrib2fv(location, array, size); break; + case f_vertexAttrib3v: context->vertexAttrib3fv(location, array, size); break; + case f_vertexAttrib4v: context->vertexAttrib4fv(location, array, size); break; + } + return jsUndefined(); +} + +static JSC::JSValue dataFunctioni(DataFunctionToCall f, JSC::ExecState* exec, const JSC::ArgList& args, CanvasRenderingContext3D* context) +{ + if (args.size() != 2) + return throwError(exec, SyntaxError); + + long location = args.at(0).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + + RefPtr<CanvasIntArray> canvasArray = toCanvasIntArray(args.at(1)); + if (exec->hadException()) + return jsUndefined(); + + if (canvasArray) { + switch(f) { + case f_uniform1v: context->uniform1iv(location, canvasArray.get()); break; + case f_uniform2v: context->uniform2iv(location, canvasArray.get()); break; + case f_uniform3v: context->uniform3iv(location, canvasArray.get()); break; + case f_uniform4v: context->uniform4iv(location, canvasArray.get()); break; + default: break; + } + return jsUndefined(); + } + + int* array; + int size; + toArray<int>(exec, args.at(1), array, size); + + if (!array) + return throwError(exec, TypeError); + + switch(f) { + case f_uniform1v: context->uniform1iv(location, array, size); break; + case f_uniform2v: context->uniform2iv(location, array, size); break; + case f_uniform3v: context->uniform3iv(location, array, size); break; + case f_uniform4v: context->uniform4iv(location, array, size); break; + default: break; + } + return jsUndefined(); +} + +static JSC::JSValue dataFunctionMatrix(DataFunctionMatrixToCall f, JSC::ExecState* exec, const JSC::ArgList& args, CanvasRenderingContext3D* context) +{ + if (args.size() != 3) + return throwError(exec, SyntaxError); + + long location = args.at(0).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + + bool transpose = args.at(1).toBoolean(exec); + if (exec->hadException()) + return jsUndefined(); + + RefPtr<CanvasFloatArray> canvasArray = toCanvasFloatArray(args.at(2)); + if (exec->hadException()) + return jsUndefined(); + + if (canvasArray) { + switch(f) { + case f_uniformMatrix2fv: context->uniformMatrix2fv(location, transpose, canvasArray.get()); break; + case f_uniformMatrix3fv: context->uniformMatrix3fv(location, transpose, canvasArray.get()); break; + case f_uniformMatrix4fv: context->uniformMatrix4fv(location, transpose, canvasArray.get()); break; + } + return jsUndefined(); + } + + float* array; + int size; + toArray<float>(exec, args.at(2), array, size); + + if (!array) + return throwError(exec, TypeError); + + switch(f) { + case f_uniformMatrix2fv: context->uniformMatrix2fv(location, transpose, array, size); break; + case f_uniformMatrix3fv: context->uniformMatrix3fv(location, transpose, array, size); break; + case f_uniformMatrix4fv: context->uniformMatrix4fv(location, transpose, array, size); break; + } + return jsUndefined(); +} + +JSC::JSValue JSCanvasRenderingContext3D::uniform1fv(JSC::ExecState* exec, const JSC::ArgList& args) +{ + return dataFunctionf(f_uniform1v, exec, args, static_cast<CanvasRenderingContext3D*>(impl())); +} + +JSC::JSValue JSCanvasRenderingContext3D::uniform1iv(JSC::ExecState* exec, const JSC::ArgList& args) +{ + return dataFunctioni(f_uniform1v, exec, args, static_cast<CanvasRenderingContext3D*>(impl())); +} + +JSC::JSValue JSCanvasRenderingContext3D::uniform2fv(JSC::ExecState* exec, const JSC::ArgList& args) +{ + return dataFunctionf(f_uniform2v, exec, args, static_cast<CanvasRenderingContext3D*>(impl())); +} + +JSC::JSValue JSCanvasRenderingContext3D::uniform2iv(JSC::ExecState* exec, const JSC::ArgList& args) +{ + return dataFunctioni(f_uniform2v, exec, args, static_cast<CanvasRenderingContext3D*>(impl())); +} + +JSC::JSValue JSCanvasRenderingContext3D::uniform3fv(JSC::ExecState* exec, const JSC::ArgList& args) +{ + return dataFunctionf(f_uniform3v, exec, args, static_cast<CanvasRenderingContext3D*>(impl())); +} + +JSC::JSValue JSCanvasRenderingContext3D::uniform3iv(JSC::ExecState* exec, const JSC::ArgList& args) +{ + return dataFunctioni(f_uniform3v, exec, args, static_cast<CanvasRenderingContext3D*>(impl())); +} + +JSC::JSValue JSCanvasRenderingContext3D::uniform4fv(JSC::ExecState* exec, const JSC::ArgList& args) +{ + return dataFunctionf(f_uniform4v, exec, args, static_cast<CanvasRenderingContext3D*>(impl())); +} + +JSC::JSValue JSCanvasRenderingContext3D::uniform4iv(JSC::ExecState* exec, const JSC::ArgList& args) +{ + return dataFunctioni(f_uniform4v, exec, args, static_cast<CanvasRenderingContext3D*>(impl())); +} + +JSC::JSValue JSCanvasRenderingContext3D::uniformMatrix2fv(JSC::ExecState* exec, const JSC::ArgList& args) +{ + return dataFunctionMatrix(f_uniformMatrix2fv, exec, args, static_cast<CanvasRenderingContext3D*>(impl())); +} + +JSC::JSValue JSCanvasRenderingContext3D::uniformMatrix3fv(JSC::ExecState* exec, const JSC::ArgList& args) +{ + return dataFunctionMatrix(f_uniformMatrix3fv, exec, args, static_cast<CanvasRenderingContext3D*>(impl())); +} + +JSC::JSValue JSCanvasRenderingContext3D::uniformMatrix4fv(JSC::ExecState* exec, const JSC::ArgList& args) +{ + return dataFunctionMatrix(f_uniformMatrix4fv, exec, args, static_cast<CanvasRenderingContext3D*>(impl())); +} + +JSC::JSValue JSCanvasRenderingContext3D::vertexAttrib1fv(JSC::ExecState* exec, const JSC::ArgList& args) +{ + return dataFunctionf(f_vertexAttrib1v, exec, args, static_cast<CanvasRenderingContext3D*>(impl())); +} + +JSC::JSValue JSCanvasRenderingContext3D::vertexAttrib2fv(JSC::ExecState* exec, const JSC::ArgList& args) +{ + return dataFunctionf(f_vertexAttrib2v, exec, args, static_cast<CanvasRenderingContext3D*>(impl())); +} + +JSC::JSValue JSCanvasRenderingContext3D::vertexAttrib3fv(JSC::ExecState* exec, const JSC::ArgList& args) +{ + return dataFunctionf(f_vertexAttrib3v, exec, args, static_cast<CanvasRenderingContext3D*>(impl())); +} + +JSC::JSValue JSCanvasRenderingContext3D::vertexAttrib4fv(JSC::ExecState* exec, const JSC::ArgList& args) +{ + return dataFunctionf(f_vertexAttrib4v, exec, args, static_cast<CanvasRenderingContext3D*>(impl())); +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSCanvasRenderingContextCustom.cpp b/WebCore/bindings/js/JSCanvasRenderingContextCustom.cpp new file mode 100644 index 0000000..0cd2aa3 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasRenderingContextCustom.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSCanvasRenderingContext.h" + +#include "CanvasRenderingContext2D.h" +#include "JSCanvasRenderingContext2D.h" +#if ENABLE(3D_CANVAS) +#include "CanvasRenderingContext3D.h" +#include "JSCanvasRenderingContext3D.h" +#endif + +using namespace JSC; + +namespace WebCore { + +JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, CanvasRenderingContext* object) +{ + if (!object) + return jsUndefined(); + +#if ENABLE(3D_CANVAS) + if (object->is3d()) + return getDOMObjectWrapper<JSCanvasRenderingContext3D>(exec, globalObject, static_cast<CanvasRenderingContext3D*>(object)); +#endif + ASSERT(object->is2d()); + return getDOMObjectWrapper<JSCanvasRenderingContext2D>(exec, globalObject, static_cast<CanvasRenderingContext2D*>(object)); +} + +} // namespace WebCore diff --git a/WebCore/bindings/js/JSCanvasShortArrayConstructor.cpp b/WebCore/bindings/js/JSCanvasShortArrayConstructor.cpp new file mode 100644 index 0000000..a885b7b --- /dev/null +++ b/WebCore/bindings/js/JSCanvasShortArrayConstructor.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "JSCanvasShortArrayConstructor.h" + +#include "Document.h" +#include "CanvasShortArray.h" +#include "JSCanvasArray.h" +#include "JSCanvasArrayBuffer.h" +#include "JSCanvasArrayBufferConstructor.h" +#include "JSCanvasShortArray.h" +#include <runtime/Error.h> + +namespace WebCore { + +using namespace JSC; + +const ClassInfo JSCanvasShortArrayConstructor::s_info = { "CanvasShortArrayConstructor", &JSCanvasArray::s_info, 0, 0 }; + +JSCanvasShortArrayConstructor::JSCanvasShortArrayConstructor(ExecState* exec, JSDOMGlobalObject* globalObject) + : DOMConstructorObject(JSCanvasShortArrayConstructor::createStructure(globalObject->objectPrototype()), globalObject) +{ + putDirect(exec->propertyNames().prototype, JSCanvasShortArrayPrototype::self(exec, globalObject), None); + putDirect(exec->propertyNames().length, jsNumber(exec, 2), ReadOnly|DontDelete|DontEnum); +} + +static JSObject* constructCanvasShortArray(ExecState* exec, JSObject* constructor, const ArgList& args) +{ + JSCanvasShortArrayConstructor* jsConstructor = static_cast<JSCanvasShortArrayConstructor*>(constructor); + RefPtr<CanvasShortArray> array = static_cast<CanvasShortArray*>(construct<CanvasShortArray, short>(exec, args).get()); + return asObject(toJS(exec, jsConstructor->globalObject(), array.get())); +} + +JSC::ConstructType JSCanvasShortArrayConstructor::getConstructData(JSC::ConstructData& constructData) +{ + constructData.native.function = constructCanvasShortArray; + return ConstructTypeHost; +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSCanvasShortArrayConstructor.h b/WebCore/bindings/js/JSCanvasShortArrayConstructor.h new file mode 100644 index 0000000..df21825 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasShortArrayConstructor.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSCanvasShortArrayConstructor_h +#define JSCanvasShortArrayConstructor_h + +#include "JSDOMBinding.h" +#include "JSDocument.h" + +namespace WebCore { + + class JSCanvasShortArrayConstructor : public DOMConstructorObject { + public: + JSCanvasShortArrayConstructor(JSC::ExecState*, JSDOMGlobalObject*); + static const JSC::ClassInfo s_info; + + private: + virtual JSC::ConstructType getConstructData(JSC::ConstructData&); + virtual const JSC::ClassInfo* classInfo() const { return &s_info; } + }; + +} + +#endif // JSCanvasShortArrayConstructor_h diff --git a/WebCore/bindings/js/JSCanvasShortArrayCustom.cpp b/WebCore/bindings/js/JSCanvasShortArrayCustom.cpp new file mode 100644 index 0000000..21af0a6 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasShortArrayCustom.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "JSCanvasShortArray.h" + +#include "CanvasShortArray.h" + +using namespace JSC; + +namespace WebCore { + +void JSCanvasShortArray::indexSetter(JSC::ExecState* exec, unsigned index, JSC::JSValue value) +{ + impl()->set(index, static_cast<signed short>(value.toInt32(exec))); +} + +JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, CanvasShortArray* object) +{ + return getDOMObjectWrapper<JSCanvasShortArray>(exec, globalObject, object); +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSCanvasUnsignedByteArrayConstructor.cpp b/WebCore/bindings/js/JSCanvasUnsignedByteArrayConstructor.cpp new file mode 100644 index 0000000..5d0800e --- /dev/null +++ b/WebCore/bindings/js/JSCanvasUnsignedByteArrayConstructor.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "JSCanvasUnsignedByteArrayConstructor.h" + +#include "Document.h" +#include "CanvasUnsignedByteArray.h" +#include "JSCanvasArrayBuffer.h" +#include "JSCanvasArrayBufferConstructor.h" +#include "JSCanvasUnsignedByteArray.h" +#include <runtime/Error.h> + +namespace WebCore { + +using namespace JSC; + +const ClassInfo JSCanvasUnsignedByteArrayConstructor::s_info = { "CanvasUnsignedByteArrayConstructor", &JSCanvasArray::s_info, 0, 0 }; + +JSCanvasUnsignedByteArrayConstructor::JSCanvasUnsignedByteArrayConstructor(ExecState* exec, JSDOMGlobalObject* globalObject) + : DOMConstructorObject(JSCanvasUnsignedByteArrayConstructor::createStructure(globalObject->objectPrototype()), globalObject) +{ + putDirect(exec->propertyNames().prototype, JSCanvasUnsignedByteArrayPrototype::self(exec, globalObject), None); + putDirect(exec->propertyNames().length, jsNumber(exec, 2), ReadOnly|DontDelete|DontEnum); +} + +static JSObject* constructCanvasUnsignedByteArray(ExecState* exec, JSObject* constructor, const ArgList& args) +{ + JSCanvasUnsignedByteArrayConstructor* jsConstructor = static_cast<JSCanvasUnsignedByteArrayConstructor*>(constructor); + RefPtr<CanvasUnsignedByteArray> array = static_cast<CanvasUnsignedByteArray*>(construct<CanvasUnsignedByteArray, unsigned char>(exec, args).get()); + return asObject(toJS(exec, jsConstructor->globalObject(), array.get())); +} + +JSC::ConstructType JSCanvasUnsignedByteArrayConstructor::getConstructData(JSC::ConstructData& constructData) +{ + constructData.native.function = constructCanvasUnsignedByteArray; + return ConstructTypeHost; +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSCanvasUnsignedByteArrayConstructor.h b/WebCore/bindings/js/JSCanvasUnsignedByteArrayConstructor.h new file mode 100644 index 0000000..9cfb721 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasUnsignedByteArrayConstructor.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSCanvasUnsignedByteArrayConstructor_h +#define JSCanvasUnsignedByteArrayConstructor_h + +#include "JSDOMBinding.h" +#include "JSDocument.h" + +namespace WebCore { + + class JSCanvasUnsignedByteArrayConstructor : public DOMConstructorObject { + public: + JSCanvasUnsignedByteArrayConstructor(JSC::ExecState*, JSDOMGlobalObject*); + static const JSC::ClassInfo s_info; + + private: + virtual JSC::ConstructType getConstructData(JSC::ConstructData&); + virtual const JSC::ClassInfo* classInfo() const { return &s_info; } + }; + +} + +#endif // JSCanvasUnsignedByteArrayConstructor_h diff --git a/WebCore/bindings/js/JSCanvasUnsignedByteArrayCustom.cpp b/WebCore/bindings/js/JSCanvasUnsignedByteArrayCustom.cpp new file mode 100644 index 0000000..f2b0c74 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasUnsignedByteArrayCustom.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "JSCanvasUnsignedByteArray.h" + +#include "CanvasUnsignedByteArray.h" + +using namespace JSC; + +namespace WebCore { + +void JSCanvasUnsignedByteArray::indexSetter(JSC::ExecState* exec, unsigned index, JSC::JSValue value) +{ + impl()->set(index, static_cast<unsigned char>(value.toInt32(exec))); +} + +JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, CanvasUnsignedByteArray* object) +{ + return getDOMObjectWrapper<JSCanvasUnsignedByteArray>(exec, globalObject, object); +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSCanvasUnsignedIntArrayConstructor.cpp b/WebCore/bindings/js/JSCanvasUnsignedIntArrayConstructor.cpp new file mode 100644 index 0000000..5f145a7 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasUnsignedIntArrayConstructor.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "JSCanvasUnsignedIntArrayConstructor.h" + +#include "Document.h" +#include "CanvasUnsignedIntArray.h" +#include "JSCanvasArrayBuffer.h" +#include "JSCanvasArrayBufferConstructor.h" +#include "JSCanvasUnsignedIntArray.h" +#include <runtime/Error.h> + +namespace WebCore { + +using namespace JSC; + +const ClassInfo JSCanvasUnsignedIntArrayConstructor::s_info = { "CanvasUnsignedIntArrayConstructor", &JSCanvasArray::s_info, 0, 0 }; + +JSCanvasUnsignedIntArrayConstructor::JSCanvasUnsignedIntArrayConstructor(ExecState* exec, JSDOMGlobalObject* globalObject) + : DOMConstructorObject(JSCanvasUnsignedIntArrayConstructor::createStructure(globalObject->objectPrototype()), globalObject) +{ + putDirect(exec->propertyNames().prototype, JSCanvasUnsignedIntArrayPrototype::self(exec, globalObject), None); + putDirect(exec->propertyNames().length, jsNumber(exec, 2), ReadOnly|DontDelete|DontEnum); +} + +static JSObject* constructCanvasUnsignedIntArray(ExecState* exec, JSObject* constructor, const ArgList& args) +{ + JSCanvasUnsignedIntArrayConstructor* jsConstructor = static_cast<JSCanvasUnsignedIntArrayConstructor*>(constructor); + RefPtr<CanvasUnsignedIntArray> array = static_cast<CanvasUnsignedIntArray*>(construct<CanvasUnsignedIntArray, unsigned int>(exec, args).get()); + return asObject(toJS(exec, jsConstructor->globalObject(), array.get())); +} + +JSC::ConstructType JSCanvasUnsignedIntArrayConstructor::getConstructData(JSC::ConstructData& constructData) +{ + constructData.native.function = constructCanvasUnsignedIntArray; + return ConstructTypeHost; +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSCanvasUnsignedIntArrayConstructor.h b/WebCore/bindings/js/JSCanvasUnsignedIntArrayConstructor.h new file mode 100644 index 0000000..6016159 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasUnsignedIntArrayConstructor.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSCanvasUnsignedIntArrayConstructor_h +#define JSCanvasUnsignedIntArrayConstructor_h + +#include "JSDOMBinding.h" +#include "JSDocument.h" + +namespace WebCore { + + class JSCanvasUnsignedIntArrayConstructor : public DOMConstructorObject { + public: + JSCanvasUnsignedIntArrayConstructor(JSC::ExecState*, JSDOMGlobalObject*); + static const JSC::ClassInfo s_info; + + private: + virtual JSC::ConstructType getConstructData(JSC::ConstructData&); + virtual const JSC::ClassInfo* classInfo() const { return &s_info; } + }; + +} + +#endif // JSCanvasUnsignedIntArrayConstructor_h diff --git a/WebCore/bindings/js/JSCanvasUnsignedIntArrayCustom.cpp b/WebCore/bindings/js/JSCanvasUnsignedIntArrayCustom.cpp new file mode 100644 index 0000000..95a80a7 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasUnsignedIntArrayCustom.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "JSCanvasUnsignedIntArray.h" + +#include "CanvasUnsignedIntArray.h" + +using namespace JSC; + +namespace WebCore { + +void JSCanvasUnsignedIntArray::indexSetter(JSC::ExecState* exec, unsigned index, JSC::JSValue value) +{ + impl()->set(index, static_cast<unsigned int>(value.toInt32(exec))); +} + +JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, CanvasUnsignedIntArray* object) +{ + return getDOMObjectWrapper<JSCanvasUnsignedIntArray>(exec, globalObject, object); +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSCanvasUnsignedShortArrayConstructor.cpp b/WebCore/bindings/js/JSCanvasUnsignedShortArrayConstructor.cpp new file mode 100644 index 0000000..9735693 --- /dev/null +++ b/WebCore/bindings/js/JSCanvasUnsignedShortArrayConstructor.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "JSCanvasUnsignedShortArrayConstructor.h" + +#include "Document.h" +#include "CanvasUnsignedShortArray.h" +#include "JSCanvasArrayBuffer.h" +#include "JSCanvasArrayBufferConstructor.h" +#include "JSCanvasUnsignedShortArray.h" +#include <runtime/Error.h> + +namespace WebCore { + +using namespace JSC; + +const ClassInfo JSCanvasUnsignedShortArrayConstructor::s_info = { "CanvasUnsignedShortArrayConstructor", &JSCanvasArray::s_info, 0, 0 }; + +JSCanvasUnsignedShortArrayConstructor::JSCanvasUnsignedShortArrayConstructor(ExecState* exec, JSDOMGlobalObject* globalObject) + : DOMConstructorObject(JSCanvasUnsignedShortArrayConstructor::createStructure(globalObject->objectPrototype()), globalObject) +{ + putDirect(exec->propertyNames().prototype, JSCanvasUnsignedShortArrayPrototype::self(exec, globalObject), None); + putDirect(exec->propertyNames().length, jsNumber(exec, 2), ReadOnly|DontDelete|DontEnum); +} + +static JSObject* constructCanvasUnsignedShortArray(ExecState* exec, JSObject* constructor, const ArgList& args) +{ + JSCanvasUnsignedShortArrayConstructor* jsConstructor = static_cast<JSCanvasUnsignedShortArrayConstructor*>(constructor); + RefPtr<CanvasUnsignedShortArray> array = static_cast<CanvasUnsignedShortArray*>(construct<CanvasUnsignedShortArray, unsigned short>(exec, args).get()); + return asObject(toJS(exec, jsConstructor->globalObject(), array.get())); +} + +JSC::ConstructType JSCanvasUnsignedShortArrayConstructor::getConstructData(JSC::ConstructData& constructData) +{ + constructData.native.function = constructCanvasUnsignedShortArray; + return ConstructTypeHost; +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSCanvasUnsignedShortArrayConstructor.h b/WebCore/bindings/js/JSCanvasUnsignedShortArrayConstructor.h new file mode 100644 index 0000000..23c197f --- /dev/null +++ b/WebCore/bindings/js/JSCanvasUnsignedShortArrayConstructor.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSCanvasUnsignedShortArrayConstructor_h +#define JSCanvasUnsignedShortArrayConstructor_h + +#include "JSDOMBinding.h" +#include "JSDocument.h" + +namespace WebCore { + + class JSCanvasUnsignedShortArrayConstructor : public DOMConstructorObject { + public: + JSCanvasUnsignedShortArrayConstructor(JSC::ExecState*, JSDOMGlobalObject*); + static const JSC::ClassInfo s_info; + + private: + virtual JSC::ConstructType getConstructData(JSC::ConstructData&); + virtual const JSC::ClassInfo* classInfo() const { return &s_info; } + }; + +} + +#endif // JSCanvasUnsignedShortArrayConstructor_h diff --git a/WebCore/bindings/js/JSCanvasUnsignedShortArrayCustom.cpp b/WebCore/bindings/js/JSCanvasUnsignedShortArrayCustom.cpp new file mode 100644 index 0000000..290cd4b --- /dev/null +++ b/WebCore/bindings/js/JSCanvasUnsignedShortArrayCustom.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "JSCanvasUnsignedShortArray.h" + +#include "CanvasUnsignedShortArray.h" + +using namespace JSC; + +namespace WebCore { + +void JSCanvasUnsignedShortArray::indexSetter(JSC::ExecState* exec, unsigned index, JSC::JSValue value) +{ + impl()->set(index, static_cast<unsigned short>(value.toInt32(exec))); +} + +JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, CanvasUnsignedShortArray* object) +{ + return getDOMObjectWrapper<JSCanvasUnsignedShortArray>(exec, globalObject, object); +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/js/JSCustomPositionCallback.cpp b/WebCore/bindings/js/JSCustomPositionCallback.cpp index ec2d8e3..e5f83aa 100644 --- a/WebCore/bindings/js/JSCustomPositionCallback.cpp +++ b/WebCore/bindings/js/JSCustomPositionCallback.cpp @@ -35,52 +35,20 @@ namespace WebCore { using namespace JSC; -JSCustomPositionCallback::JSCustomPositionCallback(JSObject* callback, Frame* frame) - : m_callback(callback) - , m_frame(frame) +JSCustomPositionCallback::JSCustomPositionCallback(JSObject* callback, JSDOMGlobalObject* globalObject) + : m_data(callback, globalObject) { } void JSCustomPositionCallback::handleEvent(Geoposition* geoposition) { - ASSERT(m_callback); - ASSERT(m_frame); - - if (!m_frame->script()->isEnabled()) - return; - - // FIXME: This is likely the wrong globalObject (for prototype chains at least) - JSGlobalObject* globalObject = m_frame->script()->globalObject(); - ExecState* exec = globalObject->globalExec(); - - JSC::JSLock lock(SilenceAssertionsOnly); - - JSValue function = m_callback->get(exec, Identifier(exec, "handleEvent")); - CallData callData; - CallType callType = function.getCallData(callData); - if (callType == CallTypeNone) { - callType = m_callback->getCallData(callData); - if (callType == CallTypeNone) { - // FIXME: Should an exception be thrown here? - return; - } - function = m_callback; - } - RefPtr<JSCustomPositionCallback> protect(this); + JSC::JSLock lock(SilenceAssertionsOnly); + ExecState* exec = m_data.globalObject()->globalExec(); MarkedArgumentBuffer args; args.append(toJS(exec, deprecatedGlobalObjectForPrototype(exec), geoposition)); - - globalObject->globalData()->timeoutChecker.start(); - call(exec, function, callType, callData, m_callback, args); - globalObject->globalData()->timeoutChecker.stop(); - - if (exec->hadException()) { - reportCurrentException(exec); - } - - Document::updateStyleForAllDocuments(); + m_data.invokeCallback(args); } } // namespace WebCore diff --git a/WebCore/bindings/js/JSCustomPositionCallback.h b/WebCore/bindings/js/JSCustomPositionCallback.h index 9c8fe86..ad5528d 100644 --- a/WebCore/bindings/js/JSCustomPositionCallback.h +++ b/WebCore/bindings/js/JSCustomPositionCallback.h @@ -26,31 +26,28 @@ #ifndef JSCustomPositionCallback_h #define JSCustomPositionCallback_h +#include "JSCallbackData.h" #include "PositionCallback.h" -#include <runtime/JSObject.h> -#include <runtime/Protect.h> #include <wtf/Forward.h> -namespace JSC { - class JSObject; -} - namespace WebCore { -class Frame; class Geoposition; +class JSDOMGlobalObject; class JSCustomPositionCallback : public PositionCallback { public: - static PassRefPtr<JSCustomPositionCallback> create(JSC::JSObject* callback, Frame* frame) { return adoptRef(new JSCustomPositionCallback(callback, frame)); } + static PassRefPtr<JSCustomPositionCallback> create(JSC::JSObject* callback, JSDOMGlobalObject* globalObject) + { + return adoptRef(new JSCustomPositionCallback(callback, globalObject)); + } - virtual void handleEvent(Geoposition*); - private: - JSCustomPositionCallback(JSC::JSObject* callback, Frame*); + JSCustomPositionCallback(JSC::JSObject* callback, JSDOMGlobalObject*); - JSC::ProtectedPtr<JSC::JSObject> m_callback; - RefPtr<Frame> m_frame; + virtual void handleEvent(Geoposition*); + + JSCallbackData m_data; }; } // namespace WebCore diff --git a/WebCore/bindings/js/JSCustomPositionErrorCallback.cpp b/WebCore/bindings/js/JSCustomPositionErrorCallback.cpp index cda5738..bd64deb 100644 --- a/WebCore/bindings/js/JSCustomPositionErrorCallback.cpp +++ b/WebCore/bindings/js/JSCustomPositionErrorCallback.cpp @@ -35,51 +35,21 @@ namespace WebCore { using namespace JSC; -JSCustomPositionErrorCallback::JSCustomPositionErrorCallback(JSObject* callback, Frame* frame) - : m_callback(callback) - , m_frame(frame) +JSCustomPositionErrorCallback::JSCustomPositionErrorCallback(JSObject* callback, JSDOMGlobalObject* globalObject) + : m_data(callback, globalObject) { } void JSCustomPositionErrorCallback::handleEvent(PositionError* positionError) { - ASSERT(m_callback); - ASSERT(m_frame); - - if (!m_frame->script()->isEnabled()) - return; + RefPtr<JSCustomPositionErrorCallback> protect(this); - // FIXME: This is likely the wrong globalObject (for prototype chains at least) - JSGlobalObject* globalObject = m_frame->script()->globalObject(); - ExecState* exec = globalObject->globalExec(); - JSC::JSLock lock(SilenceAssertionsOnly); - - JSValue function = m_callback->get(exec, Identifier(exec, "handleEvent")); - CallData callData; - CallType callType = function.getCallData(callData); - if (callType == CallTypeNone) { - callType = m_callback->getCallData(callData); - if (callType == CallTypeNone) { - // FIXME: Should an exception be thrown here? - return; - } - function = m_callback; - } - - RefPtr<JSCustomPositionErrorCallback> protect(this); - + ExecState* exec = m_data.globalObject()->globalExec(); MarkedArgumentBuffer args; args.append(toJS(exec, deprecatedGlobalObjectForPrototype(exec), positionError)); - globalObject->globalData()->timeoutChecker.start(); - call(exec, function, callType, callData, m_callback, args); - globalObject->globalData()->timeoutChecker.stop(); - - if (exec->hadException()) - reportCurrentException(exec); - - Document::updateStyleForAllDocuments(); + m_data.invokeCallback(args); } } // namespace WebCore diff --git a/WebCore/bindings/js/JSCustomPositionErrorCallback.h b/WebCore/bindings/js/JSCustomPositionErrorCallback.h index 9f143a2..59328ca 100644 --- a/WebCore/bindings/js/JSCustomPositionErrorCallback.h +++ b/WebCore/bindings/js/JSCustomPositionErrorCallback.h @@ -26,31 +26,26 @@ #ifndef JSCustomPositionErrorCallback_h #define JSCustomPositionErrorCallback_h +#include "JSCallbackData.h" #include "PositionErrorCallback.h" -#include <runtime/JSObject.h> -#include <runtime/Protect.h> #include <wtf/Forward.h> -namespace JSC { - class JSObject; -} - namespace WebCore { -class Frame; class PositionError; class JSCustomPositionErrorCallback : public PositionErrorCallback { public: - static PassRefPtr<JSCustomPositionErrorCallback> create(JSC::JSObject* callback, Frame* frame) { return adoptRef(new JSCustomPositionErrorCallback(callback, frame)); } + static PassRefPtr<JSCustomPositionErrorCallback> create(JSC::JSObject* callback, JSDOMGlobalObject* globalObject) + { + return adoptRef(new JSCustomPositionErrorCallback(callback, globalObject)); + } - virtual void handleEvent(PositionError*); - private: - JSCustomPositionErrorCallback(JSC::JSObject* callback, Frame*); - - JSC::ProtectedPtr<JSC::JSObject> m_callback; - RefPtr<Frame> m_frame; + JSCustomPositionErrorCallback(JSC::JSObject* callback, JSDOMGlobalObject* globalObject); + virtual void handleEvent(PositionError*); + + JSCallbackData m_data; }; } // namespace WebCore diff --git a/WebCore/bindings/js/JSCustomSQLStatementCallback.cpp b/WebCore/bindings/js/JSCustomSQLStatementCallback.cpp index d0943de..1f6bd95 100644 --- a/WebCore/bindings/js/JSCustomSQLStatementCallback.cpp +++ b/WebCore/bindings/js/JSCustomSQLStatementCallback.cpp @@ -28,6 +28,7 @@ #include "config.h" #include "JSCustomSQLStatementCallback.h" + #if ENABLE(DATABASE) #include "Frame.h" @@ -35,60 +36,38 @@ #include "JSSQLResultSet.h" #include "JSSQLTransaction.h" #include <runtime/JSLock.h> +#include <wtf/MainThread.h> namespace WebCore { using namespace JSC; -JSCustomSQLStatementCallback::JSCustomSQLStatementCallback(JSObject* callback, Frame* frame) - : m_callback(callback) - , m_frame(frame) +JSCustomSQLStatementCallback::JSCustomSQLStatementCallback(JSObject* callback, JSDOMGlobalObject* globalObject) + : m_data(new JSCallbackData(callback, globalObject)) { } -void JSCustomSQLStatementCallback::handleEvent(SQLTransaction* transaction, SQLResultSet* resultSet, bool& raisedException) +JSCustomSQLStatementCallback::~JSCustomSQLStatementCallback() { - ASSERT(m_callback); - ASSERT(m_frame); - - if (!m_frame->script()->isEnabled()) - return; - - // FIXME: This is likely the wrong globalObject (for prototype chains at least) - JSGlobalObject* globalObject = m_frame->script()->globalObject(); - ExecState* exec = globalObject->globalExec(); - - JSC::JSLock lock(SilenceAssertionsOnly); + callOnMainThread(JSCallbackData::deleteData, m_data); +#ifndef NDEBUG + m_data = 0; +#endif +} - JSValue function = m_callback->get(exec, Identifier(exec, "handleEvent")); - CallData callData; - CallType callType = function.getCallData(callData); - if (callType == CallTypeNone) { - callType = m_callback->getCallData(callData); - if (callType == CallTypeNone) { - // FIXME: Should an exception be thrown here? - return; - } - function = m_callback; - } +void JSCustomSQLStatementCallback::handleEvent(SQLTransaction* transaction, SQLResultSet* resultSet, bool& raisedException) +{ + ASSERT(m_data); RefPtr<JSCustomSQLStatementCallback> protect(this); + JSC::JSLock lock(SilenceAssertionsOnly); + ExecState* exec = m_data->globalObject()->globalExec(); MarkedArgumentBuffer args; args.append(toJS(exec, deprecatedGlobalObjectForPrototype(exec), transaction)); args.append(toJS(exec, deprecatedGlobalObjectForPrototype(exec), resultSet)); - - globalObject->globalData()->timeoutChecker.start(); - call(exec, function, callType, callData, m_callback, args); - globalObject->globalData()->timeoutChecker.stop(); - - if (exec->hadException()) { - reportCurrentException(exec); - - raisedException = true; - } - Document::updateStyleForAllDocuments(); + m_data->invokeCallback(args, &raisedException); } } diff --git a/WebCore/bindings/js/JSCustomSQLStatementCallback.h b/WebCore/bindings/js/JSCustomSQLStatementCallback.h index c380670..259aecf 100644 --- a/WebCore/bindings/js/JSCustomSQLStatementCallback.h +++ b/WebCore/bindings/js/JSCustomSQLStatementCallback.h @@ -31,32 +31,29 @@ #if ENABLE(DATABASE) +#include "JSCallbackData.h" #include "SQLStatementCallback.h" - -#include <runtime/JSObject.h> -#include <runtime/Protect.h> #include <wtf/Forward.h> -namespace JSC { - class JSObject; -} - namespace WebCore { -class Frame; class SQLResultSet; class JSCustomSQLStatementCallback : public SQLStatementCallback { public: - static PassRefPtr<JSCustomSQLStatementCallback> create(JSC::JSObject* callback, Frame* frame) { return adoptRef(new JSCustomSQLStatementCallback(callback, frame)); } + static PassRefPtr<JSCustomSQLStatementCallback> create(JSC::JSObject* callback, JSDOMGlobalObject* globalObject) + { + return adoptRef(new JSCustomSQLStatementCallback(callback, globalObject)); + } + + virtual ~JSCustomSQLStatementCallback(); virtual void handleEvent(SQLTransaction*, SQLResultSet*, bool& raisedException); private: - JSCustomSQLStatementCallback(JSC::JSObject* callback, Frame*); + JSCustomSQLStatementCallback(JSC::JSObject* callback, JSDOMGlobalObject*); - JSC::ProtectedPtr<JSC::JSObject> m_callback; - RefPtr<Frame> m_frame; + JSCallbackData* m_data; }; } diff --git a/WebCore/bindings/js/JSCustomSQLStatementErrorCallback.cpp b/WebCore/bindings/js/JSCustomSQLStatementErrorCallback.cpp index 6c831ac..6178509 100644 --- a/WebCore/bindings/js/JSCustomSQLStatementErrorCallback.cpp +++ b/WebCore/bindings/js/JSCustomSQLStatementErrorCallback.cpp @@ -32,75 +32,51 @@ #if ENABLE(DATABASE) #include "Frame.h" -#include "ScriptController.h" +#include "JSCallbackData.h" #include "JSSQLError.h" #include "JSSQLTransaction.h" +#include "ScriptController.h" #include <runtime/JSLock.h> +#include <wtf/MainThread.h> namespace WebCore { using namespace JSC; -JSCustomSQLStatementErrorCallback::JSCustomSQLStatementErrorCallback(JSObject* callback, Frame* frame) - : m_callback(callback) - , m_frame(frame) +JSCustomSQLStatementErrorCallback::JSCustomSQLStatementErrorCallback(JSObject* callback, JSDOMGlobalObject* globalObject) + : m_data(new JSCallbackData(callback, globalObject)) { } - -bool JSCustomSQLStatementErrorCallback::handleEvent(SQLTransaction* transaction, SQLError* error) -{ - ASSERT(m_callback); - ASSERT(m_frame); - - if (!m_frame->script()->isEnabled()) - return true; - // FIXME: This is likely the wrong globalObject (for prototype chains at least) - JSGlobalObject* globalObject = m_frame->script()->globalObject(); - ExecState* exec = globalObject->globalExec(); - - JSC::JSLock lock(SilenceAssertionsOnly); - - JSValue handleEventFunction = m_callback->get(exec, Identifier(exec, "handleEvent")); - CallData handleEventCallData; - CallType handleEventCallType = handleEventFunction.getCallData(handleEventCallData); - CallData callbackCallData; - CallType callbackCallType = CallTypeNone; +JSCustomSQLStatementErrorCallback::~JSCustomSQLStatementErrorCallback() +{ + callOnMainThread(JSCallbackData::deleteData, m_data); +#ifndef NDEBUG + m_data = 0; +#endif +} - if (handleEventCallType == CallTypeNone) { - callbackCallType = m_callback->getCallData(callbackCallData); - if (callbackCallType == CallTypeNone) { - // FIXME: Should an exception be thrown here? - return true; - } - } +bool JSCustomSQLStatementErrorCallback::handleEvent(SQLTransaction* transaction, SQLError* error) +{ + ASSERT(m_data); RefPtr<JSCustomSQLStatementErrorCallback> protect(this); + JSC::JSLock lock(SilenceAssertionsOnly); + ExecState* exec = m_data->globalObject()->globalExec(); MarkedArgumentBuffer args; args.append(toJS(exec, deprecatedGlobalObjectForPrototype(exec), transaction)); args.append(toJS(exec, deprecatedGlobalObjectForPrototype(exec), error)); - - JSValue result; - globalObject->globalData()->timeoutChecker.start(); - if (handleEventCallType != CallTypeNone) - result = call(exec, handleEventFunction, handleEventCallType, handleEventCallData, m_callback, args); - else - result = call(exec, m_callback, callbackCallType, callbackCallData, m_callback, args); - globalObject->globalData()->timeoutChecker.stop(); - - if (exec->hadException()) { - reportCurrentException(exec); - + + bool raisedException = false; + JSValue result = m_data->invokeCallback(args, &raisedException); + if (raisedException) { // The spec says: // "If the error callback returns false, then move on to the next statement..." // "Otherwise, the error callback did not return false, or there was no error callback" // Therefore an exception and returning true are the same thing - so, return true on an exception return true; } - - Document::updateStyleForAllDocuments(); - return result.toBoolean(exec); } diff --git a/WebCore/bindings/js/JSCustomSQLStatementErrorCallback.h b/WebCore/bindings/js/JSCustomSQLStatementErrorCallback.h index e563393..ac4e45f 100644 --- a/WebCore/bindings/js/JSCustomSQLStatementErrorCallback.h +++ b/WebCore/bindings/js/JSCustomSQLStatementErrorCallback.h @@ -31,32 +31,31 @@ #if ENABLE(DATABASE) +#include "JSDOMGlobalObject.h" #include "SQLStatementErrorCallback.h" - -#include <runtime/JSObject.h> #include <runtime/Protect.h> #include <wtf/Forward.h> -namespace JSC { - class JSObject; -} - namespace WebCore { - -class Frame; + +class JSCallbackData; class SQLError; class JSCustomSQLStatementErrorCallback : public SQLStatementErrorCallback { public: - static PassRefPtr<JSCustomSQLStatementErrorCallback> create(JSC::JSObject* callback, Frame* frame) { return adoptRef(new JSCustomSQLStatementErrorCallback(callback, frame)); } - + static PassRefPtr<JSCustomSQLStatementErrorCallback> create(JSC::JSObject* callback, JSDOMGlobalObject* globalObject) + { + return adoptRef(new JSCustomSQLStatementErrorCallback(callback, globalObject)); + } + + virtual ~JSCustomSQLStatementErrorCallback(); + virtual bool handleEvent(SQLTransaction*, SQLError*); private: - JSCustomSQLStatementErrorCallback(JSC::JSObject* callback, Frame*); + JSCustomSQLStatementErrorCallback(JSC::JSObject* callback, JSDOMGlobalObject*); - JSC::ProtectedPtr<JSC::JSObject> m_callback; - RefPtr<Frame> m_frame; + JSCallbackData* m_data; }; } diff --git a/WebCore/bindings/js/JSCustomSQLTransactionCallback.cpp b/WebCore/bindings/js/JSCustomSQLTransactionCallback.cpp index 3d42f81..456022f 100644 --- a/WebCore/bindings/js/JSCustomSQLTransactionCallback.cpp +++ b/WebCore/bindings/js/JSCustomSQLTransactionCallback.cpp @@ -32,9 +32,11 @@ #if ENABLE(DATABASE) #include "Frame.h" -#include "ScriptController.h" +#include "JSCallbackData.h" +#include "JSDOMGlobalObject.h" #include "JSSQLTransaction.h" #include "Page.h" +#include "ScriptController.h" #include <runtime/JSLock.h> #include <wtf/MainThread.h> #include <wtf/RefCountedLeakCounter.h> @@ -47,39 +49,17 @@ using namespace JSC; static WTF::RefCountedLeakCounter counter("JSCustomSQLTransactionCallback"); #endif -// We have to clean up the data on the main thread for two reasons: -// -// 1) Can't deref a Frame on a non-main thread. -// 2) Unprotecting the JSObject on a non-main thread would register that thread -// for JavaScript garbage collection, which could unnecessarily slow things down. - -class JSCustomSQLTransactionCallback::Data { -public: - Data(JSObject* callback, Frame* frame) : m_callback(callback), m_frame(frame) { } - JSObject* callback() { return m_callback; } - Frame* frame() { return m_frame.get(); } - -private: - ProtectedPtr<JSObject> m_callback; - RefPtr<Frame> m_frame; -}; - -JSCustomSQLTransactionCallback::JSCustomSQLTransactionCallback(JSObject* callback, Frame* frame) - : m_data(new Data(callback, frame)) +JSCustomSQLTransactionCallback::JSCustomSQLTransactionCallback(JSObject* callback, JSDOMGlobalObject* globalObject) + : m_data(new JSCallbackData(callback, globalObject)) { #ifndef NDEBUG counter.increment(); #endif } -void JSCustomSQLTransactionCallback::deleteData(void* context) -{ - delete static_cast<Data*>(context); -} - JSCustomSQLTransactionCallback::~JSCustomSQLTransactionCallback() { - callOnMainThread(deleteData, m_data); + callOnMainThread(JSCallbackData::deleteData, m_data); #ifndef NDEBUG m_data = 0; counter.decrement(); @@ -89,51 +69,14 @@ JSCustomSQLTransactionCallback::~JSCustomSQLTransactionCallback() void JSCustomSQLTransactionCallback::handleEvent(SQLTransaction* transaction, bool& raisedException) { ASSERT(m_data); - ASSERT(m_data->callback()); - ASSERT(m_data->frame()); - if (!m_data->frame()->script()->isEnabled()) - return; - - // FIXME: This is likely the wrong globalObject (for prototype chains at least) - JSGlobalObject* globalObject = m_data->frame()->script()->globalObject(); - ExecState* exec = globalObject->globalExec(); - - JSC::JSLock lock(SilenceAssertionsOnly); - - JSValue handleEventFunction = m_data->callback()->get(exec, Identifier(exec, "handleEvent")); - CallData handleEventCallData; - CallType handleEventCallType = handleEventFunction.getCallData(handleEventCallData); - CallData callbackCallData; - CallType callbackCallType = CallTypeNone; - - if (handleEventCallType == CallTypeNone) { - callbackCallType = m_data->callback()->getCallData(callbackCallData); - if (callbackCallType == CallTypeNone) { - // FIXME: Should an exception be thrown here? - return; - } - } - RefPtr<JSCustomSQLTransactionCallback> protect(this); + JSC::JSLock lock(SilenceAssertionsOnly); + ExecState* exec = m_data->globalObject()->globalExec(); MarkedArgumentBuffer args; args.append(toJS(exec, deprecatedGlobalObjectForPrototype(exec), transaction)); - - globalObject->globalData()->timeoutChecker.start(); - if (handleEventCallType != CallTypeNone) - call(exec, handleEventFunction, handleEventCallType, handleEventCallData, m_data->callback(), args); - else - call(exec, m_data->callback(), callbackCallType, callbackCallData, m_data->callback(), args); - globalObject->globalData()->timeoutChecker.stop(); - - if (exec->hadException()) { - reportCurrentException(exec); - - raisedException = true; - } - - Document::updateStyleForAllDocuments(); + m_data->invokeCallback(args, &raisedException); } } diff --git a/WebCore/bindings/js/JSCustomSQLTransactionCallback.h b/WebCore/bindings/js/JSCustomSQLTransactionCallback.h index 22c367c..f142e59 100644 --- a/WebCore/bindings/js/JSCustomSQLTransactionCallback.h +++ b/WebCore/bindings/js/JSCustomSQLTransactionCallback.h @@ -32,7 +32,6 @@ #if ENABLE(DATABASE) #include "SQLTransactionCallback.h" - #include <wtf/PassRefPtr.h> namespace JSC { @@ -42,22 +41,24 @@ namespace JSC { namespace WebCore { class Frame; +class JSCallbackData; +class JSDOMGlobalObject; class JSCustomSQLTransactionCallback : public SQLTransactionCallback { public: - static PassRefPtr<JSCustomSQLTransactionCallback> create(JSC::JSObject* callback, Frame* frame) { return adoptRef(new JSCustomSQLTransactionCallback(callback, frame)); } + static PassRefPtr<JSCustomSQLTransactionCallback> create(JSC::JSObject* callback, JSDOMGlobalObject* globalObject) + { + return adoptRef(new JSCustomSQLTransactionCallback(callback, globalObject)); + } virtual ~JSCustomSQLTransactionCallback(); virtual void handleEvent(SQLTransaction*, bool& raisedException); private: - JSCustomSQLTransactionCallback(JSC::JSObject* callback, Frame*); - - static void deleteData(void*); + JSCustomSQLTransactionCallback(JSC::JSObject* callback, JSDOMGlobalObject*); - class Data; - Data* m_data; + JSCallbackData* m_data; }; } diff --git a/WebCore/bindings/js/JSCustomSQLTransactionErrorCallback.cpp b/WebCore/bindings/js/JSCustomSQLTransactionErrorCallback.cpp index 2d41bb8..331e014 100644 --- a/WebCore/bindings/js/JSCustomSQLTransactionErrorCallback.cpp +++ b/WebCore/bindings/js/JSCustomSQLTransactionErrorCallback.cpp @@ -32,59 +32,40 @@ #if ENABLE(DATABASE) #include "Frame.h" -#include "ScriptController.h" +#include "JSCallbackData.h" #include "JSSQLError.h" +#include "ScriptController.h" #include <runtime/JSLock.h> +#include <wtf/MainThread.h> namespace WebCore { using namespace JSC; -JSCustomSQLTransactionErrorCallback::JSCustomSQLTransactionErrorCallback(JSObject* callback, Frame* frame) - : m_callback(callback) - , m_frame(frame) +JSCustomSQLTransactionErrorCallback::JSCustomSQLTransactionErrorCallback(JSObject* callback, JSDOMGlobalObject* globalObject) + : m_data(new JSCallbackData(callback, globalObject)) { } - -void JSCustomSQLTransactionErrorCallback::handleEvent(SQLError* error) -{ - ASSERT(m_callback); - ASSERT(m_frame); - - if (!m_frame->script()->isEnabled()) - return; - // FIXME: This is likely the wrong globalObject (for prototype chains at least) - JSGlobalObject* globalObject = m_frame->script()->globalObject(); - ExecState* exec = globalObject->globalExec(); - - JSC::JSLock lock(SilenceAssertionsOnly); +JSCustomSQLTransactionErrorCallback::~JSCustomSQLTransactionErrorCallback() +{ + callOnMainThread(JSCallbackData::deleteData, m_data); +#ifndef NDEBUG + m_data = 0; +#endif +} - JSValue function = m_callback->get(exec, Identifier(exec, "handleEvent")); - CallData callData; - CallType callType = function.getCallData(callData); - if (callType == CallTypeNone) { - callType = m_callback->getCallData(callData); - if (callType == CallTypeNone) { - // FIXME: Should an exception be thrown here? - return; - } - function = m_callback; - } +void JSCustomSQLTransactionErrorCallback::handleEvent(SQLError* error) +{ + ASSERT(m_data); RefPtr<JSCustomSQLTransactionErrorCallback> protect(this); + JSC::JSLock lock(SilenceAssertionsOnly); + ExecState* exec = m_data->globalObject()->globalExec(); MarkedArgumentBuffer args; args.append(toJS(exec, deprecatedGlobalObjectForPrototype(exec), error)); - - globalObject->globalData()->timeoutChecker.start(); - call(exec, function, callType, callData, m_callback, args); - globalObject->globalData()->timeoutChecker.stop(); - - if (exec->hadException()) - reportCurrentException(exec); - - Document::updateStyleForAllDocuments(); + m_data->invokeCallback(args); } } diff --git a/WebCore/bindings/js/JSCustomSQLTransactionErrorCallback.h b/WebCore/bindings/js/JSCustomSQLTransactionErrorCallback.h index be3df29..54bf33b 100644 --- a/WebCore/bindings/js/JSCustomSQLTransactionErrorCallback.h +++ b/WebCore/bindings/js/JSCustomSQLTransactionErrorCallback.h @@ -32,31 +32,30 @@ #if ENABLE(DATABASE) #include "SQLTransactionErrorCallback.h" - -#include <runtime/JSObject.h> +#include "JSDOMGlobalObject.h" #include <runtime/Protect.h> #include <wtf/Forward.h> -namespace JSC { - class JSObject; -} - namespace WebCore { -class Frame; +class JSCallbackData; class SQLError; class JSCustomSQLTransactionErrorCallback : public SQLTransactionErrorCallback { public: - static PassRefPtr<JSCustomSQLTransactionErrorCallback> create(JSC::JSObject* callback, Frame* frame) { return adoptRef(new JSCustomSQLTransactionErrorCallback(callback, frame)); } + static PassRefPtr<JSCustomSQLTransactionErrorCallback> create(JSC::JSObject* callback, JSDOMGlobalObject* globalObject) + { + return adoptRef(new JSCustomSQLTransactionErrorCallback(callback, globalObject)); + } + + virtual ~JSCustomSQLTransactionErrorCallback(); virtual void handleEvent(SQLError*); private: - JSCustomSQLTransactionErrorCallback(JSC::JSObject* callback, Frame*); + JSCustomSQLTransactionErrorCallback(JSC::JSObject* callback, JSDOMGlobalObject* globalObject); - JSC::ProtectedPtr<JSC::JSObject> m_callback; - RefPtr<Frame> m_frame; + JSCallbackData* m_data; }; } diff --git a/WebCore/bindings/js/JSCustomVoidCallback.cpp b/WebCore/bindings/js/JSCustomVoidCallback.cpp index b4e525b..0edd66f 100644 --- a/WebCore/bindings/js/JSCustomVoidCallback.cpp +++ b/WebCore/bindings/js/JSCustomVoidCallback.cpp @@ -30,70 +30,38 @@ #include "JSCustomVoidCallback.h" #include "Frame.h" +#include "JSCallbackData.h" #include "JSDOMWindowCustom.h" #include "ScriptController.h" #include <runtime/JSLock.h> +#include <wtf/MainThread.h> namespace WebCore { using namespace JSC; -JSCustomVoidCallback::JSCustomVoidCallback(JSObject* callback, Frame* frame) - : m_callback(callback) - , m_frame(frame) +JSCustomVoidCallback::JSCustomVoidCallback(JSObject* callback, JSDOMGlobalObject* globalObject) + : m_data(new JSCallbackData(callback, globalObject)) { } + +JSCustomVoidCallback::~JSCustomVoidCallback() +{ + callOnMainThread(JSCallbackData::deleteData, m_data); +#ifndef NDEBUG + m_data = 0; +#endif +} void JSCustomVoidCallback::handleEvent() { - ASSERT(m_callback); - ASSERT(m_frame); - - if (!m_frame->script()->isEnabled()) - return; - - JSGlobalObject* globalObject = m_frame->script()->globalObject(); - ExecState* exec = globalObject->globalExec(); - - JSC::JSLock lock(SilenceAssertionsOnly); - - JSValue function = m_callback->get(exec, Identifier(exec, "handleEvent")); - CallData callData; - CallType callType = function.getCallData(callData); - if (callType == CallTypeNone) { - callType = m_callback->getCallData(callData); - if (callType == CallTypeNone) { - // FIXME: Should an exception be thrown here? - return; - } - function = m_callback; - } - + ASSERT(m_data); + RefPtr<JSCustomVoidCallback> protect(this); + JSC::JSLock lock(SilenceAssertionsOnly); MarkedArgumentBuffer args; - - globalObject->globalData()->timeoutChecker.start(); - call(exec, function, callType, callData, m_callback, args); - globalObject->globalData()->timeoutChecker.stop(); - - if (exec->hadException()) - reportCurrentException(exec); - - Document::updateStyleForAllDocuments(); -} - -PassRefPtr<VoidCallback> toVoidCallback(ExecState* exec, JSValue value) -{ - JSObject* object = value.getObject(); - if (!object) - return 0; - - Frame* frame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame(); - if (!frame) - return 0; - - return JSCustomVoidCallback::create(object, frame); + m_data->invokeCallback(args); } -} +} // namespace WebCore diff --git a/WebCore/bindings/js/JSCustomVoidCallback.h b/WebCore/bindings/js/JSCustomVoidCallback.h index 9cd7c34..4b8d7ea 100644 --- a/WebCore/bindings/js/JSCustomVoidCallback.h +++ b/WebCore/bindings/js/JSCustomVoidCallback.h @@ -29,33 +29,31 @@ #ifndef JSCustomVoidCallback_h #define JSCustomVoidCallback_h +#include "JSDOMGlobalObject.h" #include "VoidCallback.h" - -#include <runtime/JSObject.h> #include <runtime/Protect.h> #include <wtf/Forward.h> namespace WebCore { + +class JSCallbackData; + +class JSCustomVoidCallback : public VoidCallback { +public: + static PassRefPtr<JSCustomVoidCallback> create(JSC::JSObject* callback, JSDOMGlobalObject* globalObject) + { + return adoptRef(new JSCustomVoidCallback(callback, globalObject)); + } - class Frame; + virtual ~JSCustomVoidCallback(); - class JSCustomVoidCallback : public VoidCallback { - public: - static PassRefPtr<JSCustomVoidCallback> create(JSC::JSObject* callback, Frame* frame) - { - return adoptRef(new JSCustomVoidCallback(callback, frame)); - } - - virtual void handleEvent(); - - private: - JSCustomVoidCallback(JSC::JSObject* callback, Frame*); - - JSC::ProtectedPtr<JSC::JSObject> m_callback; - RefPtr<Frame> m_frame; - }; - - PassRefPtr<VoidCallback> toVoidCallback(JSC::ExecState*, JSC::JSValue); + virtual void handleEvent(); + +private: + JSCustomVoidCallback(JSC::JSObject* callback, JSDOMGlobalObject*); + + JSCallbackData* m_data; +}; } // namespace WebCore diff --git a/WebCore/bindings/js/JSCustomXPathNSResolver.cpp b/WebCore/bindings/js/JSCustomXPathNSResolver.cpp index 4476be5..da4a53a 100644 --- a/WebCore/bindings/js/JSCustomXPathNSResolver.cpp +++ b/WebCore/bindings/js/JSCustomXPathNSResolver.cpp @@ -49,13 +49,13 @@ PassRefPtr<JSCustomXPathNSResolver> JSCustomXPathNSResolver::create(JSC::ExecSta setDOMException(exec, TYPE_MISMATCH_ERR); return 0; } - - return adoptRef(new JSCustomXPathNSResolver(resolverObject, asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame())); + + return adoptRef(new JSCustomXPathNSResolver(resolverObject, asJSDOMWindow(exec->dynamicGlobalObject()))); } -JSCustomXPathNSResolver::JSCustomXPathNSResolver(JSObject* customResolver, Frame* frame) +JSCustomXPathNSResolver::JSCustomXPathNSResolver(JSObject* customResolver, JSDOMWindow* globalObject) : m_customResolver(customResolver) - , m_frame(frame) + , m_globalObject(globalObject) { } @@ -67,15 +67,9 @@ String JSCustomXPathNSResolver::lookupNamespaceURI(const String& prefix) { ASSERT(m_customResolver); - if (!m_frame) - return String(); - if (!m_frame->script()->isEnabled()) - return String(); - JSLock lock(SilenceAssertionsOnly); - JSGlobalObject* globalObject = m_frame->script()->globalObject(); - ExecState* exec = globalObject->globalExec(); + ExecState* exec = m_globalObject->globalExec(); JSValue function = m_customResolver->get(exec, Identifier(exec, "lookupNamespaceURI")); CallData callData; @@ -84,7 +78,7 @@ String JSCustomXPathNSResolver::lookupNamespaceURI(const String& prefix) callType = m_customResolver->getCallData(callData); if (callType == CallTypeNone) { // FIXME: Pass actual line number and source URL. - m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "XPathNSResolver does not have a lookupNamespaceURI method.", 0, String()); + m_globalObject->impl()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "XPathNSResolver does not have a lookupNamespaceURI method.", 0, String()); return String(); } function = m_customResolver; @@ -95,9 +89,9 @@ String JSCustomXPathNSResolver::lookupNamespaceURI(const String& prefix) MarkedArgumentBuffer args; args.append(jsString(exec, prefix)); - globalObject->globalData()->timeoutChecker.start(); + m_globalObject->globalData()->timeoutChecker.start(); JSValue retval = call(exec, function, callType, callData, m_customResolver, args); - globalObject->globalData()->timeoutChecker.stop(); + m_globalObject->globalData()->timeoutChecker.stop(); String result; if (exec->hadException()) diff --git a/WebCore/bindings/js/JSCustomXPathNSResolver.h b/WebCore/bindings/js/JSCustomXPathNSResolver.h index 44c44f9..7d66494 100644 --- a/WebCore/bindings/js/JSCustomXPathNSResolver.h +++ b/WebCore/bindings/js/JSCustomXPathNSResolver.h @@ -41,6 +41,7 @@ namespace JSC { namespace WebCore { class Frame; + class JSDOMWindow; class JSCustomXPathNSResolver : public XPathNSResolver { public: @@ -51,10 +52,11 @@ namespace WebCore { virtual String lookupNamespaceURI(const String& prefix); private: - JSCustomXPathNSResolver(JSC::JSObject*, Frame*); + JSCustomXPathNSResolver(JSC::JSObject*, JSDOMWindow*); - JSC::JSObject* m_customResolver; // JSCustomXPathNSResolvers are always temporary, thus no need to GC protect the object. - RefPtr<Frame> m_frame; + // JSCustomXPathNSResolvers are always temporary, thus no need to GC protect the objects. + JSC::JSObject* m_customResolver; + JSDOMWindow* m_globalObject; }; } // namespace WebCore diff --git a/WebCore/bindings/js/JSDOMApplicationCacheCustom.cpp b/WebCore/bindings/js/JSDOMApplicationCacheCustom.cpp index 109308c..49ef5e3 100644 --- a/WebCore/bindings/js/JSDOMApplicationCacheCustom.cpp +++ b/WebCore/bindings/js/JSDOMApplicationCacheCustom.cpp @@ -42,28 +42,6 @@ using namespace JSC; namespace WebCore { -void JSDOMApplicationCache::markChildren(MarkStack& markStack) -{ - Base::markChildren(markStack); - - markIfNotNull(markStack, m_impl->onchecking()); - markIfNotNull(markStack, m_impl->onerror()); - markIfNotNull(markStack, m_impl->onnoupdate()); - markIfNotNull(markStack, m_impl->ondownloading()); - markIfNotNull(markStack, m_impl->onprogress()); - markIfNotNull(markStack, m_impl->onupdateready()); - markIfNotNull(markStack, m_impl->oncached()); - markIfNotNull(markStack, m_impl->onobsolete()); - - typedef DOMApplicationCache::EventListenersMap EventListenersMap; - typedef DOMApplicationCache::ListenerVector ListenerVector; - EventListenersMap& eventListeners = m_impl->eventListeners(); - for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) { - for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter) - (*vecIter)->markJSFunction(markStack); - } -} - #if ENABLE(APPLICATION_CACHE_DYNAMIC_ENTRIES) JSValue JSDOMApplicationCache::hasItem(ExecState* exec, const ArgList& args) @@ -112,10 +90,12 @@ JSValue JSDOMApplicationCache::addEventListener(ExecState* exec, const ArgList& JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext()); if (!globalObject) return jsUndefined(); - RefPtr<JSEventListener> listener = globalObject->findOrCreateJSEventListener(args.at(1)); - if (!listener) + + JSValue listener = args.at(1); + if (!listener.isObject()) return jsUndefined(); - impl()->addEventListener(args.at(0).toString(exec), listener.release(), args.at(2).toBoolean(exec)); + + impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false), args.at(2).toBoolean(exec)); return jsUndefined(); } @@ -124,10 +104,12 @@ JSValue JSDOMApplicationCache::removeEventListener(ExecState* exec, const ArgLis JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext()); if (!globalObject) return jsUndefined(); - JSEventListener* listener = globalObject->findJSEventListener(args.at(1)); - if (!listener) + + JSValue listener = args.at(1); + if (!listener.isObject()) return jsUndefined(); - impl()->removeEventListener(args.at(0).toString(exec), listener, args.at(2).toBoolean(exec)); + + impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec)); return jsUndefined(); } diff --git a/WebCore/bindings/js/JSDOMBinding.cpp b/WebCore/bindings/js/JSDOMBinding.cpp index 566b986..515c088 100644 --- a/WebCore/bindings/js/JSDOMBinding.cpp +++ b/WebCore/bindings/js/JSDOMBinding.cpp @@ -28,6 +28,7 @@ #include "ExceptionCode.h" #include "Frame.h" #include "HTMLAudioElement.h" +#include "HTMLCanvasElement.h" #include "HTMLImageElement.h" #include "HTMLScriptElement.h" #include "HTMLNames.h" @@ -42,6 +43,8 @@ #include "RangeException.h" #include "ScriptController.h" #include "XMLHttpRequestException.h" +#include <runtime/Error.h> +#include <runtime/JSFunction.h> #include <runtime/PrototypeFunction.h> #include <wtf/StdLibExtras.h> @@ -264,18 +267,48 @@ static inline bool isObservableThroughDOM(JSNode* jsNode) Node* node = jsNode->impl(); if (node->inDocument()) { - // 1. If a node is in the document, and its wrapper has custom properties, + // If a node is in the document, and its wrapper has custom properties, // the wrapper is observable because future access to the node through the // DOM must reflect those properties. if (jsNode->hasCustomProperties()) return true; - // 2. If a node is in the document, and has event listeners, its wrapper is + // If a node is in the document, and has event listeners, its wrapper is // observable because its wrapper is responsible for marking those event listeners. - if (node->eventListeners().size()) + if (node->hasEventListeners()) return true; // Technically, we may overzealously mark a wrapper for a node that has only non-JS event listeners. Oh well. + + // If a node owns another object with a wrapper with custom properties, + // the wrapper must be treated as observable, because future access to + // those objects through the DOM must reflect those properties. + // FIXME: It would be better if this logic could be in the node next to + // the custom markChildren functions rather than here. + if (node->isElementNode()) { + if (NamedNodeMap* attributes = static_cast<Element*>(node)->attributeMap()) { + if (DOMObject* wrapper = getCachedDOMObjectWrapper(*jsNode->globalObject()->globalData(), attributes)) { + if (wrapper->hasCustomProperties()) + return true; + } + } + if (node->isStyledElement()) { + if (CSSMutableStyleDeclaration* style = static_cast<StyledElement*>(node)->inlineStyleDecl()) { + if (DOMObject* wrapper = getCachedDOMObjectWrapper(*jsNode->globalObject()->globalData(), style)) { + if (wrapper->hasCustomProperties()) + return true; + } + } + } + if (static_cast<Element*>(node)->hasTagName(canvasTag)) { + if (CanvasRenderingContext* context = static_cast<HTMLCanvasElement*>(node)->renderingContext()) { + if (DOMObject* wrapper = getCachedDOMObjectWrapper(*jsNode->globalObject()->globalData(), context)) { + if (wrapper->hasCustomProperties()) + return true; + } + } + } + } } else { - // 3. If a wrapper is the last reference to an image or script element + // If a wrapper is the last reference to an image or script 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 image element is destroyed, its load event will not fire. @@ -290,6 +323,11 @@ static inline bool isObservableThroughDOM(JSNode* jsNode) #endif } + // If a node is firing event listeners, its wrapper is observable because + // its wrapper is responsible for marking those event listeners. + if (node->isFiringEventListeners()) + return true; + return false; } @@ -348,6 +386,9 @@ void updateDOMNodeDocument(Node* node, Document* oldDocument, Document* newDocum void markDOMObjectWrapper(MarkStack& markStack, JSGlobalData& globalData, void* object) { + // FIXME: This could be changed to only mark wrappers that are "observable" + // as markDOMNodesForDocument does, allowing us to collect more wrappers, + // but doing this correctly would be challenging. if (!object) return; DOMObject* wrapper = getCachedDOMObjectWrapper(globalData, object); @@ -559,7 +600,7 @@ Structure* getCachedDOMStructure(JSDOMGlobalObject* globalObject, const ClassInf return structures.get(classInfo).get(); } -Structure* cacheDOMStructure(JSDOMGlobalObject* globalObject, PassRefPtr<Structure> structure, const ClassInfo* classInfo) +Structure* cacheDOMStructure(JSDOMGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, const ClassInfo* classInfo) { JSDOMStructureMap& structures = globalObject->structures(); ASSERT(!structures.contains(classInfo)); @@ -571,7 +612,7 @@ Structure* getCachedDOMStructure(ExecState* exec, const ClassInfo* classInfo) return getCachedDOMStructure(static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), classInfo); } -Structure* cacheDOMStructure(ExecState* exec, PassRefPtr<Structure> structure, const ClassInfo* classInfo) +Structure* cacheDOMStructure(ExecState* exec, NonNullPassRefPtr<Structure> structure, const ClassInfo* classInfo) { return cacheDOMStructure(static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), structure, classInfo); } @@ -589,4 +630,33 @@ void cacheDOMConstructor(ExecState* exec, const ClassInfo* classInfo, JSObject* constructors.set(classInfo, constructor); } +JSC::JSObject* toJSSequence(ExecState* exec, JSValue value, unsigned& length) +{ + JSObject* object = value.getObject(); + if (!object) { + throwError(exec, TypeError); + return 0; + } + JSValue lengthValue = object->get(exec, exec->propertyNames().length); + if (exec->hadException()) + return 0; + + if (lengthValue.isUndefinedOrNull()) { + throwError(exec, TypeError); + return 0; + } + + length = lengthValue.toUInt32(exec); + if (exec->hadException()) + return 0; + + return object; +} + +bool DOMObject::defineOwnProperty(ExecState* exec, const Identifier&, PropertyDescriptor&, bool) +{ + throwError(exec, TypeError, "defineProperty is not supported on DOM Objects"); + return false; +} + } // namespace WebCore diff --git a/WebCore/bindings/js/JSDOMBinding.h b/WebCore/bindings/js/JSDOMBinding.h index 64cfc3a..9c0ad7e 100644 --- a/WebCore/bindings/js/JSDOMBinding.h +++ b/WebCore/bindings/js/JSDOMBinding.h @@ -26,7 +26,6 @@ #include "Document.h" // For DOMConstructorWithDocument #include <runtime/Completion.h> #include <runtime/Lookup.h> -#include <runtime/JSFunction.h> #include <wtf/Noncopyable.h> namespace JSC { @@ -51,17 +50,19 @@ namespace WebCore { // Base class for all objects in this binding except Window. class DOMObject : public JSC::JSObject { protected: - explicit DOMObject(PassRefPtr<JSC::Structure> structure) + explicit DOMObject(NonNullPassRefPtr<JSC::Structure> structure) : JSObject(structure) { } + virtual bool defineOwnProperty(JSC::ExecState*, const JSC::Identifier&, JSC::PropertyDescriptor&, bool); + #ifndef NDEBUG virtual ~DOMObject(); #endif }; - // FIXME: This class should colapse into DOMObject once all DOMObjects are + // FIXME: This class should collapse into DOMObject once all DOMObjects are // updated to store a globalObject pointer. class DOMObjectWithGlobalPointer : public DOMObject { public: @@ -73,8 +74,13 @@ namespace WebCore { return m_globalObject->scriptExecutionContext(); } + static PassRefPtr<JSC::Structure> createStructure(JSC::JSValue prototype) + { + return JSC::Structure::create(prototype, JSC::TypeInfo(JSC::ObjectType, JSC::HasStandardGetOwnPropertySlot)); + } + protected: - DOMObjectWithGlobalPointer(PassRefPtr<JSC::Structure> structure, JSDOMGlobalObject* globalObject) + DOMObjectWithGlobalPointer(NonNullPassRefPtr<JSC::Structure> structure, JSDOMGlobalObject* globalObject) : DOMObject(structure) , m_globalObject(globalObject) { @@ -83,7 +89,7 @@ namespace WebCore { // needing to reach through the frame to get to the Document*. See bug 27640. // ASSERT(globalObject->scriptExecutionContext()); } - virtual ~DOMObjectWithGlobalPointer() {} + virtual ~DOMObjectWithGlobalPointer() { } void markChildren(JSC::MarkStack& markStack) { @@ -104,7 +110,7 @@ namespace WebCore { } protected: - DOMConstructorObject(PassRefPtr<JSC::Structure> structure, JSDOMGlobalObject* globalObject) + DOMConstructorObject(NonNullPassRefPtr<JSC::Structure> structure, JSDOMGlobalObject* globalObject) : DOMObjectWithGlobalPointer(structure, globalObject) { } @@ -120,7 +126,7 @@ namespace WebCore { } protected: - DOMConstructorWithDocument(PassRefPtr<JSC::Structure> structure, JSDOMGlobalObject* globalObject) + DOMConstructorWithDocument(NonNullPassRefPtr<JSC::Structure> structure, JSDOMGlobalObject* globalObject) : DOMConstructorObject(structure, globalObject) { ASSERT(globalObject->scriptExecutionContext()->isDocument()); @@ -141,9 +147,9 @@ namespace WebCore { void markDOMObjectWrapper(JSC::MarkStack&, JSC::JSGlobalData& globalData, void* object); JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject*, const JSC::ClassInfo*); - JSC::Structure* cacheDOMStructure(JSDOMGlobalObject*, PassRefPtr<JSC::Structure>, const JSC::ClassInfo*); + JSC::Structure* cacheDOMStructure(JSDOMGlobalObject*, NonNullPassRefPtr<JSC::Structure>, const JSC::ClassInfo*); JSC::Structure* getCachedDOMStructure(JSC::ExecState*, const JSC::ClassInfo*); - JSC::Structure* cacheDOMStructure(JSC::ExecState*, PassRefPtr<JSC::Structure>, const JSC::ClassInfo*); + JSC::Structure* cacheDOMStructure(JSC::ExecState*, NonNullPassRefPtr<JSC::Structure>, const JSC::ClassInfo*); JSC::JSObject* getCachedDOMConstructor(JSC::ExecState*, const JSC::ClassInfo*); void cacheDOMConstructor(JSC::ExecState*, const JSC::ClassInfo*, JSC::JSObject* constructor); @@ -277,6 +283,9 @@ namespace WebCore { return toJS(exec, globalObject, ptr.get()); } + // Validates that the passed object is a sequence type per section 4.1.13 of the WebIDL spec. + JSC::JSObject* toJSSequence(JSC::ExecState*, JSC::JSValue, unsigned&); + bool checkNodeSecurity(JSC::ExecState*, Node*); // Helpers for Window, History, and Location classes to implement cross-domain policy. diff --git a/WebCore/bindings/js/JSDOMGlobalObject.cpp b/WebCore/bindings/js/JSDOMGlobalObject.cpp index 68a1db9..372684c 100644 --- a/WebCore/bindings/js/JSDOMGlobalObject.cpp +++ b/WebCore/bindings/js/JSDOMGlobalObject.cpp @@ -40,24 +40,11 @@ using namespace JSC; namespace WebCore { -JSDOMGlobalObject::JSDOMGlobalObjectData::JSDOMGlobalObjectData() - : evt(0) -{ -} - -JSDOMGlobalObject::JSDOMGlobalObject(PassRefPtr<Structure> structure, JSDOMGlobalObject::JSDOMGlobalObjectData* data, JSObject* thisValue) +JSDOMGlobalObject::JSDOMGlobalObject(NonNullPassRefPtr<Structure> structure, JSDOMGlobalObject::JSDOMGlobalObjectData* data, JSObject* thisValue) : JSGlobalObject(structure, data, thisValue) { } -JSDOMGlobalObject::~JSDOMGlobalObject() -{ - JSListenersMap::iterator it = d()->jsEventListeners.begin(); - JSListenersMap::iterator end = d()->jsEventListeners.end(); - for (; it != end; ++it) - it->second->clearGlobalObject(); -} - void JSDOMGlobalObject::markChildren(MarkStack& markStack) { Base::markChildren(markStack); @@ -71,37 +58,12 @@ void JSDOMGlobalObject::markChildren(MarkStack& markStack) markStack.append(it2->second); } -JSEventListener* JSDOMGlobalObject::findJSEventListener(JSValue val) -{ - if (!val.isObject()) - return 0; - - return d()->jsEventListeners.get(asObject(val)); -} - -PassRefPtr<JSEventListener> JSDOMGlobalObject::findOrCreateJSEventListener(JSValue val) -{ - if (JSEventListener* listener = findJSEventListener(val)) - return listener; - - if (!val.isObject()) - return 0; - - // The JSEventListener constructor adds it to our jsEventListeners map. - return JSEventListener::create(asObject(val), this, false).get(); -} - PassRefPtr<JSEventListener> JSDOMGlobalObject::createJSAttributeEventListener(JSValue val) { if (!val.isObject()) return 0; - return JSEventListener::create(asObject(val), this, true).get(); -} - -JSDOMGlobalObject::JSListenersMap& JSDOMGlobalObject::jsEventListeners() -{ - return d()->jsEventListeners; + return JSEventListener::create(asObject(val), true).get(); } void JSDOMGlobalObject::setCurrentEvent(Event* evt) @@ -114,6 +76,11 @@ Event* JSDOMGlobalObject::currentEvent() const return d()->evt; } +void JSDOMGlobalObject::destroyJSDOMGlobalObjectData(void* jsDOMGlobalObjectData) +{ + delete static_cast<JSDOMGlobalObjectData*>(jsDOMGlobalObjectData); +} + JSDOMGlobalObject* toJSDOMGlobalObject(Document* document) { return toJSDOMWindow(document->frame()); diff --git a/WebCore/bindings/js/JSDOMGlobalObject.h b/WebCore/bindings/js/JSDOMGlobalObject.h index 855691c..ce26857 100644 --- a/WebCore/bindings/js/JSDOMGlobalObject.h +++ b/WebCore/bindings/js/JSDOMGlobalObject.h @@ -45,8 +45,7 @@ namespace WebCore { protected: struct JSDOMGlobalObjectData; - JSDOMGlobalObject(PassRefPtr<JSC::Structure>, JSDOMGlobalObjectData*, JSC::JSObject* thisValue); - virtual ~JSDOMGlobalObject(); + JSDOMGlobalObject(NonNullPassRefPtr<JSC::Structure>, JSDOMGlobalObjectData*, JSC::JSObject* thisValue); public: JSDOMStructureMap& structures() { return d()->structures; } @@ -54,20 +53,10 @@ namespace WebCore { virtual ScriptExecutionContext* scriptExecutionContext() const = 0; - // Finds a wrapper of a GC-unprotected JS EventListener, returns 0 if no existing one. - JSEventListener* findJSEventListener(JSC::JSValue); - - // Finds or creates a wrapper of a JS EventListener. JS EventListener object is *NOT* GC-protected. - PassRefPtr<JSEventListener> findOrCreateJSEventListener(JSC::JSValue); - - // Creates a GC-protected JS EventListener for an "onXXX" event attribute. - // These listeners cannot be removed through the removeEventListener API. + // Creates a JS EventListener for an "onXXX" event attribute. These + // listeners cannot be removed through the removeEventListener API. PassRefPtr<JSEventListener> createJSAttributeEventListener(JSC::JSValue); - typedef HashMap<JSC::JSObject*, JSEventListener*> JSListenersMap; - - JSListenersMap& jsEventListeners(); - // Make binding code generation easier. JSDOMGlobalObject* globalObject() { return this; } @@ -78,17 +67,27 @@ namespace WebCore { protected: struct JSDOMGlobalObjectData : public JSC::JSGlobalObject::JSGlobalObjectData { - JSDOMGlobalObjectData(); + JSDOMGlobalObjectData() + : JSGlobalObjectData(destroyJSDOMGlobalObjectData) + , evt(0) + { + } + + JSDOMGlobalObjectData(Destructor destructor) + : JSGlobalObjectData(destructor) + , evt(0) + { + } JSDOMStructureMap structures; JSDOMConstructorMap constructors; - JSDOMGlobalObject::JSListenersMap jsEventListeners; - Event* evt; }; private: + static void destroyJSDOMGlobalObjectData(void*); + JSDOMGlobalObjectData* d() const { return static_cast<JSDOMGlobalObjectData*>(JSC::JSVariableObject::d); } }; diff --git a/WebCore/bindings/js/JSDOMWindowBase.cpp b/WebCore/bindings/js/JSDOMWindowBase.cpp index df6068a..a04ef89 100644 --- a/WebCore/bindings/js/JSDOMWindowBase.cpp +++ b/WebCore/bindings/js/JSDOMWindowBase.cpp @@ -42,13 +42,7 @@ namespace WebCore { const ClassInfo JSDOMWindowBase::s_info = { "Window", 0, 0, 0 }; -JSDOMWindowBase::JSDOMWindowBaseData::JSDOMWindowBaseData(PassRefPtr<DOMWindow> window, JSDOMWindowShell* shell) - : impl(window) - , shell(shell) -{ -} - -JSDOMWindowBase::JSDOMWindowBase(PassRefPtr<Structure> structure, PassRefPtr<DOMWindow> window, JSDOMWindowShell* shell) +JSDOMWindowBase::JSDOMWindowBase(NonNullPassRefPtr<Structure> structure, PassRefPtr<DOMWindow> window, JSDOMWindowShell* shell) : JSDOMGlobalObject(structure, new JSDOMWindowBaseData(window, shell), shell) { GlobalPropertyInfo staticGlobals[] = { @@ -113,7 +107,7 @@ ExecState* JSDOMWindowBase::globalExec() bool JSDOMWindowBase::supportsProfiling() const { -#if !ENABLE(JAVASCRIPT_DEBUGGER) +#if !ENABLE(JAVASCRIPT_DEBUGGER) || !ENABLE(INSPECTOR) return false; #else Frame* frame = impl()->frame(); @@ -167,11 +161,19 @@ JSGlobalData* JSDOMWindowBase::commonJSGlobalData() if (!globalData) { globalData = JSGlobalData::createLeaked().releaseRef(); globalData->timeoutChecker.setTimeoutInterval(10000); // 10 seconds +#ifndef NDEBUG + globalData->mainThreadOnly = true; +#endif } return globalData; } +void JSDOMWindowBase::destroyJSDOMWindowBaseData(void* jsDOMWindowBaseData) +{ + delete static_cast<JSDOMWindowBaseData*>(jsDOMWindowBaseData); +} + // JSDOMGlobalObject* is ignored, accesing a window in any context will // use that DOMWindow's prototype chain. JSValue toJS(ExecState* exec, JSDOMGlobalObject*, DOMWindow* domWindow) diff --git a/WebCore/bindings/js/JSDOMWindowBase.h b/WebCore/bindings/js/JSDOMWindowBase.h index 84cc81f..52c3c1d 100644 --- a/WebCore/bindings/js/JSDOMWindowBase.h +++ b/WebCore/bindings/js/JSDOMWindowBase.h @@ -43,7 +43,7 @@ namespace WebCore { class JSDOMWindowBase : public JSDOMGlobalObject { typedef JSDOMGlobalObject Base; protected: - JSDOMWindowBase(PassRefPtr<JSC::Structure>, PassRefPtr<DOMWindow>, JSDOMWindowShell*); + JSDOMWindowBase(NonNullPassRefPtr<JSC::Structure>, PassRefPtr<DOMWindow>, JSDOMWindowShell*); public: void updateDocument(); @@ -76,7 +76,12 @@ namespace WebCore { private: struct JSDOMWindowBaseData : public JSDOMGlobalObjectData { - JSDOMWindowBaseData(PassRefPtr<DOMWindow>, JSDOMWindowShell*); + JSDOMWindowBaseData(PassRefPtr<DOMWindow> window, JSDOMWindowShell* shell) + : JSDOMGlobalObjectData(destroyJSDOMWindowBaseData) + , impl(window) + , shell(shell) + { + } RefPtr<DOMWindow> impl; JSDOMWindowShell* shell; @@ -85,6 +90,8 @@ namespace WebCore { bool allowsAccessFromPrivate(const JSC::JSGlobalObject*) const; String crossDomainAccessErrorMessage(const JSC::JSGlobalObject*) const; + static void destroyJSDOMWindowBaseData(void*); + JSDOMWindowBaseData* d() const { return static_cast<JSDOMWindowBaseData*>(JSC::JSVariableObject::d); } }; diff --git a/WebCore/bindings/js/JSDOMWindowCustom.cpp b/WebCore/bindings/js/JSDOMWindowCustom.cpp index 9798972..47339d4 100644 --- a/WebCore/bindings/js/JSDOMWindowCustom.cpp +++ b/WebCore/bindings/js/JSDOMWindowCustom.cpp @@ -38,29 +38,53 @@ #include "JSDOMWindowShell.h" #include "JSEvent.h" #include "JSEventListener.h" +#include "JSEventSourceConstructor.h" #include "JSHTMLCollection.h" #include "JSHistory.h" #include "JSImageConstructor.h" #include "JSLocation.h" #include "JSMessageChannelConstructor.h" #include "JSMessagePort.h" +#include "JSMessagePortCustom.h" #include "JSOptionConstructor.h" + +#if ENABLE(SHARED_WORKERS) #include "JSSharedWorkerConstructor.h" +#endif + +#if ENABLE(3D_CANVAS) +#include "JSCanvasArrayBufferConstructor.h" +#include "JSCanvasByteArrayConstructor.h" +#include "JSCanvasUnsignedByteArrayConstructor.h" +#include "JSCanvasIntArrayConstructor.h" +#include "JSCanvasUnsignedIntArrayConstructor.h" +#include "JSCanvasShortArrayConstructor.h" +#include "JSCanvasUnsignedShortArrayConstructor.h" +#include "JSCanvasFloatArrayConstructor.h" +#endif #include "JSWebKitCSSMatrixConstructor.h" #include "JSWebKitPointConstructor.h" +#if ENABLE(WEB_SOCKETS) +#include "JSWebSocketConstructor.h" +#endif #include "JSWorkerConstructor.h" #include "JSXMLHttpRequestConstructor.h" #include "JSXSLTProcessorConstructor.h" #include "Location.h" #include "MediaPlayer.h" #include "MessagePort.h" +#include "NotificationCenter.h" #include "Page.h" #include "PlatformScreen.h" #include "RegisteredEventListener.h" #include "ScheduledAction.h" #include "ScriptController.h" +#include "SerializedScriptValue.h" #include "Settings.h" +#include "SharedWorkerRepository.h" #include "WindowFeatures.h" +#include <runtime/Error.h> +#include <runtime/JSFunction.h> #include <runtime/JSObject.h> #include <runtime/PrototypeFunction.h> @@ -72,7 +96,7 @@ void JSDOMWindow::markChildren(MarkStack& markStack) { Base::markChildren(markStack); - markEventListeners(markStack, impl()->eventListeners()); + impl()->markEventListeners(markStack); JSGlobalData& globalData = *Heap::heap(this)->globalData(); @@ -271,6 +295,150 @@ bool JSDOMWindow::getOwnPropertySlot(ExecState* exec, const Identifier& property return Base::getOwnPropertySlot(exec, propertyName, slot); } +bool JSDOMWindow::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + // When accessing a Window cross-domain, functions are always the native built-in ones, and they + // are not affected by properties changed on the Window or anything in its prototype chain. + // This is consistent with the behavior of Firefox. + + const HashEntry* entry; + + // We don't want any properties other than "close" and "closed" on a closed window. + if (!impl()->frame()) { + // The following code is safe for cross-domain and same domain use. + // It ignores any custom properties that might be set on the DOMWindow (including a custom prototype). + entry = s_info.propHashTable(exec)->entry(exec, propertyName); + if (entry && !(entry->attributes() & Function) && entry->propertyGetter() == jsDOMWindowClosed) { + descriptor.setDescriptor(jsBoolean(true), ReadOnly | DontDelete | DontEnum); + return true; + } + entry = JSDOMWindowPrototype::s_info.propHashTable(exec)->entry(exec, propertyName); + if (entry && (entry->attributes() & Function) && entry->function() == jsDOMWindowPrototypeFunctionClose) { + PropertySlot slot; + slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>); + descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum); + return true; + } + descriptor.setUndefined(); + return true; + } + + String errorMessage; + bool allowsAccess = allowsAccessFrom(exec, errorMessage); + if (allowsAccess && JSGlobalObject::getOwnPropertyDescriptor(exec, propertyName, descriptor)) + return true; + + // We need this code here because otherwise JSDOMWindowBase will stop the search before we even get to the + // prototype due to the blanket same origin (allowsAccessFrom) check at the end of getOwnPropertySlot. + // Also, it's important to get the implementation straight out of the DOMWindow prototype regardless of + // what prototype is actually set on this object. + entry = JSDOMWindowPrototype::s_info.propHashTable(exec)->entry(exec, propertyName); + if (entry) { + if (entry->attributes() & Function) { + if (entry->function() == jsDOMWindowPrototypeFunctionBlur) { + if (!allowsAccess) { + PropertySlot slot; + slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionBlur, 0>); + descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum); + return true; + } + } else if (entry->function() == jsDOMWindowPrototypeFunctionClose) { + if (!allowsAccess) { + PropertySlot slot; + slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>); + descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum); + return true; + } + } else if (entry->function() == jsDOMWindowPrototypeFunctionFocus) { + if (!allowsAccess) { + PropertySlot slot; + slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionFocus, 0>); + descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum); + return true; + } + } else if (entry->function() == jsDOMWindowPrototypeFunctionPostMessage) { + if (!allowsAccess) { + PropertySlot slot; + slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionPostMessage, 2>); + descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum); + return true; + } + } else if (entry->function() == jsDOMWindowPrototypeFunctionShowModalDialog) { + if (!DOMWindow::canShowModalDialog(impl()->frame())) { + descriptor.setUndefined(); + return true; + } + } + } + } else { + // Allow access to toString() cross-domain, but always Object.prototype.toString. + if (propertyName == exec->propertyNames().toString) { + if (!allowsAccess) { + PropertySlot slot; + slot.setCustom(this, objectToStringFunctionGetter); + descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum); + return true; + } + } + } + + entry = JSDOMWindow::s_info.propHashTable(exec)->entry(exec, propertyName); + if (entry) { + PropertySlot slot; + slot.setCustom(this, entry->propertyGetter()); + descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes()); + return true; + } + + // Check for child frames by name before built-in properties to + // match Mozilla. This does not match IE, but some sites end up + // naming frames things that conflict with window properties that + // are in Moz but not IE. Since we have some of these, we have to do + // it the Moz way. + if (impl()->frame()->tree()->child(propertyName)) { + PropertySlot slot; + slot.setCustom(this, childFrameGetter); + descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum); + return true; + } + + // Do prototype lookup early so that functions and attributes in the prototype can have + // precedence over the index and name getters. + JSValue proto = prototype(); + if (proto.isObject()) { + if (asObject(proto)->getPropertyDescriptor(exec, propertyName, descriptor)) { + if (!allowsAccess) { + printErrorMessage(errorMessage); + descriptor.setUndefined(); + } + return true; + } + } + + bool ok; + unsigned i = propertyName.toArrayIndex(&ok); + if (ok && i < impl()->frame()->tree()->childCount()) { + PropertySlot slot; + slot.setCustomIndex(this, i, indexGetter); + descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum); + return true; + } + + // Allow shortcuts like 'Image1' instead of document.images.Image1 + Document* document = impl()->frame()->document(); + if (document->isHTMLDocument()) { + AtomicStringImpl* atomicPropertyName = AtomicString::find(propertyName); + if (atomicPropertyName && (static_cast<HTMLDocument*>(document)->hasNamedItem(atomicPropertyName) || document->hasElementWithId(atomicPropertyName))) { + PropertySlot slot; + slot.setCustom(this, namedItemGetter); + descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum); + return true; + } + } + + return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor); +} + void JSDOMWindow::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { if (!impl()->frame()) @@ -306,6 +474,14 @@ void JSDOMWindow::getPropertyNames(ExecState* exec, PropertyNameArray& propertyN Base::getPropertyNames(exec, propertyNames); } +void JSDOMWindow::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +{ + // Only allow the window to enumerated by frames in the same origin. + if (!allowsAccessFrom(exec)) + return; + Base::getOwnPropertyNames(exec, propertyNames); +} + bool JSDOMWindow::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const { // Only allow getting property attributes properties by frames in the same origin. @@ -314,7 +490,7 @@ bool JSDOMWindow::getPropertyAttributes(ExecState* exec, const Identifier& prope return Base::getPropertyAttributes(exec, propertyName, attributes); } -void JSDOMWindow::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction) +void JSDOMWindow::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes) { // Only allow defining getters by frames in the same origin. if (!allowsAccessFrom(exec)) @@ -324,15 +500,23 @@ void JSDOMWindow::defineGetter(ExecState* exec, const Identifier& propertyName, if (propertyName == "location") return; - Base::defineGetter(exec, propertyName, getterFunction); + Base::defineGetter(exec, propertyName, getterFunction, attributes); } -void JSDOMWindow::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction) +void JSDOMWindow::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes) { // Only allow defining setters by frames in the same origin. if (!allowsAccessFrom(exec)) return; - Base::defineSetter(exec, propertyName, setterFunction); + Base::defineSetter(exec, propertyName, setterFunction, attributes); +} + +bool JSDOMWindow::defineOwnProperty(JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::PropertyDescriptor& descriptor, bool shouldThrow) +{ + // Only allow defining properties in this way by frames in the same origin, as it allows setters to be introduced. + if (!allowsAccessFrom(exec)) + return false; + return Base::defineOwnProperty(exec, propertyName, descriptor, shouldThrow); } JSValue JSDOMWindow::lookupGetter(ExecState* exec, const Identifier& propertyName) @@ -398,16 +582,16 @@ void JSDOMWindow::setLocation(ExecState* exec, JSValue value) Frame* frame = impl()->frame(); ASSERT(frame); - if (!shouldAllowNavigation(exec, frame)) - return; - KURL url = completeURL(exec, value.toString(exec)); if (url.isNull()) return; + if (!shouldAllowNavigation(exec, frame)) + return; + if (!protocolIsJavaScript(url) || allowsAccessFrom(exec)) { // We want a new history item if this JS was called via a user gesture - frame->loader()->scheduleLocationChange(url, lexicalFrame->loader()->outgoingReferrer(), !lexicalFrame->script()->anyPageIsProcessingUserGesture(), false, processingUserGesture(exec)); + frame->redirectScheduler()->scheduleLocationChange(url, lexicalFrame->loader()->outgoingReferrer(), !lexicalFrame->script()->anyPageIsProcessingUserGesture(), false, processingUserGesture(exec)); } } @@ -424,6 +608,13 @@ JSValue JSDOMWindow::event(ExecState* exec) const return toJS(exec, event); } +#if ENABLE(EVENTSOURCE) +JSValue JSDOMWindow::eventSource(ExecState* exec) const +{ + return getDOMConstructor<JSEventSourceConstructor>(exec, this); +} +#endif + JSValue JSDOMWindow::image(ExecState* exec) const { return getDOMConstructor<JSImageConstructor>(exec, this); @@ -453,6 +644,48 @@ JSValue JSDOMWindow::webKitCSSMatrix(ExecState* exec) const return getDOMConstructor<JSWebKitCSSMatrixConstructor>(exec, this); } +#if ENABLE(3D_CANVAS) +JSValue JSDOMWindow::canvasArrayBuffer(ExecState* exec) const +{ + return getDOMConstructor<JSCanvasArrayBufferConstructor>(exec, this); +} + +JSValue JSDOMWindow::canvasByteArray(ExecState* exec) const +{ + return getDOMConstructor<JSCanvasByteArrayConstructor>(exec, this); +} + +JSValue JSDOMWindow::canvasUnsignedByteArray(ExecState* exec) const +{ + return getDOMConstructor<JSCanvasUnsignedByteArrayConstructor>(exec, this); +} + +JSValue JSDOMWindow::canvasIntArray(ExecState* exec) const +{ + return getDOMConstructor<JSCanvasIntArrayConstructor>(exec, this); +} + +JSValue JSDOMWindow::canvasUnsignedIntArray(ExecState* exec) const +{ + return getDOMConstructor<JSCanvasUnsignedIntArrayConstructor>(exec, this); +} + +JSValue JSDOMWindow::canvasShortArray(ExecState* exec) const +{ + return getDOMConstructor<JSCanvasShortArrayConstructor>(exec, this); +} + +JSValue JSDOMWindow::canvasUnsignedShortArray(ExecState* exec) const +{ + return getDOMConstructor<JSCanvasUnsignedShortArrayConstructor>(exec, this); +} + +JSValue JSDOMWindow::canvasFloatArray(ExecState* exec) const +{ + return getDOMConstructor<JSCanvasFloatArrayConstructor>(exec, this); +} +#endif + JSValue JSDOMWindow::xmlHttpRequest(ExecState* exec) const { return getDOMConstructor<JSXMLHttpRequestConstructor>(exec, this); @@ -482,7 +715,24 @@ JSValue JSDOMWindow::worker(ExecState* exec) const #if ENABLE(SHARED_WORKERS) JSValue JSDOMWindow::sharedWorker(ExecState* exec) const { - return getDOMConstructor<JSSharedWorkerConstructor>(exec, this); + if (SharedWorkerRepository::isAvailable()) + return getDOMConstructor<JSSharedWorkerConstructor>(exec, this); + return jsUndefined(); +} +#endif + +#if ENABLE(WEB_SOCKETS) +JSValue JSDOMWindow::webSocket(ExecState* exec) const +{ + Frame* frame = impl()->frame(); + if (!frame) + return jsUndefined(); + Settings* settings = frame->settings(); + if (!settings) + return jsUndefined(); + if (!settings->experimentalWebSocketsEnabled()) + return jsUndefined(); + return getDOMConstructor<JSWebSocketConstructor>(exec, this); } #endif @@ -521,7 +771,7 @@ static Frame* createWindow(ExecState* exec, Frame* lexicalFrame, Frame* dynamicF return 0; newFrame->loader()->setOpener(openerFrame); - newFrame->loader()->setOpenedByDOM(); + newFrame->page()->setOpenedByDOM(); JSDOMWindow* newWindow = toJSDOMWindow(newFrame); @@ -529,13 +779,13 @@ static Frame* createWindow(ExecState* exec, Frame* lexicalFrame, Frame* dynamicF newWindow->putDirect(Identifier(exec, "dialogArguments"), dialogArgs); if (!protocolIsJavaScript(url) || newWindow->allowsAccessFrom(exec)) { - KURL completedURL = url.isEmpty() ? KURL("") : completeURL(exec, url); + KURL completedURL = url.isEmpty() ? KURL(ParsedURLString, "") : completeURL(exec, url); bool userGesture = processingUserGesture(exec); if (created) newFrame->loader()->changeLocation(completedURL, referrer, false, false, userGesture); else if (!url.isEmpty()) - newFrame->loader()->scheduleLocationChange(completedURL.string(), referrer, !lexicalFrame->script()->anyPageIsProcessingUserGesture(), false, userGesture); + newFrame->redirectScheduler()->scheduleLocationChange(completedURL.string(), referrer, !lexicalFrame->script()->anyPageIsProcessingUserGesture(), false, userGesture); } return newFrame; @@ -543,6 +793,10 @@ static Frame* createWindow(ExecState* exec, Frame* lexicalFrame, Frame* dynamicF JSValue JSDOMWindow::open(ExecState* exec, const ArgList& args) { + String urlString = valueToStringWithUndefinedOrNullCheck(exec, args.at(0)); + AtomicString frameName = args.at(1).isUndefinedOrNull() ? "_blank" : AtomicString(args.at(1).toString(exec)); + WindowFeatures windowFeatures(valueToStringWithUndefinedOrNullCheck(exec, args.at(2))); + Frame* frame = impl()->frame(); if (!frame) return jsUndefined(); @@ -555,9 +809,6 @@ JSValue JSDOMWindow::open(ExecState* exec, const ArgList& args) Page* page = frame->page(); - String urlString = valueToStringWithUndefinedOrNullCheck(exec, args.at(0)); - AtomicString frameName = args.at(1).isUndefinedOrNull() ? "_blank" : AtomicString(args.at(1).toString(exec)); - // Because FrameTree::find() returns true for empty strings, we must check for empty framenames. // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker. if (!DOMWindow::allowPopUp(dynamicFrame) && (frameName.isEmpty() || !frame->tree()->find(frameName))) @@ -575,13 +826,13 @@ JSValue JSDOMWindow::open(ExecState* exec, const ArgList& args) topOrParent = true; } if (topOrParent) { - if (!shouldAllowNavigation(exec, frame)) - return jsUndefined(); - String completedURL; if (!urlString.isEmpty()) completedURL = completeURL(exec, urlString).string(); + if (!shouldAllowNavigation(exec, frame)) + return jsUndefined(); + const JSDOMWindow* targetedWindow = toJSDOMWindow(frame); if (!completedURL.isEmpty() && (!protocolIsJavaScript(completedURL) || (targetedWindow && targetedWindow->allowsAccessFrom(exec)))) { bool userGesture = processingUserGesture(exec); @@ -591,13 +842,12 @@ JSValue JSDOMWindow::open(ExecState* exec, const ArgList& args) // here. String referrer = dynamicFrame->loader()->outgoingReferrer(); - frame->loader()->scheduleLocationChange(completedURL, referrer, !lexicalFrame->script()->anyPageIsProcessingUserGesture(), false, userGesture); + frame->redirectScheduler()->scheduleLocationChange(completedURL, referrer, !lexicalFrame->script()->anyPageIsProcessingUserGesture(), false, userGesture); } return toJS(exec, frame->domWindow()); } // In the case of a named frame or a new window, we'll use the createWindow() helper - WindowFeatures windowFeatures(valueToStringWithUndefinedOrNullCheck(exec, args.at(2))); FloatRect windowRect(windowFeatures.xSet ? windowFeatures.x : 0, windowFeatures.ySet ? windowFeatures.y : 0, windowFeatures.widthSet ? windowFeatures.width : 0, windowFeatures.heightSet ? windowFeatures.height : 0); DOMWindow::adjustWindowRect(screenAvailableRect(page ? page->mainFrame()->view() : 0), windowRect, windowRect); @@ -617,6 +867,10 @@ JSValue JSDOMWindow::open(ExecState* exec, const ArgList& args) JSValue JSDOMWindow::showModalDialog(ExecState* exec, const ArgList& args) { + String url = valueToStringWithUndefinedOrNullCheck(exec, args.at(0)); + JSValue dialogArgs = args.at(1); + String featureArgs = valueToStringWithUndefinedOrNullCheck(exec, args.at(2)); + Frame* frame = impl()->frame(); if (!frame) return jsUndefined(); @@ -630,10 +884,6 @@ JSValue JSDOMWindow::showModalDialog(ExecState* exec, const ArgList& args) if (!DOMWindow::canShowModalDialogNow(frame) || !DOMWindow::allowPopUp(dynamicFrame)) return jsUndefined(); - String url = valueToStringWithUndefinedOrNullCheck(exec, args.at(0)); - JSValue dialogArgs = args.at(1); - String featureArgs = valueToStringWithUndefinedOrNullCheck(exec, args.at(2)); - HashMap<String, String> features; DOMWindow::parseModalDialogFeatures(featureArgs, features); @@ -687,7 +937,15 @@ JSValue JSDOMWindow::showModalDialog(ExecState* exec, const ArgList& args) JSDOMWindow* dialogWindow = toJSDOMWindow(dialogFrame); dialogFrame->page()->chrome()->runModal(); - return dialogWindow->getDirect(Identifier(exec, "returnValue")); + Identifier returnValue(exec, "returnValue"); + if (dialogWindow->allowsAccessFromNoErrorMessage(exec)) { + PropertySlot slot; + // This is safe, we have already performed the origin security check and we are + // not interested in any of the DOM properties of the window. + if (dialogWindow->JSGlobalObject::getOwnPropertySlot(exec, returnValue, slot)) + return slot.getValue(exec, returnValue); + } + return jsUndefined(); } JSValue JSDOMWindow::postMessage(ExecState* exec, const ArgList& args) @@ -695,19 +953,23 @@ JSValue JSDOMWindow::postMessage(ExecState* exec, const ArgList& args) DOMWindow* window = impl(); DOMWindow* source = asJSDOMWindow(exec->lexicalGlobalObject())->impl(); - String message = args.at(0).toString(exec); + PassRefPtr<SerializedScriptValue> message = SerializedScriptValue::create(exec, args.at(0)); if (exec->hadException()) return jsUndefined(); - MessagePort* messagePort = (args.size() == 2) ? 0 : toMessagePort(args.at(1)); + MessagePortArray messagePorts; + if (args.size() > 2) + fillMessagePortArray(exec, args.at(1), messagePorts); + if (exec->hadException()) + return jsUndefined(); String targetOrigin = valueToStringWithUndefinedOrNullCheck(exec, args.at((args.size() == 2) ? 1 : 2)); if (exec->hadException()) return jsUndefined(); ExceptionCode ec = 0; - window->postMessage(message, messagePort, targetOrigin, source, ec); + window->postMessage(message, &messagePorts, targetOrigin, source, ec); setDOMException(exec, ec); return jsUndefined(); @@ -788,9 +1050,11 @@ JSValue JSDOMWindow::addEventListener(ExecState* exec, const ArgList& args) if (!frame) return jsUndefined(); - if (RefPtr<JSEventListener> listener = findOrCreateJSEventListener(args.at(1))) - impl()->addEventListener(AtomicString(args.at(0).toString(exec)), listener.release(), args.at(2).toBoolean(exec)); + JSValue listener = args.at(1); + if (!listener.isObject()) + return jsUndefined(); + impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false), args.at(2).toBoolean(exec)); return jsUndefined(); } @@ -800,9 +1064,11 @@ JSValue JSDOMWindow::removeEventListener(ExecState* exec, const ArgList& args) if (!frame) return jsUndefined(); - if (JSEventListener* listener = findJSEventListener(args.at(1))) - impl()->removeEventListener(AtomicString(args.at(0).toString(exec)), listener, args.at(2).toBoolean(exec)); + JSValue listener = args.at(1); + if (!listener.isObject()) + return jsUndefined(); + impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec)); return jsUndefined(); } diff --git a/WebCore/bindings/js/JSDOMWindowShell.cpp b/WebCore/bindings/js/JSDOMWindowShell.cpp index efffd42..3c3ff4c 100644 --- a/WebCore/bindings/js/JSDOMWindowShell.cpp +++ b/WebCore/bindings/js/JSDOMWindowShell.cpp @@ -88,6 +88,11 @@ bool JSDOMWindowShell::getOwnPropertySlot(ExecState* exec, const Identifier& pro return m_window->getOwnPropertySlot(exec, propertyName, slot); } +bool JSDOMWindowShell::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + return m_window->getOwnPropertyDescriptor(exec, propertyName, descriptor); +} + void JSDOMWindowShell::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { m_window->put(exec, propertyName, value, slot); @@ -98,6 +103,11 @@ void JSDOMWindowShell::putWithAttributes(ExecState* exec, const Identifier& prop m_window->putWithAttributes(exec, propertyName, value, attributes); } +bool JSDOMWindowShell::defineOwnProperty(JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::PropertyDescriptor& descriptor, bool shouldThrow) +{ + return m_window->defineOwnProperty(exec, propertyName, descriptor, shouldThrow); +} + bool JSDOMWindowShell::deleteProperty(ExecState* exec, const Identifier& propertyName) { return m_window->deleteProperty(exec, propertyName); @@ -108,19 +118,24 @@ void JSDOMWindowShell::getPropertyNames(ExecState* exec, PropertyNameArray& prop m_window->getPropertyNames(exec, propertyNames); } +void JSDOMWindowShell::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +{ + m_window->getOwnPropertyNames(exec, propertyNames); +} + bool JSDOMWindowShell::getPropertyAttributes(JSC::ExecState* exec, const Identifier& propertyName, unsigned& attributes) const { return m_window->getPropertyAttributes(exec, propertyName, attributes); } -void JSDOMWindowShell::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction) +void JSDOMWindowShell::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes) { - m_window->defineGetter(exec, propertyName, getterFunction); + m_window->defineGetter(exec, propertyName, getterFunction, attributes); } -void JSDOMWindowShell::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction) +void JSDOMWindowShell::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes) { - m_window->defineSetter(exec, propertyName, setterFunction); + m_window->defineSetter(exec, propertyName, setterFunction, attributes); } JSValue JSDOMWindowShell::lookupGetter(ExecState* exec, const Identifier& propertyName) diff --git a/WebCore/bindings/js/JSDOMWindowShell.h b/WebCore/bindings/js/JSDOMWindowShell.h index 0506283..23af340 100644 --- a/WebCore/bindings/js/JSDOMWindowShell.h +++ b/WebCore/bindings/js/JSDOMWindowShell.h @@ -67,13 +67,16 @@ namespace WebCore { virtual void markChildren(JSC::MarkStack&); virtual JSC::UString className() const; virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&); + virtual bool getOwnPropertyDescriptor(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertyDescriptor&); virtual void put(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&); virtual void putWithAttributes(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue, unsigned attributes); virtual bool deleteProperty(JSC::ExecState*, const JSC::Identifier& propertyName); virtual void getPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&); + virtual void getOwnPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&); virtual bool getPropertyAttributes(JSC::ExecState*, const JSC::Identifier& propertyName, unsigned& attributes) const; - virtual void defineGetter(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* getterFunction); - virtual void defineSetter(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* setterFunction); + virtual void defineGetter(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* getterFunction, unsigned attributes); + virtual void defineSetter(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* setterFunction, unsigned attributes); + virtual bool defineOwnProperty(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertyDescriptor&, bool shouldThrow); virtual JSC::JSValue lookupGetter(JSC::ExecState*, const JSC::Identifier& propertyName); virtual JSC::JSValue lookupSetter(JSC::ExecState*, const JSC::Identifier& propertyName); virtual JSC::JSObject* unwrappedObject(); diff --git a/WebCore/bindings/js/JSDatabaseCustom.cpp b/WebCore/bindings/js/JSDatabaseCustom.cpp index af3b066..0932cca 100644 --- a/WebCore/bindings/js/JSDatabaseCustom.cpp +++ b/WebCore/bindings/js/JSDatabaseCustom.cpp @@ -52,17 +52,13 @@ JSValue JSDatabase::changeVersion(ExecState* exec, const ArgList& args) String oldVersion = args.at(0).toString(exec); String newVersion = args.at(1).toString(exec); - Frame* frame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame(); - if (!frame) - return jsUndefined(); - JSObject* object; if (!(object = args.at(2).getObject())) { setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } - RefPtr<SQLTransactionCallback> callback(JSCustomSQLTransactionCallback::create(object, frame)); + RefPtr<SQLTransactionCallback> callback(JSCustomSQLTransactionCallback::create(object, static_cast<JSDOMGlobalObject*>(exec->dynamicGlobalObject()))); RefPtr<SQLTransactionErrorCallback> errorCallback; if (!args.at(3).isNull()) { @@ -71,24 +67,25 @@ JSValue JSDatabase::changeVersion(ExecState* exec, const ArgList& args) return jsUndefined(); } - errorCallback = JSCustomSQLTransactionErrorCallback::create(object, frame); + errorCallback = JSCustomSQLTransactionErrorCallback::create(object, static_cast<JSDOMGlobalObject*>(exec->dynamicGlobalObject())); } RefPtr<VoidCallback> successCallback; if (!args.at(4).isNull()) { - successCallback = toVoidCallback(exec, args.at(4)); - if (!successCallback) { + if (!(object = args.at(4).getObject())) { setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } + + successCallback = JSCustomVoidCallback::create(object, static_cast<JSDOMGlobalObject*>(exec->dynamicGlobalObject())); } - + m_impl->changeVersion(oldVersion, newVersion, callback.release(), errorCallback.release(), successCallback.release()); return jsUndefined(); } -JSValue JSDatabase::transaction(ExecState* exec, const ArgList& args) +static JSValue createTransaction(ExecState* exec, const ArgList& args, Database* database, JSDOMGlobalObject* globalObject, bool readOnly) { JSObject* object; @@ -96,12 +93,8 @@ JSValue JSDatabase::transaction(ExecState* exec, const ArgList& args) setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } - - Frame* frame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame(); - if (!frame) - return jsUndefined(); - - RefPtr<SQLTransactionCallback> callback(JSCustomSQLTransactionCallback::create(object, frame)); + + RefPtr<SQLTransactionCallback> callback(JSCustomSQLTransactionCallback::create(object, globalObject)); RefPtr<SQLTransactionErrorCallback> errorCallback; if (args.size() > 1 && !args.at(1).isNull()) { @@ -110,22 +103,33 @@ JSValue JSDatabase::transaction(ExecState* exec, const ArgList& args) return jsUndefined(); } - errorCallback = JSCustomSQLTransactionErrorCallback::create(object, frame); + errorCallback = JSCustomSQLTransactionErrorCallback::create(object, globalObject); } RefPtr<VoidCallback> successCallback; if (args.size() > 2 && !args.at(2).isNull()) { - successCallback = toVoidCallback(exec, args.at(2)); - if (!successCallback) { + if (!(object = args.at(2).getObject())) { setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } + + successCallback = JSCustomVoidCallback::create(object, globalObject); } - m_impl->transaction(callback.release(), errorCallback.release(), successCallback.release()); - + database->transaction(callback.release(), errorCallback.release(), successCallback.release(), readOnly); return jsUndefined(); } + +JSValue JSDatabase::transaction(ExecState* exec, const ArgList& args) +{ + return createTransaction(exec, args, m_impl.get(), static_cast<JSDOMGlobalObject*>(exec->dynamicGlobalObject()), false); +} +JSValue JSDatabase::readTransaction(ExecState* exec, const ArgList& args) +{ + return createTransaction(exec, args, m_impl.get(), static_cast<JSDOMGlobalObject*>(exec->dynamicGlobalObject()), true); +} + } + #endif // ENABLE(DATABASE) diff --git a/WebCore/bindings/js/JSDedicatedWorkerContextCustom.cpp b/WebCore/bindings/js/JSDedicatedWorkerContextCustom.cpp index 657f9b3..fbee5ef 100644 --- a/WebCore/bindings/js/JSDedicatedWorkerContextCustom.cpp +++ b/WebCore/bindings/js/JSDedicatedWorkerContextCustom.cpp @@ -35,15 +35,16 @@ #include "JSDedicatedWorkerContext.h" +#include "JSDOMBinding.h" +#include "JSMessagePortCustom.h" + using namespace JSC; namespace WebCore { -void JSDedicatedWorkerContext::markChildren(MarkStack& markStack) +JSC::JSValue JSDedicatedWorkerContext::postMessage(JSC::ExecState* exec, const JSC::ArgList& args) { - Base::markChildren(markStack); - - markIfNotNull(markStack, impl()->onmessage()); + return handlePostMessage(exec, args, impl()); } } // namespace WebCore diff --git a/WebCore/bindings/js/JSDesktopNotificationsCustom.cpp b/WebCore/bindings/js/JSDesktopNotificationsCustom.cpp new file mode 100644 index 0000000..493d7bd --- /dev/null +++ b/WebCore/bindings/js/JSDesktopNotificationsCustom.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(NOTIFICATIONS) + +#include "Document.h" +#include "JSCustomVoidCallback.h" +#include "JSEventListener.h" +#include "JSNotification.h" +#include "JSNotificationCenter.h" +#include "Notification.h" +#include "NotificationCenter.h" +#include <runtime/Error.h> + +using namespace JSC; + +namespace WebCore { + +JSValue JSNotificationCenter::requestPermission(ExecState* exec, const ArgList& args) +{ + // Permission request is only valid from page context. + ScriptExecutionContext* context = impl()->context(); + if (context->isWorkerContext()) + return throwError(exec, SyntaxError); + + if (!args.at(0).isObject()) + return throwError(exec, TypeError); + + PassRefPtr<JSCustomVoidCallback> callback = JSCustomVoidCallback::create(args.at(0).getObject(), static_cast<Document*>(context)->frame()); + + impl()->requestPermission(callback); + return jsUndefined(); +} + +JSValue JSNotification::addEventListener(ExecState* exec, const ArgList& args) +{ + JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext()); + if (!globalObject) + return jsUndefined(); + + JSValue listener = args.at(1); + if (!listener.isObject()) + return jsUndefined(); + + impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener)), globalObject, false), args.at(2).toBoolean(exec)); + return jsUndefined(); +} + +JSValue JSNotification::removeEventListener(ExecState* exec, const ArgList& args) +{ + JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext()); + if (!globalObject) + return jsUndefined(); + + JSValue listener = args.at(1); + if (!listener.isObject()) + return jsUndefined(); + + impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), globalObject, false).get(), args.at(2).toBoolean(exec)); + return jsUndefined(); +} + + +} // namespace + +#endif // ENABLE(NOTIFICATIONS) diff --git a/WebCore/bindings/js/JSDocumentCustom.cpp b/WebCore/bindings/js/JSDocumentCustom.cpp index 39a1fc5..d7f8725 100644 --- a/WebCore/bindings/js/JSDocumentCustom.cpp +++ b/WebCore/bindings/js/JSDocumentCustom.cpp @@ -24,6 +24,10 @@ #include "Frame.h" #include "FrameLoader.h" #include "HTMLDocument.h" +#include "JSCanvasRenderingContext2D.h" +#if ENABLE(3D_CANVAS) +#include "JSCanvasRenderingContext3D.h" +#endif #include "JSDOMWindowCustom.h" #include "JSHTMLDocument.h" #include "JSLocation.h" @@ -35,6 +39,8 @@ #include "SVGDocument.h" #endif +#include <wtf/GetPtr.h> + using namespace JSC; namespace WebCore { @@ -42,8 +48,14 @@ namespace WebCore { void JSDocument::markChildren(MarkStack& markStack) { JSNode::markChildren(markStack); - markDOMNodesForDocument(markStack, impl()); - markActiveObjectsForContext(markStack, *Heap::heap(this)->globalData(), impl()); + + Document* document = impl(); + JSGlobalData& globalData = *Heap::heap(this)->globalData(); + + markDOMNodesForDocument(markStack, document); + markActiveObjectsForContext(markStack, globalData, document); + markDOMObjectWrapper(markStack, globalData, document->implementation()); + markDOMObjectWrapper(markStack, globalData, document->styleSheets()); } JSValue JSDocument::location(ExecState* exec) const @@ -76,7 +88,7 @@ void JSDocument::setLocation(ExecState* exec, JSValue value) str = activeFrame->document()->completeURL(str).string(); bool userGesture = activeFrame->script()->processingUserGesture(); - frame->loader()->scheduleLocationChange(str, activeFrame->loader()->outgoingReferrer(), !activeFrame->script()->anyPageIsProcessingUserGesture(), false, userGesture); + frame->redirectScheduler()->scheduleLocationChange(str, activeFrame->loader()->outgoingReferrer(), !activeFrame->script()->anyPageIsProcessingUserGesture(), false, userGesture); } JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, Document* document) diff --git a/WebCore/bindings/js/JSElementCustom.cpp b/WebCore/bindings/js/JSElementCustom.cpp index 47793d0..fb64ff2 100644 --- a/WebCore/bindings/js/JSElementCustom.cpp +++ b/WebCore/bindings/js/JSElementCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -51,15 +51,27 @@ namespace WebCore { using namespace HTMLNames; +void JSElement::markChildren(MarkStack& markStack) +{ + Base::markChildren(markStack); + + Element* element = impl(); + JSGlobalData& globalData = *Heap::heap(this)->globalData(); + + markDOMObjectWrapper(markStack, globalData, element->attributeMap()); + if (element->isStyledElement()) + markDOMObjectWrapper(markStack, globalData, static_cast<StyledElement*>(element)->inlineStyleDecl()); +} + static inline bool allowSettingSrcToJavascriptURL(ExecState* exec, Element* element, const String& name, const String& value) { if ((element->hasTagName(iframeTag) || element->hasTagName(frameTag)) && equalIgnoringCase(name, "src") && protocolIsJavaScript(deprecatedParseURL(value))) { - HTMLFrameElementBase* frame = static_cast<HTMLFrameElementBase*>(element); - if (!checkNodeSecurity(exec, frame->contentDocument())) + Document* contentDocument = static_cast<HTMLFrameElementBase*>(element)->contentDocument(); + if (contentDocument && !checkNodeSecurity(exec, contentDocument)) return false; } return true; -} +} JSValue JSElement::setAttribute(ExecState* exec, const ArgList& args) { diff --git a/WebCore/bindings/js/JSEventCustom.cpp b/WebCore/bindings/js/JSEventCustom.cpp index 804c529..c64ddc9 100644 --- a/WebCore/bindings/js/JSEventCustom.cpp +++ b/WebCore/bindings/js/JSEventCustom.cpp @@ -38,6 +38,7 @@ #include "JSMouseEvent.h" #include "JSMutationEvent.h" #include "JSOverflowEvent.h" +#include "JSPageTransitionEvent.h" #include "JSProgressEvent.h" #include "JSTextEvent.h" #include "JSUIEvent.h" @@ -51,6 +52,7 @@ #include "MouseEvent.h" #include "MutationEvent.h" #include "OverflowEvent.h" +#include "PageTransitionEvent.h" #include "ProgressEvent.h" #include "TextEvent.h" #include "UIEvent.h" @@ -120,6 +122,8 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, Event* event) wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, OverflowEvent, event); else if (event->isMessageEvent()) wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, MessageEvent, event); + else if (event->isPageTransitionEvent()) + wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, PageTransitionEvent, event); else if (event->isProgressEvent()) { if (event->isXMLHttpRequestProgressEvent()) wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, XMLHttpRequestProgressEvent, event); diff --git a/WebCore/bindings/js/JSEventListener.cpp b/WebCore/bindings/js/JSEventListener.cpp index 42e0281..4f273fe 100644 --- a/WebCore/bindings/js/JSEventListener.cpp +++ b/WebCore/bindings/js/JSEventListener.cpp @@ -31,22 +31,18 @@ using namespace JSC; namespace WebCore { -JSEventListener::JSEventListener(JSObject* function, JSDOMGlobalObject* globalObject, bool isAttribute) - : m_jsFunction(function) - , m_globalObject(globalObject) +JSEventListener::JSEventListener(JSObject* function, bool isAttribute) + : EventListener(JSEventListenerType) + , m_jsFunction(function) , m_isAttribute(isAttribute) { - if (!m_isAttribute && m_jsFunction) - globalObject->jsEventListeners().set(m_jsFunction, this); } JSEventListener::~JSEventListener() { - if (!m_isAttribute && m_jsFunction && m_globalObject) - m_globalObject->jsEventListeners().remove(m_jsFunction); } -JSObject* JSEventListener::jsFunction() const +JSObject* JSEventListener::jsFunction(ScriptExecutionContext*) const { return m_jsFunction; } @@ -55,30 +51,24 @@ void JSEventListener::markJSFunction(MarkStack& markStack) { if (m_jsFunction) markStack.append(m_jsFunction); - if (m_globalObject) - markStack.append(m_globalObject); } -void JSEventListener::handleEvent(Event* event, bool isWindowEvent) +void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) { + ASSERT(scriptExecutionContext); + if (!scriptExecutionContext) + return; + JSLock lock(SilenceAssertionsOnly); - JSObject* jsFunction = this->jsFunction(); + JSObject* jsFunction = this->jsFunction(scriptExecutionContext); if (!jsFunction) return; - JSDOMGlobalObject* globalObject = m_globalObject; - // Null check as clearGlobalObject() can clear this and we still get called back by - // xmlhttprequest objects. See http://bugs.webkit.org/show_bug.cgi?id=13275 - // FIXME: Is this check still necessary? Requests are supposed to be stopped before clearGlobalObject() is called. - ASSERT(globalObject); + JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext); if (!globalObject) return; - ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext(); - if (!scriptExecutionContext) - return; - if (scriptExecutionContext->isDocument()) { JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); Frame* frame = window->impl()->frame(); @@ -113,26 +103,14 @@ void JSEventListener::handleEvent(Event* event, bool isWindowEvent) Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); - // If this event handler is the first JavaScript to execute, then the - // dynamic global object should be set to the global object of the - // window in which the event occurred. JSGlobalData* globalData = globalObject->globalData(); DynamicGlobalObjectScope globalObjectScope(exec, globalData->dynamicGlobalObject ? globalData->dynamicGlobalObject : globalObject); - JSValue retval; - if (handleEventFunction) { - globalObject->globalData()->timeoutChecker.start(); - retval = call(exec, handleEventFunction, callType, callData, jsFunction, args); - } else { - JSValue thisValue; - if (isWindowEvent) - thisValue = globalObject->toThisObject(exec); - else - thisValue = toJS(exec, globalObject, event->currentTarget()); - globalObject->globalData()->timeoutChecker.start(); - retval = call(exec, jsFunction, callType, callData, thisValue, args); - } - globalObject->globalData()->timeoutChecker.stop(); + globalData->timeoutChecker.start(); + JSValue retval = handleEventFunction + ? call(exec, handleEventFunction, callType, callData, jsFunction, args) + : call(exec, jsFunction, callType, callData, toJS(exec, globalObject, event->currentTarget()), args); + globalData->timeoutChecker.stop(); globalObject->setCurrentEvent(savedEvent); @@ -154,18 +132,15 @@ void JSEventListener::handleEvent(Event* event, bool isWindowEvent) } } -bool JSEventListener::reportError(const String& message, const String& url, int lineNumber) +bool JSEventListener::reportError(ScriptExecutionContext* context, const String& message, const String& url, int lineNumber) { JSLock lock(SilenceAssertionsOnly); - JSObject* jsFunction = this->jsFunction(); + JSObject* jsFunction = this->jsFunction(context); if (!jsFunction) return false; - JSDOMGlobalObject* globalObject = m_globalObject; - if (!globalObject) - return false; - + JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(context); ExecState* exec = globalObject->globalExec(); CallData callData; @@ -179,17 +154,14 @@ bool JSEventListener::reportError(const String& message, const String& url, int args.append(jsString(exec, url)); args.append(jsNumber(exec, lineNumber)); - // If this event handler is the first JavaScript to execute, then the - // dynamic global object should be set to the global object of the - // window in which the event occurred. JSGlobalData* globalData = globalObject->globalData(); DynamicGlobalObjectScope globalObjectScope(exec, globalData->dynamicGlobalObject ? globalData->dynamicGlobalObject : globalObject); JSValue thisValue = globalObject->toThisObject(exec); - globalObject->globalData()->timeoutChecker.start(); + globalData->timeoutChecker.start(); JSValue returnValue = call(exec, jsFunction, callType, callData, thisValue, args); - globalObject->globalData()->timeoutChecker.stop(); + globalData->timeoutChecker.stop(); // If an error occurs while handling the script error, it should be bubbled up. if (exec->hadException()) { @@ -206,4 +178,11 @@ bool JSEventListener::virtualisAttribute() const return m_isAttribute; } +bool JSEventListener::operator==(const EventListener& listener) +{ + if (const JSEventListener* jsEventListener = JSEventListener::cast(&listener)) + return m_jsFunction == jsEventListener->m_jsFunction && m_isAttribute == jsEventListener->m_isAttribute; + return false; +} + } // namespace WebCore diff --git a/WebCore/bindings/js/JSEventListener.h b/WebCore/bindings/js/JSEventListener.h index 7929169..285a9c4 100644 --- a/WebCore/bindings/js/JSEventListener.h +++ b/WebCore/bindings/js/JSEventListener.h @@ -30,30 +30,38 @@ namespace WebCore { class JSEventListener : public EventListener { public: - static PassRefPtr<JSEventListener> create(JSC::JSObject* listener, JSDOMGlobalObject* globalObject, bool isAttribute) + static PassRefPtr<JSEventListener> create(JSC::JSObject* listener, bool isAttribute) { - return adoptRef(new JSEventListener(listener, globalObject, isAttribute)); + return adoptRef(new JSEventListener(listener, isAttribute)); } + + static const JSEventListener* cast(const EventListener* listener) + { + return listener->type() == JSEventListenerType + ? static_cast<const JSEventListener*>(listener) + : 0; + } + virtual ~JSEventListener(); - void clearGlobalObject() { m_globalObject = 0; } + + virtual bool operator==(const EventListener& other); // Returns true if this event listener was created for an event handler attribute, like "onload" or "onclick". bool isAttribute() const { return m_isAttribute; } - virtual JSC::JSObject* jsFunction() const; + virtual JSC::JSObject* jsFunction(ScriptExecutionContext*) const; private: virtual void markJSFunction(JSC::MarkStack&); - virtual void handleEvent(Event*, bool isWindowEvent); - virtual bool reportError(const String& message, const String& url, int lineNumber); + virtual void handleEvent(ScriptExecutionContext*, Event*); + virtual bool reportError(ScriptExecutionContext*, const String& message, const String& url, int lineNumber); virtual bool virtualisAttribute() const; void clearJSFunctionInline(); protected: - JSEventListener(JSC::JSObject* function, JSDOMGlobalObject*, bool isAttribute); + JSEventListener(JSC::JSObject* function, bool isAttribute); mutable JSC::JSObject* m_jsFunction; - JSDOMGlobalObject* m_globalObject; bool m_isAttribute; }; diff --git a/WebCore/bindings/js/JSEventSourceConstructor.cpp b/WebCore/bindings/js/JSEventSourceConstructor.cpp new file mode 100644 index 0000000..c6e4825 --- /dev/null +++ b/WebCore/bindings/js/JSEventSourceConstructor.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2009 Ericsson AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(EVENTSOURCE) + +#include "JSEventSourceConstructor.h" + +#include "EventSource.h" +#include "ExceptionCode.h" +#include "JSEventSource.h" +#include "ScriptExecutionContext.h" +#include <runtime/Error.h> + +using namespace JSC; + +namespace WebCore { + +ASSERT_CLASS_FITS_IN_CELL(JSEventSourceConstructor); + +const ClassInfo JSEventSourceConstructor::s_info = { "EventSourceContructor", 0, 0, 0 }; + +JSEventSourceConstructor::JSEventSourceConstructor(ExecState* exec, JSDOMGlobalObject* globalObject) + : DOMConstructorObject(JSEventSourceConstructor::createStructure(globalObject->objectPrototype()), globalObject) +{ + putDirect(exec->propertyNames().prototype, JSEventSourcePrototype::self(exec, globalObject), None); + putDirect(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly|DontDelete|DontEnum); +} + +static JSObject* constructEventSource(ExecState* exec, JSObject* constructor, const ArgList& args) +{ + if (args.size() < 1) + return throwError(exec, SyntaxError, "Not enough arguments"); + + UString url = args.at(0).toString(exec); + if (exec->hadException()) + return 0; + + JSEventSourceConstructor* jsConstructor = static_cast<JSEventSourceConstructor*>(constructor); + ScriptExecutionContext* context = jsConstructor->scriptExecutionContext(); + if (!context) + return throwError(exec, ReferenceError, "EventSource constructor associated document is unavailable"); + + ExceptionCode ec = 0; + RefPtr<EventSource> eventSource = EventSource::create(url, context, ec); + if (ec) { + setDOMException(exec, ec); + return 0; + } + + return asObject(toJS(exec, jsConstructor->globalObject(), eventSource.release())); +} + +ConstructType JSEventSourceConstructor::getConstructData(ConstructData& constructData) +{ + constructData.native.function = constructEventSource; + return ConstructTypeHost; +} + +} // namespace WebCore + +#endif // ENABLE(EVENTSOURCE) diff --git a/WebCore/bindings/js/JSEventSourceConstructor.h b/WebCore/bindings/js/JSEventSourceConstructor.h new file mode 100644 index 0000000..b2f3cb5 --- /dev/null +++ b/WebCore/bindings/js/JSEventSourceConstructor.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2009 Ericsson AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSEventSourceConstructor_h +#define JSEventSourceConstructor_h + +#if ENABLE(EVENTSOURCE) + +#include "JSDOMBinding.h" + +namespace WebCore { + + class JSEventSourceConstructor : public DOMConstructorObject { + public: + JSEventSourceConstructor(JSC::ExecState*, JSDOMGlobalObject*); + static const JSC::ClassInfo s_info; + + private: + virtual JSC::ConstructType getConstructData(JSC::ConstructData&); + virtual const JSC::ClassInfo* classInfo() const { return &s_info; } + }; + +} // namespace WebCore + +#endif // ENABLE(EVENTSOURCE) + +#endif // JSEventSourceConstructor_h diff --git a/WebCore/bindings/js/JSEventSourceCustom.cpp b/WebCore/bindings/js/JSEventSourceCustom.cpp new file mode 100644 index 0000000..404bf11 --- /dev/null +++ b/WebCore/bindings/js/JSEventSourceCustom.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2009 Ericsson AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(EVENTSOURCE) + +#include "JSEventSource.h" + +#include "EventSource.h" +#include "JSDOMGlobalObject.h" +#include "JSEventListener.h" + +using namespace JSC; + +namespace WebCore { + +JSValue JSEventSource::addEventListener(ExecState* exec, const ArgList& args) +{ + JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext()); + if (!globalObject) + return jsUndefined(); + + JSValue listener = args.at(1); + if (!listener.isObject()) + return jsUndefined(); + + impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec)); + return jsUndefined(); +} + +JSValue JSEventSource::removeEventListener(ExecState* exec, const ArgList& args) +{ + JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext()); + if (!globalObject) + return jsUndefined(); + + JSValue listener = args.at(1); + if (!listener.isObject()) + return jsUndefined(); + + impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec)); + return jsUndefined(); +} + +} // namespace WebCore + +#endif // ENABLE(EVENTSOURCE) diff --git a/WebCore/bindings/js/JSEventTarget.cpp b/WebCore/bindings/js/JSEventTarget.cpp index c34e10e..0421d10 100644 --- a/WebCore/bindings/js/JSEventTarget.cpp +++ b/WebCore/bindings/js/JSEventTarget.cpp @@ -33,16 +33,29 @@ #include "JSEventListener.h" #include "JSMessagePort.h" #include "JSNode.h" +#if ENABLE(SHARED_WORKERS) + #include "JSSharedWorker.h" #include "JSSharedWorkerContext.h" +#endif + #include "JSXMLHttpRequest.h" #include "JSXMLHttpRequestUpload.h" #include "MessagePort.h" + +#if ENABLE(SHARED_WORKERS) #include "SharedWorker.h" #include "SharedWorkerContext.h" +#endif + #include "XMLHttpRequest.h" #include "XMLHttpRequestUpload.h" +#if ENABLE(EVENTSOURCE) +#include "EventSource.h" +#include "JSEventSource.h" +#endif + #if ENABLE(OFFLINE_WEB_APPLICATIONS) #include "DOMApplicationCache.h" #include "JSDOMApplicationCache.h" @@ -60,6 +73,16 @@ #include "Worker.h" #endif +#if ENABLE(NOTIFICATIONS) +#include "JSNotification.h" +#include "Notification.h" +#endif + +#if ENABLE(WEB_SOCKETS) +#include "JSWebSocket.h" +#include "WebSocket.h" +#endif + using namespace JSC; namespace WebCore { @@ -69,6 +92,11 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, EventTarget* targ if (!target) return jsNull(); +#if ENABLE(EVENTSOURCE) + if (EventSource* eventSource = target->toEventSource()) + return toJS(exec, globalObject, eventSource); +#endif + #if ENABLE(SVG) // SVGElementInstance supports both toSVGElementInstance and toNode since so much mouse handling code depends on toNode returning a valid node. if (SVGElementInstance* instance = target->toSVGElementInstance()) @@ -111,6 +139,16 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, EventTarget* targ return toJSDOMGlobalObject(workerContext); #endif +#if ENABLE(NOTIFICATIONS) + if (Notification* notification = target->toNotification()) + return toJS(exec, notification); +#endif + +#if ENABLE(WEB_SOCKETS) + if (WebSocket* webSocket = target->toWebSocket()) + return toJS(exec, webSocket); +#endif + ASSERT_NOT_REACHED(); return jsNull(); } @@ -118,7 +156,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, EventTarget* targ EventTarget* toEventTarget(JSC::JSValue value) { #define CONVERT_TO_EVENT_TARGET(type) \ - if (value.isObject(&JS##type::s_info)) \ + if (value.inherits(&JS##type::s_info)) \ return static_cast<JS##type*>(asObject(value))->impl(); CONVERT_TO_EVENT_TARGET(Node) @@ -126,9 +164,13 @@ EventTarget* toEventTarget(JSC::JSValue value) CONVERT_TO_EVENT_TARGET(XMLHttpRequestUpload) CONVERT_TO_EVENT_TARGET(MessagePort) - if (value.isObject(&JSDOMWindowShell::s_info)) + if (value.inherits(&JSDOMWindowShell::s_info)) return static_cast<JSDOMWindowShell*>(asObject(value))->impl(); +#if ENABLE(EVENTSOURCE) + CONVERT_TO_EVENT_TARGET(EventSource) +#endif + #if ENABLE(OFFLINE_WEB_APPLICATIONS) CONVERT_TO_EVENT_TARGET(DOMApplicationCache) #endif @@ -147,6 +189,14 @@ EventTarget* toEventTarget(JSC::JSValue value) CONVERT_TO_EVENT_TARGET(SharedWorkerContext) #endif +#if ENABLE(NOTIFICATIONS) + CONVERT_TO_EVENT_TARGET(Notification) +#endif + +#if ENABLE(WEB_SOCKETS) + CONVERT_TO_EVENT_TARGET(WebSocket) +#endif + return 0; } diff --git a/WebCore/bindings/js/JSGeolocationCustom.cpp b/WebCore/bindings/js/JSGeolocationCustom.cpp index 8ef8601..530b89b 100644 --- a/WebCore/bindings/js/JSGeolocationCustom.cpp +++ b/WebCore/bindings/js/JSGeolocationCustom.cpp @@ -34,40 +34,39 @@ #include "JSCustomPositionErrorCallback.h" #include "JSDOMWindow.h" #include "PositionOptions.h" +#include <runtime/InternalFunction.h> using namespace JSC; using namespace std; namespace WebCore { -static PassRefPtr<PositionCallback> createPositionCallback(ExecState* exec, JSValue value) +static PassRefPtr<PositionCallback> createPositionCallback(ExecState* exec, JSDOMGlobalObject* globalObject, JSValue value) { // The spec specifies 'FunctionOnly' for this object. - if (!value.isObject(&InternalFunction::info)) { + if (!value.inherits(&InternalFunction::info)) { setDOMException(exec, TYPE_MISMATCH_ERR); return 0; } JSObject* object = asObject(value); - Frame* frame = toJSDOMWindow(exec->lexicalGlobalObject())->impl()->frame(); - return JSCustomPositionCallback::create(object, frame); + return JSCustomPositionCallback::create(object, globalObject); } -static PassRefPtr<PositionErrorCallback> createPositionErrorCallback(ExecState* exec, JSValue value) +static PassRefPtr<PositionErrorCallback> createPositionErrorCallback(ExecState* exec, JSDOMGlobalObject* globalObject, JSValue value) { // Argument is optional (hence undefined is allowed), and null is allowed. if (value.isUndefinedOrNull()) return 0; // The spec specifies 'FunctionOnly' for this object. - if (!value.isObject(&InternalFunction::info)) { + if (!value.inherits(&InternalFunction::info)) { setDOMException(exec, TYPE_MISMATCH_ERR); return 0; } JSObject* object = asObject(value); - Frame* frame = toJSDOMWindow(exec->lexicalGlobalObject())->impl()->frame(); - return JSCustomPositionErrorCallback::create(object, frame); + return JSCustomPositionErrorCallback::create(object, globalObject); } static PassRefPtr<PositionOptions> createPositionOptions(ExecState* exec, JSValue value) @@ -91,7 +90,7 @@ static PassRefPtr<PositionOptions> createPositionOptions(ExecState* exec, JSValu JSValue enableHighAccuracyValue = object->get(exec, Identifier(exec, "enableHighAccuracy")); if (exec->hadException()) return 0; - if(!enableHighAccuracyValue.isUndefined()) { + if (!enableHighAccuracyValue.isUndefined()) { options->setEnableHighAccuracy(enableHighAccuracyValue.toBoolean(exec)); if (exec->hadException()) return 0; @@ -104,8 +103,8 @@ static PassRefPtr<PositionOptions> createPositionOptions(ExecState* exec, JSValu double timeoutNumber = timeoutValue.toNumber(exec); if (exec->hadException()) return 0; - // If the value is infinity, there's nothing to do. - if (timeoutNumber != Inf) { + // If the value is positive infinity, there's nothing to do. + if (!(isinf(timeoutNumber) && (timeoutNumber > 0))) { // Wrap to int32 and force non-negative to match behavior of window.setTimeout. options->setTimeout(max(0, timeoutValue.toInt32(exec))); if (exec->hadException()) @@ -120,8 +119,8 @@ static PassRefPtr<PositionOptions> createPositionOptions(ExecState* exec, JSValu double maximumAgeNumber = maximumAgeValue.toNumber(exec); if (exec->hadException()) return 0; - if (maximumAgeNumber == Inf) { - // If the value is infinity, clear maximumAge. + if (isinf(maximumAgeNumber) && (maximumAgeNumber > 0)) { + // If the value is positive infinity, clear maximumAge. options->clearMaximumAge(); } else { // Wrap to int32 and force non-negative to match behavior of window.setTimeout. @@ -138,12 +137,12 @@ JSValue JSGeolocation::getCurrentPosition(ExecState* exec, const ArgList& args) { // Arguments: PositionCallback, (optional)PositionErrorCallback, (optional)PositionOptions - RefPtr<PositionCallback> positionCallback = createPositionCallback(exec, args.at(0)); + RefPtr<PositionCallback> positionCallback = createPositionCallback(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), args.at(0)); if (exec->hadException()) return jsUndefined(); ASSERT(positionCallback); - RefPtr<PositionErrorCallback> positionErrorCallback = createPositionErrorCallback(exec, args.at(1)); + RefPtr<PositionErrorCallback> positionErrorCallback = createPositionErrorCallback(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), args.at(1)); if (exec->hadException()) return jsUndefined(); @@ -160,12 +159,12 @@ JSValue JSGeolocation::watchPosition(ExecState* exec, const ArgList& args) { // Arguments: PositionCallback, (optional)PositionErrorCallback, (optional)PositionOptions - RefPtr<PositionCallback> positionCallback = createPositionCallback(exec, args.at(0)); + RefPtr<PositionCallback> positionCallback = createPositionCallback(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), args.at(0)); if (exec->hadException()) return jsUndefined(); ASSERT(positionCallback); - RefPtr<PositionErrorCallback> positionErrorCallback = createPositionErrorCallback(exec, args.at(1)); + RefPtr<PositionErrorCallback> positionErrorCallback = createPositionErrorCallback(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), args.at(1)); if (exec->hadException()) return jsUndefined(); diff --git a/WebCore/bindings/js/JSHTMLAllCollection.h b/WebCore/bindings/js/JSHTMLAllCollection.h index 7363e5c..e6fe7f5 100644 --- a/WebCore/bindings/js/JSHTMLAllCollection.h +++ b/WebCore/bindings/js/JSHTMLAllCollection.h @@ -35,7 +35,7 @@ namespace WebCore { class JSHTMLAllCollection : public JSHTMLCollection { public: - JSHTMLAllCollection(PassRefPtr<JSC::Structure> structure, JSDOMGlobalObject* globalObject, PassRefPtr<HTMLCollection> collection) + JSHTMLAllCollection(NonNullPassRefPtr<JSC::Structure> structure, JSDOMGlobalObject* globalObject, PassRefPtr<HTMLCollection> collection) : JSHTMLCollection(structure, globalObject, collection) { } diff --git a/WebCore/bindings/js/JSHTMLAppletElementCustom.cpp b/WebCore/bindings/js/JSHTMLAppletElementCustom.cpp index 37561af..30892e0 100644 --- a/WebCore/bindings/js/JSHTMLAppletElementCustom.cpp +++ b/WebCore/bindings/js/JSHTMLAppletElementCustom.cpp @@ -38,6 +38,11 @@ bool JSHTMLAppletElement::getOwnPropertySlotDelegate(ExecState* exec, const Iden return runtimeObjectCustomGetOwnPropertySlot(exec, propertyName, slot, this); } +bool JSHTMLAppletElement::getOwnPropertyDescriptorDelegate(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + return runtimeObjectCustomGetOwnPropertyDescriptor(exec, propertyName, descriptor, this); +} + bool JSHTMLAppletElement::putDelegate(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { return runtimeObjectCustomPut(exec, propertyName, value, impl(), slot); diff --git a/WebCore/bindings/js/JSHTMLCanvasElementCustom.cpp b/WebCore/bindings/js/JSHTMLCanvasElementCustom.cpp new file mode 100644 index 0000000..8ecd287 --- /dev/null +++ b/WebCore/bindings/js/JSHTMLCanvasElementCustom.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSHTMLCanvasElement.h" + +#include "HTMLCanvasElement.h" +#include "JSCanvasRenderingContext2D.h" +#if ENABLE(3D_CANVAS) +#include "JSCanvasRenderingContext3D.h" +#endif +#include <wtf/GetPtr.h> + +using namespace JSC; + +namespace WebCore { + +void JSHTMLCanvasElement::markChildren(MarkStack& markStack) +{ + Base::markChildren(markStack); + + HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(impl()); + JSGlobalData& globalData = *Heap::heap(this)->globalData(); + + markDOMObjectWrapper(markStack, globalData, canvas->renderingContext()); +} + +} // namespace WebCore diff --git a/WebCore/bindings/js/JSHTMLCollectionCustom.cpp b/WebCore/bindings/js/JSHTMLCollectionCustom.cpp index dd9af74..8ffddf7 100644 --- a/WebCore/bindings/js/JSHTMLCollectionCustom.cpp +++ b/WebCore/bindings/js/JSHTMLCollectionCustom.cpp @@ -23,12 +23,13 @@ #include "AtomicString.h" #include "HTMLCollection.h" #include "HTMLOptionsCollection.h" +#include "JSDOMBinding.h" #include "JSHTMLAllCollection.h" #include "JSHTMLOptionsCollection.h" -#include "JSNamedNodesCollection.h" #include "JSNode.h" +#include "JSNodeList.h" #include "Node.h" -#include "JSDOMBinding.h" +#include "StaticNodeList.h" #include <wtf/Vector.h> using namespace JSC; @@ -42,11 +43,13 @@ static JSValue getNamedItems(ExecState* exec, JSHTMLCollection* collection, cons if (namedItems.isEmpty()) return jsUndefined(); - if (namedItems.size() == 1) return toJS(exec, collection->globalObject(), namedItems[0].get()); - return new (exec) JSNamedNodesCollection(exec, collection->globalObject(), namedItems); + // FIXME: HTML5 specifies that this should be a DynamicNodeList. + // FIXME: HTML5 specifies that non-HTMLOptionsCollection collections should return + // the first matching item instead of a NodeList. + return toJS(exec, collection->globalObject(), StaticNodeList::adopt(namedItems).get()); } // HTMLCollections are strange objects, they support both get and call, diff --git a/WebCore/bindings/js/JSHTMLEmbedElementCustom.cpp b/WebCore/bindings/js/JSHTMLEmbedElementCustom.cpp index 2570bc6..bce3ffb 100644 --- a/WebCore/bindings/js/JSHTMLEmbedElementCustom.cpp +++ b/WebCore/bindings/js/JSHTMLEmbedElementCustom.cpp @@ -38,6 +38,11 @@ bool JSHTMLEmbedElement::getOwnPropertySlotDelegate(ExecState* exec, const Ident return runtimeObjectCustomGetOwnPropertySlot(exec, propertyName, slot, this); } +bool JSHTMLEmbedElement::getOwnPropertyDescriptorDelegate(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + return runtimeObjectCustomGetOwnPropertyDescriptor(exec, propertyName, descriptor, this); +} + bool JSHTMLEmbedElement::putDelegate(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { return runtimeObjectCustomPut(exec, propertyName, value, impl(), slot); diff --git a/WebCore/bindings/js/JSHTMLFormElementCustom.cpp b/WebCore/bindings/js/JSHTMLFormElementCustom.cpp index ffa2d57..de9ec4a 100644 --- a/WebCore/bindings/js/JSHTMLFormElementCustom.cpp +++ b/WebCore/bindings/js/JSHTMLFormElementCustom.cpp @@ -30,7 +30,8 @@ #include "HTMLCollection.h" #include "HTMLFormElement.h" #include "JSDOMWindowCustom.h" -#include "JSNamedNodesCollection.h" +#include "JSNodeList.h" +#include "StaticNodeList.h" using namespace JSC; @@ -47,15 +48,17 @@ JSValue JSHTMLFormElement::nameGetter(ExecState* exec, const Identifier& propert { JSHTMLElement* jsForm = static_cast<JSHTMLFormElement*>(asObject(slot.slotBase())); HTMLFormElement* form = static_cast<HTMLFormElement*>(jsForm->impl()); - + Vector<RefPtr<Node> > namedItems; form->getNamedElements(propertyName, namedItems); + if (namedItems.isEmpty()) + return jsUndefined(); if (namedItems.size() == 1) return toJS(exec, namedItems[0].get()); - if (namedItems.size() > 1) - return new (exec) JSNamedNodesCollection(exec, jsForm->globalObject(), namedItems); - return jsUndefined(); + + // FIXME: HTML5 specifies that this should be a RadioNodeList. + return toJS(exec, jsForm->globalObject(), StaticNodeList::adopt(namedItems).get()); } JSValue JSHTMLFormElement::submit(ExecState* exec, const ArgList&) diff --git a/WebCore/bindings/js/JSHTMLFrameElementCustom.cpp b/WebCore/bindings/js/JSHTMLFrameElementCustom.cpp index c8aea9f..6e01513 100644 --- a/WebCore/bindings/js/JSHTMLFrameElementCustom.cpp +++ b/WebCore/bindings/js/JSHTMLFrameElementCustom.cpp @@ -32,16 +32,20 @@ #include "CSSHelper.h" #include "Document.h" #include "HTMLFrameElement.h" +#include "HTMLNames.h" #include "JSDOMBinding.h" using namespace JSC; namespace WebCore { +using namespace HTMLNames; + static inline bool allowSettingJavascriptURL(ExecState* exec, HTMLFrameElement* imp, const String& value) { if (protocolIsJavaScript(deprecatedParseURL(value))) { - if (!checkNodeSecurity(exec, imp->contentDocument())) + Document* contentDocument = imp->contentDocument(); + if (contentDocument && !checkNodeSecurity(exec, contentDocument)) return false; } return true; @@ -55,8 +59,7 @@ void JSHTMLFrameElement::setSrc(ExecState* exec, JSValue value) if (!allowSettingJavascriptURL(exec, imp, srcValue)) return; - imp->setSrc(srcValue); - return; + imp->setAttribute(srcAttr, srcValue); } void JSHTMLFrameElement::setLocation(ExecState* exec, JSValue value) @@ -68,7 +71,6 @@ void JSHTMLFrameElement::setLocation(ExecState* exec, JSValue value) return; imp->setLocation(locationValue); - return; } } // namespace WebCore diff --git a/WebCore/bindings/js/JSHTMLIFrameElementCustom.cpp b/WebCore/bindings/js/JSHTMLIFrameElementCustom.cpp index 8e32381..60ea45e 100644 --- a/WebCore/bindings/js/JSHTMLIFrameElementCustom.cpp +++ b/WebCore/bindings/js/JSHTMLIFrameElementCustom.cpp @@ -32,12 +32,15 @@ #include "CSSHelper.h" #include "Document.h" #include "HTMLIFrameElement.h" +#include "HTMLNames.h" #include "JSDOMBinding.h" using namespace JSC; namespace WebCore { +using namespace HTMLNames; + void JSHTMLIFrameElement::setSrc(ExecState* exec, JSValue value) { HTMLIFrameElement* imp = static_cast<HTMLIFrameElement*>(impl()); @@ -45,11 +48,12 @@ void JSHTMLIFrameElement::setSrc(ExecState* exec, JSValue value) String srcValue = valueToStringWithNullCheck(exec, value); if (protocolIsJavaScript(deprecatedParseURL(srcValue))) { - if (!checkNodeSecurity(exec, imp->contentDocument())) + Document* contentDocument = imp->contentDocument(); + if (contentDocument && !checkNodeSecurity(exec, contentDocument)) return; } - imp->setSrc(srcValue); + imp->setAttribute(srcAttr, srcValue); } } // namespace WebCore diff --git a/WebCore/bindings/js/JSHTMLInputElementCustom.cpp b/WebCore/bindings/js/JSHTMLInputElementCustom.cpp index 6b47622..e5166ee 100644 --- a/WebCore/bindings/js/JSHTMLInputElementCustom.cpp +++ b/WebCore/bindings/js/JSHTMLInputElementCustom.cpp @@ -29,6 +29,7 @@ #include "Document.h" #include "HTMLInputElement.h" #include "Settings.h" +#include <runtime/Error.h> using namespace JSC; diff --git a/WebCore/bindings/js/JSHTMLObjectElementCustom.cpp b/WebCore/bindings/js/JSHTMLObjectElementCustom.cpp index a99e46c..1bfb51f 100644 --- a/WebCore/bindings/js/JSHTMLObjectElementCustom.cpp +++ b/WebCore/bindings/js/JSHTMLObjectElementCustom.cpp @@ -38,6 +38,11 @@ bool JSHTMLObjectElement::getOwnPropertySlotDelegate(ExecState* exec, const Iden return runtimeObjectCustomGetOwnPropertySlot(exec, propertyName, slot, this); } +bool JSHTMLObjectElement::getOwnPropertyDescriptorDelegate(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + return runtimeObjectCustomGetOwnPropertyDescriptor(exec, propertyName, descriptor, this); +} + bool JSHTMLObjectElement::putDelegate(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { return runtimeObjectCustomPut(exec, propertyName, value, impl(), slot); diff --git a/WebCore/bindings/js/JSHistoryCustom.cpp b/WebCore/bindings/js/JSHistoryCustom.cpp index a3b15e1..b24b1ff 100644 --- a/WebCore/bindings/js/JSHistoryCustom.cpp +++ b/WebCore/bindings/js/JSHistoryCustom.cpp @@ -31,6 +31,7 @@ #include "Frame.h" #include "History.h" +#include <runtime/JSFunction.h> #include <runtime/PrototypeFunction.h> using namespace JSC; @@ -92,6 +93,52 @@ bool JSHistory::getOwnPropertySlotDelegate(ExecState* exec, const Identifier& pr return true; } +bool JSHistory::getOwnPropertyDescriptorDelegate(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + // When accessing History cross-domain, functions are always the native built-in ones. + // See JSDOMWindow::getOwnPropertySlotDelegate for additional details. + + // Our custom code is only needed to implement the Window cross-domain scheme, so if access is + // allowed, return false so the normal lookup will take place. + String message; + if (allowsAccessFromFrame(exec, impl()->frame(), message)) + return false; + + // Check for the few functions that we allow, even when called cross-domain. + const HashEntry* entry = JSHistoryPrototype::s_info.propHashTable(exec)->entry(exec, propertyName); + if (entry) { + PropertySlot slot; + // Allow access to back(), forward() and go() from any frame. + if (entry->attributes() & Function) { + if (entry->function() == jsHistoryPrototypeFunctionBack) { + slot.setCustom(this, nonCachingStaticBackFunctionGetter); + descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes()); + return true; + } else if (entry->function() == jsHistoryPrototypeFunctionForward) { + slot.setCustom(this, nonCachingStaticForwardFunctionGetter); + descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes()); + return true; + } else if (entry->function() == jsHistoryPrototypeFunctionGo) { + slot.setCustom(this, nonCachingStaticGoFunctionGetter); + descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes()); + return true; + } + } + } else { + // Allow access to toString() cross-domain, but always Object.toString. + if (propertyName == exec->propertyNames().toString) { + PropertySlot slot; + slot.setCustom(this, objectToStringFunctionGetter); + descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes()); + return true; + } + } + + printErrorMessageForFrame(impl()->frame(), message); + descriptor.setUndefined(); + return true; +} + bool JSHistory::putDelegate(ExecState* exec, const Identifier&, JSValue, PutPropertySlot&) { // Only allow putting by frames in the same origin. @@ -108,12 +155,12 @@ bool JSHistory::deleteProperty(ExecState* exec, const Identifier& propertyName) return Base::deleteProperty(exec, propertyName); } -void JSHistory::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +void JSHistory::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) { // Only allow the history object to enumerated by frames in the same origin. if (!allowsAccessFromFrame(exec, impl()->frame())) return; - Base::getPropertyNames(exec, propertyNames); + Base::getOwnPropertyNames(exec, propertyNames); } } // namespace WebCore diff --git a/WebCore/bindings/js/JSImageConstructor.cpp b/WebCore/bindings/js/JSImageConstructor.cpp index faaaf41..0f4a991 100644 --- a/WebCore/bindings/js/JSImageConstructor.cpp +++ b/WebCore/bindings/js/JSImageConstructor.cpp @@ -25,6 +25,7 @@ #include "JSHTMLImageElement.h" #include "JSNode.h" #include "ScriptExecutionContext.h" +#include <runtime/Error.h> using namespace JSC; diff --git a/WebCore/bindings/js/JSInspectedObjectWrapper.cpp b/WebCore/bindings/js/JSInspectedObjectWrapper.cpp index fff7aee..ed79427 100644 --- a/WebCore/bindings/js/JSInspectedObjectWrapper.cpp +++ b/WebCore/bindings/js/JSInspectedObjectWrapper.cpp @@ -26,6 +26,8 @@ #include "config.h" #include "JSInspectedObjectWrapper.h" +#if ENABLE(INSPECTOR) + #include "JSInspectorCallbackWrapper.h" #include <runtime/JSGlobalObject.h> #include <wtf/StdLibExtras.h> @@ -69,7 +71,7 @@ JSValue JSInspectedObjectWrapper::wrap(ExecState* unwrappedExec, JSValue unwrapp return new (unwrappedExec) JSInspectedObjectWrapper(unwrappedExec, unwrappedObject, JSQuarantinedObjectWrapper::createStructure(asObject(wrap(unwrappedExec, prototype)))); } -JSInspectedObjectWrapper::JSInspectedObjectWrapper(ExecState* unwrappedExec, JSObject* unwrappedObject, PassRefPtr<Structure> structure) +JSInspectedObjectWrapper::JSInspectedObjectWrapper(ExecState* unwrappedExec, JSObject* unwrappedObject, NonNullPassRefPtr<Structure> structure) : JSQuarantinedObjectWrapper(unwrappedExec, unwrappedObject, structure) { WrapperMap* wrapperMap = wrappers().get(unwrappedGlobalObject()); @@ -125,3 +127,5 @@ JSValue JSInspectedObjectWrapper::prepareIncomingValue(ExecState*, JSValue value } } // namespace WebCore + +#endif // ENABLE(INSPECTOR) diff --git a/WebCore/bindings/js/JSInspectedObjectWrapper.h b/WebCore/bindings/js/JSInspectedObjectWrapper.h index 201feb6..ad97035 100644 --- a/WebCore/bindings/js/JSInspectedObjectWrapper.h +++ b/WebCore/bindings/js/JSInspectedObjectWrapper.h @@ -38,7 +38,7 @@ namespace WebCore { static const JSC::ClassInfo s_info; private: - JSInspectedObjectWrapper(JSC::ExecState* unwrappedExec, JSC::JSObject* unwrappedObject, PassRefPtr<JSC::Structure>); + JSInspectedObjectWrapper(JSC::ExecState* unwrappedExec, JSC::JSObject* unwrappedObject, NonNullPassRefPtr<JSC::Structure>); virtual bool allowsGetProperty() const { return true; } virtual bool allowsSetProperty() const { return true; } diff --git a/WebCore/bindings/js/JSInspectorBackendCustom.cpp b/WebCore/bindings/js/JSInspectorBackendCustom.cpp index b2eb2d1..73fa268 100644 --- a/WebCore/bindings/js/JSInspectorBackendCustom.cpp +++ b/WebCore/bindings/js/JSInspectorBackendCustom.cpp @@ -33,6 +33,8 @@ #include "config.h" #include "JSInspectorBackend.h" +#if ENABLE(INSPECTOR) + #include "Console.h" #if ENABLE(DATABASE) #include "Database.h" @@ -51,6 +53,10 @@ #include "JSRange.h" #include "Node.h" #include "Page.h" +#if ENABLE(DOM_STORAGE) +#include "Storage.h" +#include "JSStorage.h" +#endif #include "TextIterator.h" #include "VisiblePosition.h" #include <runtime/JSArray.h> @@ -70,21 +76,12 @@ using namespace JSC; namespace WebCore { -JSValue JSInspectorBackend::highlightDOMNode(JSC::ExecState*, const JSC::ArgList& args) +JSValue JSInspectorBackend::highlightDOMNode(JSC::ExecState* exec, const JSC::ArgList& args) { if (args.size() < 1) return jsUndefined(); - JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(args.at(0)); - if (!wrapper) - return jsUndefined(); - - Node* node = toNode(wrapper->unwrappedObject()); - if (!node) - return jsUndefined(); - - impl()->highlight(node); - + impl()->highlight(args.at(0).toInt32(exec)); return jsUndefined(); } @@ -125,27 +122,20 @@ JSValue JSInspectorBackend::search(ExecState* exec, const ArgList& args) } #if ENABLE(DATABASE) -JSValue JSInspectorBackend::databaseTableNames(ExecState* exec, const ArgList& args) +JSValue JSInspectorBackend::databaseForId(ExecState* exec, const ArgList& args) { if (args.size() < 1) return jsUndefined(); - JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(args.at(0)); - if (!wrapper) + InspectorController* ic = impl()->inspectorController(); + if (!ic) return jsUndefined(); - Database* database = toDatabase(wrapper->unwrappedObject()); + Database* database = impl()->databaseForId(args.at(0).toInt32(exec)); if (!database) return jsUndefined(); - - MarkedArgumentBuffer result; - - Vector<String> tableNames = database->tableNames(); - unsigned length = tableNames.size(); - for (unsigned i = 0; i < length; ++i) - result.append(jsString(exec, tableNames[i])); - - return constructArray(exec, result); + JSDOMWindow* inspectedWindow = toJSDOMWindow(ic->inspectedPage()->mainFrame()); + return JSInspectedObjectWrapper::wrap(inspectedWindow->globalExec(), toJS(exec, database)); } #endif @@ -257,7 +247,7 @@ JSValue JSInspectorBackend::currentCallFrame(ExecState* exec, const ArgList&) return jsUndefined(); // FIXME: I am not sure if this is actually needed. Can we just use exec? - ExecState* globalExec = callFrame->scopeChain()->globalObject()->globalExec(); + ExecState* globalExec = callFrame->scopeChain()->globalObject->globalExec(); JSLock lock(SilenceAssertionsOnly); return JSInspectedObjectWrapper::wrap(globalExec, toJS(exec, callFrame)); @@ -280,4 +270,94 @@ JSValue JSInspectorBackend::profiles(JSC::ExecState* exec, const JSC::ArgList&) #endif +JSValue JSInspectorBackend::nodeForId(ExecState* exec, const ArgList& args) +{ + if (args.size() < 1) + return jsUndefined(); + + Node* node = impl()->nodeForId(args.at(0).toInt32(exec)); + if (!node) + return jsUndefined(); + + InspectorController* ic = impl()->inspectorController(); + if (!ic) + return jsUndefined(); + + JSLock lock(SilenceAssertionsOnly); + JSDOMWindow* inspectedWindow = toJSDOMWindow(ic->inspectedPage()->mainFrame()); + return JSInspectedObjectWrapper::wrap(inspectedWindow->globalExec(), toJS(exec, deprecatedGlobalObjectForPrototype(inspectedWindow->globalExec()), node)); +} + +JSValue JSInspectorBackend::wrapObject(ExecState* exec, const ArgList& args) +{ + if (args.size() < 2) + return jsUndefined(); + + return impl()->wrapObject(ScriptValue(args.at(0)), args.at(1).toString(exec)).jsValue(); +} + +JSValue JSInspectorBackend::unwrapObject(ExecState* exec, const ArgList& args) +{ + if (args.size() < 1) + return jsUndefined(); + + return impl()->unwrapObject(args.at(0).toString(exec)).jsValue(); +} + +JSValue JSInspectorBackend::pushNodePathToFrontend(ExecState* exec, const ArgList& args) +{ + if (args.size() < 2) + return jsUndefined(); + + JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(args.at(0)); + if (!wrapper) + return jsUndefined(); + + Node* node = toNode(wrapper->unwrappedObject()); + if (!node) + return jsUndefined(); + + bool selectInUI = args.at(1).toBoolean(exec); + return jsNumber(exec, impl()->pushNodePathToFrontend(node, selectInUI)); +} + +#if ENABLE(DATABASE) +JSValue JSInspectorBackend::selectDatabase(ExecState*, const ArgList& args) +{ + if (args.size() < 1) + return jsUndefined(); + + JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(args.at(0)); + if (!wrapper) + return jsUndefined(); + + Database* database = toDatabase(wrapper->unwrappedObject()); + if (database) + impl()->selectDatabase(database); + return jsUndefined(); +} +#endif + +#if ENABLE(DOM_STORAGE) +JSValue JSInspectorBackend::selectDOMStorage(ExecState*, const ArgList& args) +{ + if (args.size() < 1) + return jsUndefined(); + InspectorController* ic = impl()->inspectorController(); + if (!ic) + return jsUndefined(); + + JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(args.at(0)); + if (!wrapper) + return jsUndefined(); + + Storage* storage = toStorage(wrapper->unwrappedObject()); + if (storage) + impl()->selectDOMStorage(storage); + return jsUndefined(); +} +#endif + } // namespace WebCore + +#endif // ENABLE(INSPECTOR) diff --git a/WebCore/bindings/js/JSInspectorCallbackWrapper.cpp b/WebCore/bindings/js/JSInspectorCallbackWrapper.cpp index 0e14109..9c4330d 100644 --- a/WebCore/bindings/js/JSInspectorCallbackWrapper.cpp +++ b/WebCore/bindings/js/JSInspectorCallbackWrapper.cpp @@ -26,6 +26,8 @@ #include "config.h" #include "JSInspectorCallbackWrapper.h" +#if ENABLE(INSPECTOR) + #include "JSInspectedObjectWrapper.h" #include <wtf/StdLibExtras.h> @@ -73,10 +75,10 @@ JSValue JSInspectorCallbackWrapper::wrap(ExecState* unwrappedExec, JSValue unwra static Structure* structure = leakInspectorCallbackWrapperStructure(); return new (unwrappedExec) JSInspectorCallbackWrapper(unwrappedExec, unwrappedObject, structure); } - return new (unwrappedExec) JSInspectorCallbackWrapper(unwrappedExec, unwrappedObject, asObject(wrap(unwrappedExec, prototype))->inheritorID()); + return new (unwrappedExec) JSInspectorCallbackWrapper(unwrappedExec, unwrappedObject, createStructure(wrap(unwrappedExec, prototype))); } -JSInspectorCallbackWrapper::JSInspectorCallbackWrapper(ExecState* unwrappedExec, JSObject* unwrappedObject, PassRefPtr<Structure> structure) +JSInspectorCallbackWrapper::JSInspectorCallbackWrapper(ExecState* unwrappedExec, JSObject* unwrappedObject, NonNullPassRefPtr<Structure> structure) : JSQuarantinedObjectWrapper(unwrappedExec, unwrappedObject, structure) { ASSERT(!wrappers().contains(unwrappedObject)); @@ -105,3 +107,5 @@ JSValue JSInspectorCallbackWrapper::prepareIncomingValue(ExecState* unwrappedExe } } // namespace WebCore + +#endif // ENABLE(INSPECTOR) diff --git a/WebCore/bindings/js/JSInspectorCallbackWrapper.h b/WebCore/bindings/js/JSInspectorCallbackWrapper.h index cfc2fb6..be28063 100644 --- a/WebCore/bindings/js/JSInspectorCallbackWrapper.h +++ b/WebCore/bindings/js/JSInspectorCallbackWrapper.h @@ -40,7 +40,7 @@ namespace WebCore { static const JSC::ClassInfo s_info; protected: - JSInspectorCallbackWrapper(JSC::ExecState* unwrappedExec, JSC::JSObject* unwrappedObject, PassRefPtr<JSC::Structure>); + JSInspectorCallbackWrapper(JSC::ExecState* unwrappedExec, JSC::JSObject* unwrappedObject, NonNullPassRefPtr<JSC::Structure>); virtual bool allowsCallAsFunction() const { return true; } diff --git a/WebCore/bindings/js/JSLazyEventListener.cpp b/WebCore/bindings/js/JSLazyEventListener.cpp index 7caff2b..0d6cb57 100644 --- a/WebCore/bindings/js/JSLazyEventListener.cpp +++ b/WebCore/bindings/js/JSLazyEventListener.cpp @@ -23,6 +23,7 @@ #include "Frame.h" #include "JSNode.h" #include <runtime/FunctionConstructor.h> +#include <runtime/JSFunction.h> #include <runtime/JSLock.h> #include <wtf/RefCountedLeakCounter.h> @@ -34,12 +35,13 @@ namespace WebCore { static WTF::RefCountedLeakCounter eventListenerCounter("JSLazyEventListener"); #endif -JSLazyEventListener::JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, JSDOMGlobalObject* globalObject, Node* node, int lineNumber) - : JSEventListener(0, globalObject, true) +JSLazyEventListener::JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, Node* node, const String& sourceURL, int lineNumber) + : JSEventListener(0, true) , m_functionName(functionName) , m_eventParameterName(eventParameterName) , m_code(code) , m_parsed(false) + , m_sourceURL(sourceURL) , m_lineNumber(lineNumber) , m_originalNode(node) { @@ -66,23 +68,43 @@ JSLazyEventListener::~JSLazyEventListener() #endif } -JSObject* JSLazyEventListener::jsFunction() const +JSObject* JSLazyEventListener::jsFunction(ScriptExecutionContext* executionContext) const { - parseCode(); + parseCode(executionContext); return m_jsFunction; } -void JSLazyEventListener::parseCode() const +void JSLazyEventListener::parseCode(ScriptExecutionContext* executionContext) const { + ASSERT(executionContext); + ASSERT(executionContext->isDocument()); + if (!executionContext) + return; + if (m_parsed) return; - ScriptExecutionContext* executionContext = m_globalObject->scriptExecutionContext(); - ASSERT(executionContext); - if (!executionContext) + Frame* frame = static_cast<Document*>(executionContext)->frame(); + if (!frame) return; + + ScriptController* scriptController = frame->script(); + if (!scriptController->isEnabled()) + return; + + JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext); + if (!globalObject) + return; + + // Ensure that 'node' has a JavaScript wrapper to mark the event listener we're creating. + if (m_originalNode) { + JSLock lock(SilenceAssertionsOnly); + // FIXME: Should pass the global object associated with the node + toJS(globalObject->globalExec(), globalObject, m_originalNode); + } + if (executionContext->isDocument()) { - JSDOMWindow* window = static_cast<JSDOMWindow*>(m_globalObject); + JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); Frame* frame = window->impl()->frame(); if (!frame) return; @@ -94,16 +116,13 @@ void JSLazyEventListener::parseCode() const m_parsed = true; - ExecState* exec = m_globalObject->globalExec(); + ExecState* exec = globalObject->globalExec(); MarkedArgumentBuffer args; - UString sourceURL(executionContext->url().string()); args.append(jsNontrivialString(exec, m_eventParameterName)); args.append(jsString(exec, m_code)); - // FIXME: Passing the document's URL to construct is not always correct, since this event listener might - // have been added with setAttribute from a script, and we should pass String() in that case. - m_jsFunction = constructFunction(exec, args, Identifier(exec, m_functionName), sourceURL, m_lineNumber); // FIXME: is globalExec ok? + m_jsFunction = constructFunction(exec, args, Identifier(exec, m_functionName), m_sourceURL, m_lineNumber); // FIXME: is globalExec ok? JSFunction* listenerAsFunction = static_cast<JSFunction*>(m_jsFunction); @@ -117,7 +136,7 @@ void JSLazyEventListener::parseCode() const // (and the document, and the form - see JSHTMLElement::eventHandlerScope) ScopeChain scope = listenerAsFunction->scope(); - JSValue thisObj = toJS(exec, m_globalObject, m_originalNode); + JSValue thisObj = toJS(exec, globalObject, m_originalNode); if (thisObj.isObject()) { static_cast<JSNode*>(asObject(thisObj))->pushEventHandlerScope(exec, scope); listenerAsFunction->setScope(scope); @@ -128,6 +147,7 @@ void JSLazyEventListener::parseCode() const m_functionName = String(); m_code = String(); m_eventParameterName = String(); + m_sourceURL = String(); } } // namespace WebCore diff --git a/WebCore/bindings/js/JSLazyEventListener.h b/WebCore/bindings/js/JSLazyEventListener.h index a5304cf..e3137b8 100644 --- a/WebCore/bindings/js/JSLazyEventListener.h +++ b/WebCore/bindings/js/JSLazyEventListener.h @@ -29,24 +29,25 @@ namespace WebCore { class JSLazyEventListener : public JSEventListener { public: - static PassRefPtr<JSLazyEventListener> create(const String& functionName, const String& eventParameterName, const String& code, JSDOMGlobalObject* globalObject, Node* node, int lineNumber) + static PassRefPtr<JSLazyEventListener> create(const String& functionName, const String& eventParameterName, const String& code, Node* node, const String& sourceURL, int lineNumber) { - return adoptRef(new JSLazyEventListener(functionName, eventParameterName, code, globalObject, node, lineNumber)); + return adoptRef(new JSLazyEventListener(functionName, eventParameterName, code, node, sourceURL, lineNumber)); } virtual ~JSLazyEventListener(); private: - JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, JSDOMGlobalObject*, Node*, int lineNumber); + JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, Node*, const String& sourceURL, int lineNumber); - virtual JSC::JSObject* jsFunction() const; + virtual JSC::JSObject* jsFunction(ScriptExecutionContext*) const; virtual bool wasCreatedFromMarkup() const { return true; } - void parseCode() const; + void parseCode(ScriptExecutionContext*) const; mutable String m_functionName; mutable String m_eventParameterName; mutable String m_code; mutable bool m_parsed; + mutable String m_sourceURL; int m_lineNumber; Node* m_originalNode; }; diff --git a/WebCore/bindings/js/JSLocationCustom.cpp b/WebCore/bindings/js/JSLocationCustom.cpp index d7d32f4..c76a2b1 100644 --- a/WebCore/bindings/js/JSLocationCustom.cpp +++ b/WebCore/bindings/js/JSLocationCustom.cpp @@ -31,6 +31,7 @@ #include "KURL.h" #include "Location.h" #include "ScriptController.h" +#include <runtime/JSFunction.h> #include <runtime/PrototypeFunction.h> using namespace JSC; @@ -93,6 +94,51 @@ bool JSLocation::getOwnPropertySlotDelegate(ExecState* exec, const Identifier& p return true; } +bool JSLocation::getOwnPropertyDescriptorDelegate(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + Frame* frame = impl()->frame(); + if (!frame) { + descriptor.setUndefined(); + return true; + } + + // When accessing Location cross-domain, functions are always the native built-in ones. + // See JSDOMWindow::getOwnPropertySlotDelegate for additional details. + + // Our custom code is only needed to implement the Window cross-domain scheme, so if access is + // allowed, return false so the normal lookup will take place. + String message; + if (allowsAccessFromFrame(exec, frame, message)) + return false; + + // Check for the few functions that we allow, even when called cross-domain. + const HashEntry* entry = JSLocationPrototype::s_info.propHashTable(exec)->entry(exec, propertyName); + PropertySlot slot; + if (entry && (entry->attributes() & Function)) { + if (entry->function() == jsLocationPrototypeFunctionReplace) { + slot.setCustom(this, nonCachingStaticReplaceFunctionGetter); + descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes()); + return true; + } else if (entry->function() == jsLocationPrototypeFunctionReload) { + slot.setCustom(this, nonCachingStaticReloadFunctionGetter); + descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes()); + return true; + } else if (entry->function() == jsLocationPrototypeFunctionAssign) { + slot.setCustom(this, nonCachingStaticAssignFunctionGetter); + descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes()); + return true; + } + } + + // FIXME: Other implementers of the Window cross-domain scheme (Window, History) allow toString, + // but for now we have decided not to, partly because it seems silly to return "[Object Location]" in + // such cases when normally the string form of Location would be the URL. + + printErrorMessageForFrame(frame, message); + descriptor.setUndefined(); + return true; +} + bool JSLocation::putDelegate(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { Frame* frame = impl()->frame(); @@ -128,19 +174,19 @@ bool JSLocation::deleteProperty(ExecState* exec, const Identifier& propertyName) return Base::deleteProperty(exec, propertyName); } -void JSLocation::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +void JSLocation::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) { // Only allow the location object to enumerated by frames in the same origin. if (!allowsAccessFromFrame(exec, impl()->frame())) return; - Base::getPropertyNames(exec, propertyNames); + Base::getOwnPropertyNames(exec, propertyNames); } -void JSLocation::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction) +void JSLocation::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes) { if (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf) return; - Base::defineGetter(exec, propertyName, getterFunction); + Base::defineGetter(exec, propertyName, getterFunction, attributes); } static void navigateIfAllowed(ExecState* exec, Frame* frame, const KURL& url, bool lockHistory, bool lockBackForwardList) @@ -150,7 +196,7 @@ static void navigateIfAllowed(ExecState* exec, Frame* frame, const KURL& url, bo return; if (!protocolIsJavaScript(url) || allowsAccessFromFrame(exec, frame)) - frame->loader()->scheduleLocationChange(url.string(), lexicalFrame->loader()->outgoingReferrer(), lockHistory, lockBackForwardList, processingUserGesture(exec)); + frame->redirectScheduler()->scheduleLocationChange(url.string(), lexicalFrame->loader()->outgoingReferrer(), lockHistory, lockBackForwardList, processingUserGesture(exec)); } void JSLocation::setHref(ExecState* exec, JSValue value) @@ -158,13 +204,13 @@ void JSLocation::setHref(ExecState* exec, JSValue value) Frame* frame = impl()->frame(); ASSERT(frame); - if (!shouldAllowNavigation(exec, frame)) - return; - KURL url = completeURL(exec, value.toString(exec)); if (url.isNull()) return; + if (!shouldAllowNavigation(exec, frame)) + return; + navigateIfAllowed(exec, frame, url, !frame->script()->anyPageIsProcessingUserGesture(), false); } @@ -262,13 +308,13 @@ JSValue JSLocation::replace(ExecState* exec, const ArgList& args) if (!frame) return jsUndefined(); - if (!shouldAllowNavigation(exec, frame)) - return jsUndefined(); - KURL url = completeURL(exec, args.at(0).toString(exec)); if (url.isNull()) return jsUndefined(); + if (!shouldAllowNavigation(exec, frame)) + return jsUndefined(); + navigateIfAllowed(exec, frame, url, true, true); return jsUndefined(); } @@ -280,7 +326,7 @@ JSValue JSLocation::reload(ExecState* exec, const ArgList&) return jsUndefined(); if (!protocolIsJavaScript(frame->loader()->url())) - frame->loader()->scheduleRefresh(processingUserGesture(exec)); + frame->redirectScheduler()->scheduleRefresh(processingUserGesture(exec)); return jsUndefined(); } @@ -290,13 +336,13 @@ JSValue JSLocation::assign(ExecState* exec, const ArgList& args) if (!frame) return jsUndefined(); - if (!shouldAllowNavigation(exec, frame)) - return jsUndefined(); - KURL url = completeURL(exec, args.at(0).toString(exec)); if (url.isNull()) return jsUndefined(); + if (!shouldAllowNavigation(exec, frame)) + return jsUndefined(); + // We want a new history item if this JS was called via a user gesture navigateIfAllowed(exec, frame, url, !frame->script()->anyPageIsProcessingUserGesture(), false); return jsUndefined(); @@ -316,11 +362,11 @@ bool JSLocationPrototype::putDelegate(ExecState* exec, const Identifier& propert return (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf); } -void JSLocationPrototype::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction) +void JSLocationPrototype::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes) { if (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf) return; - Base::defineGetter(exec, propertyName, getterFunction); + Base::defineGetter(exec, propertyName, getterFunction, attributes); } } // namespace WebCore diff --git a/WebCore/bindings/js/JSMessageChannelConstructor.cpp b/WebCore/bindings/js/JSMessageChannelConstructor.cpp index 25a5cb2..9721ba3 100644 --- a/WebCore/bindings/js/JSMessageChannelConstructor.cpp +++ b/WebCore/bindings/js/JSMessageChannelConstructor.cpp @@ -30,6 +30,7 @@ #include "JSDocument.h" #include "JSMessageChannel.h" #include "MessageChannel.h" +#include <runtime/Error.h> using namespace JSC; diff --git a/WebCore/bindings/js/JSMessageEventCustom.cpp b/WebCore/bindings/js/JSMessageEventCustom.cpp new file mode 100644 index 0000000..2e7b2d0 --- /dev/null +++ b/WebCore/bindings/js/JSMessageEventCustom.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSMessageEvent.h" + +#include "JSDOMBinding.h" +#include "JSDOMWindow.h" +#include "JSEventTarget.h" +#include "JSMessagePortCustom.h" +#include "MessageEvent.h" +#include <runtime/JSArray.h> + +using namespace JSC; + +namespace WebCore { + +JSValue JSMessageEvent::ports(ExecState* exec) const +{ + MessagePortArray* ports = static_cast<MessageEvent*>(impl())->ports(); + if (!ports || ports->isEmpty()) + return jsNull(); + + MarkedArgumentBuffer list; + for (size_t i = 0; i < ports->size(); i++) + list.append(toJS(exec, globalObject(), (*ports)[i].get())); + return constructArray(exec, list); +} + +JSC::JSValue JSMessageEvent::initMessageEvent(JSC::ExecState* exec, const JSC::ArgList& args) +{ + const UString& typeArg = args.at(0).toString(exec); + bool canBubbleArg = args.at(1).toBoolean(exec); + bool cancelableArg = args.at(2).toBoolean(exec); + PassRefPtr<SerializedScriptValue> dataArg = SerializedScriptValue::create(exec, args.at(3)); + const UString& originArg = args.at(4).toString(exec); + const UString& lastEventIdArg = args.at(5).toString(exec); + DOMWindow* sourceArg = toDOMWindow(args.at(6)); + OwnPtr<MessagePortArray> messagePorts; + if (!args.at(7).isUndefinedOrNull()) { + messagePorts = new MessagePortArray(); + fillMessagePortArray(exec, args.at(7), *messagePorts); + if (exec->hadException()) + return jsUndefined(); + } + + MessageEvent* event = static_cast<MessageEvent*>(this->impl()); + event->initMessageEvent(typeArg, canBubbleArg, cancelableArg, dataArg, originArg, lastEventIdArg, sourceArg, messagePorts.release()); + return jsUndefined(); +} + +} // namespace WebCore diff --git a/WebCore/bindings/js/JSMessagePortCustom.cpp b/WebCore/bindings/js/JSMessagePortCustom.cpp index c3316c5..210c93e 100644 --- a/WebCore/bindings/js/JSMessagePortCustom.cpp +++ b/WebCore/bindings/js/JSMessagePortCustom.cpp @@ -28,11 +28,14 @@ #include "AtomicString.h" #include "Event.h" +#include "ExceptionCode.h" #include "Frame.h" #include "JSDOMGlobalObject.h" #include "JSEvent.h" #include "JSEventListener.h" +#include "JSMessagePortCustom.h" #include "MessagePort.h" +#include <runtime/Error.h> using namespace JSC; @@ -42,8 +45,6 @@ void JSMessagePort::markChildren(MarkStack& markStack) { Base::markChildren(markStack); - markIfNotNull(markStack, m_impl->onmessage()); - // If we have a locally entangled port, we can directly mark it as reachable. Ports that are remotely entangled are marked in-use by markActiveObjectsForContext(). if (MessagePort* entangledPort = m_impl->locallyEntangledPort()) { DOMObject* wrapper = getCachedDOMObjectWrapper(*Heap::heap(this)->globalData(), entangledPort); @@ -51,13 +52,7 @@ void JSMessagePort::markChildren(MarkStack& markStack) markStack.append(wrapper); } - typedef MessagePort::EventListenersMap EventListenersMap; - typedef MessagePort::ListenerVector ListenerVector; - EventListenersMap& eventListeners = m_impl->eventListeners(); - for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) { - for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter) - (*vecIter)->markJSFunction(markStack); - } + m_impl->markEventListeners(markStack); } JSValue JSMessagePort::addEventListener(ExecState* exec, const ArgList& args) @@ -65,10 +60,12 @@ JSValue JSMessagePort::addEventListener(ExecState* exec, const ArgList& args) JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext()); if (!globalObject) return jsUndefined(); - RefPtr<JSEventListener> listener = globalObject->findOrCreateJSEventListener(args.at(1)); - if (!listener) + + JSValue listener = args.at(1); + if (!listener.isObject()) return jsUndefined(); - impl()->addEventListener(args.at(0).toString(exec), listener.release(), args.at(2).toBoolean(exec)); + + impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec)); return jsUndefined(); } @@ -77,11 +74,54 @@ JSValue JSMessagePort::removeEventListener(ExecState* exec, const ArgList& args) JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext()); if (!globalObject) return jsUndefined(); - JSEventListener* listener = globalObject->findJSEventListener(args.at(1)); - if (!listener) + + JSValue listener = args.at(1); + if (!listener.isObject()) return jsUndefined(); - impl()->removeEventListener(args.at(0).toString(exec), listener, args.at(2).toBoolean(exec)); + + impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec)); return jsUndefined(); } +JSC::JSValue JSMessagePort::postMessage(JSC::ExecState* exec, const JSC::ArgList& args) +{ + return handlePostMessage(exec, args, impl()); +} + +void fillMessagePortArray(JSC::ExecState* exec, JSC::JSValue value, MessagePortArray& portArray) +{ + // Convert from the passed-in JS array-like object to a MessagePortArray. + // Also validates the elements per sections 4.1.13 and 4.1.15 of the WebIDL spec and section 8.3.3 of the HTML5 spec. + if (value.isUndefinedOrNull()) { + portArray.resize(0); + return; + } + + // Validation of sequence types, per WebIDL spec 4.1.13. + unsigned length; + JSObject* object = toJSSequence(exec, value, length); + if (exec->hadException()) + return; + + portArray.resize(length); + for (unsigned i = 0 ; i < length; ++i) { + JSValue value = object->get(exec, i); + if (exec->hadException()) + return; + // Validation of non-null objects, per HTML5 spec 8.3.3. + if (value.isUndefinedOrNull()) { + setDOMException(exec, INVALID_STATE_ERR); + return; + } + + // Validation of Objects implementing an interface, per WebIDL spec 4.1.15. + RefPtr<MessagePort> port = toMessagePort(value); + if (!port) { + throwError(exec, TypeError); + return; + } + portArray[i] = port.release(); + } +} + } // namespace WebCore diff --git a/WebCore/bindings/js/JSMessagePortCustom.h b/WebCore/bindings/js/JSMessagePortCustom.h new file mode 100644 index 0000000..17b1eae --- /dev/null +++ b/WebCore/bindings/js/JSMessagePortCustom.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSMessagePortCustom_h +#define JSMessagePortCustom_h + +#include "MessagePort.h" +#include <runtime/JSValue.h> + +namespace WebCore { + + typedef int ExceptionCode; + + class String; + + // Helper function which pulls the values out of a JS sequence and into a MessagePortArray. + // Also validates the elements per sections 4.1.13 and 4.1.15 of the WebIDL spec and section 8.3.3 of the HTML5 spec. + // May generate an exception via the passed ExecState. + void fillMessagePortArray(JSC::ExecState*, JSC::JSValue, MessagePortArray&); + + // Helper function to convert from JS postMessage arguments to WebCore postMessage arguments. + template <typename T> + inline JSC::JSValue handlePostMessage(JSC::ExecState* exec, const JSC::ArgList& args, T* impl) + { + PassRefPtr<SerializedScriptValue> message = SerializedScriptValue::create(exec, args.at(0)); + MessagePortArray portArray; + fillMessagePortArray(exec, args.at(1), portArray); + if (exec->hadException()) + return JSC::jsUndefined(); + + ExceptionCode ec = 0; + impl->postMessage(message, &portArray, ec); + setDOMException(exec, ec); + return JSC::jsUndefined(); + } + +} +#endif // JSMessagePortCustom_h diff --git a/WebCore/bindings/js/JSNamedNodeMapCustom.cpp b/WebCore/bindings/js/JSNamedNodeMapCustom.cpp index 7bd95b4..1974ab0 100644 --- a/WebCore/bindings/js/JSNamedNodeMapCustom.cpp +++ b/WebCore/bindings/js/JSNamedNodeMapCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,10 +27,9 @@ #include "JSNamedNodeMap.h" #include "JSNode.h" + +#include "Element.h" #include "NamedNodeMap.h" -#include "Node.h" -#include "PlatformString.h" -#include "JSDOMBinding.h" using namespace JSC; @@ -47,4 +46,16 @@ JSValue JSNamedNodeMap::nameGetter(ExecState* exec, const Identifier& propertyNa return toJS(exec, thisObj->impl()->getNamedItem(propertyName)); } +void JSNamedNodeMap::markChildren(MarkStack& markStack) +{ + Base::markChildren(markStack); + + // Mark the element so that this will work to access the attribute even if the last + // other reference goes away. + if (Element* element = impl()->element()) { + if (JSNode* wrapper = getCachedDOMNodeWrapper(element->document(), element)) + markStack.append(wrapper); + } +} + } // namespace WebCore diff --git a/WebCore/bindings/js/JSNamedNodesCollection.cpp b/WebCore/bindings/js/JSNamedNodesCollection.cpp deleted file mode 100644 index f36a7d6..0000000 --- a/WebCore/bindings/js/JSNamedNodesCollection.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * 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 - * 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 - * 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 - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "JSNamedNodesCollection.h" - -#include "AtomicString.h" -#include "Element.h" -#include "JSNode.h" -#include "NamedNodeMap.h" - -namespace WebCore { - -using namespace JSC; - -ASSERT_CLASS_FITS_IN_CELL(JSNamedNodesCollection); - -const ClassInfo JSNamedNodesCollection::s_info = { "Collection", 0, 0, 0 }; - -// Such a collection is usually very short-lived, it only exists -// for constructs like document.forms.<name>[1], -// so it shouldn't be a problem that it's storing all the nodes (with the same name). (David) -JSNamedNodesCollection::JSNamedNodesCollection(ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<RefPtr<Node> >& nodes) - : DOMObjectWithGlobalPointer(getDOMStructure<JSNamedNodesCollection>(exec, globalObject), globalObject) - , m_nodes(new Vector<RefPtr<Node> >(nodes)) -{ -} - -JSValue JSNamedNodesCollection::lengthGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) -{ - JSNamedNodesCollection* thisObj = static_cast<JSNamedNodesCollection*>(asObject(slot.slotBase())); - return jsNumber(exec, thisObj->m_nodes->size()); -} - -JSValue JSNamedNodesCollection::indexGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) -{ - JSNamedNodesCollection *thisObj = static_cast<JSNamedNodesCollection*>(asObject(slot.slotBase())); - return toJS(exec, (*thisObj->m_nodes)[slot.index()].get()); -} - -bool JSNamedNodesCollection::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) -{ - if (propertyName == exec->propertyNames().length) { - slot.setCustom(this, lengthGetter); - return true; - } - - bool ok; - unsigned index = propertyName.toUInt32(&ok); - if (ok && index < m_nodes->size()) { - slot.setCustomIndex(this, index, indexGetter); - return true; - } - - // For IE compatibility, we need to be able to look up elements in a - // document.formName.name result by id as well as be index. - - AtomicString atomicPropertyName = propertyName; - for (unsigned i = 0; i < m_nodes->size(); i++) { - Node* node = (*m_nodes)[i].get(); - if (node->hasAttributes() && node->attributes()->id() == atomicPropertyName) { - slot.setCustomIndex(this, i, indexGetter); - return true; - } - } - - return DOMObjectWithGlobalPointer::getOwnPropertySlot(exec, propertyName, slot); -} - -} // namespace WebCore diff --git a/WebCore/bindings/js/JSNodeCustom.cpp b/WebCore/bindings/js/JSNodeCustom.cpp index cf884b9..52f21e7 100644 --- a/WebCore/bindings/js/JSNodeCustom.cpp +++ b/WebCore/bindings/js/JSNodeCustom.cpp @@ -110,25 +110,37 @@ JSValue JSNode::appendChild(ExecState* exec, const ArgList& args) JSValue JSNode::addEventListener(ExecState* exec, const ArgList& args) { - JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->document()); + Document* document = impl()->document(); + if (!document) + return jsUndefined(); + + JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(document); if (!globalObject) return jsUndefined(); - if (RefPtr<JSEventListener> listener = globalObject->findOrCreateJSEventListener(args.at(1))) - impl()->addEventListener(args.at(0).toString(exec), listener.release(), args.at(2).toBoolean(exec)); + JSValue listener = args.at(1); + if (!listener.isObject()) + return jsUndefined(); + impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false), args.at(2).toBoolean(exec)); return jsUndefined(); } JSValue JSNode::removeEventListener(ExecState* exec, const ArgList& args) { - JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->document()); + Document* document = impl()->document(); + if (!document) + return jsUndefined(); + + JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(document); if (!globalObject) return jsUndefined(); - if (JSEventListener* listener = globalObject->findJSEventListener(args.at(1))) - impl()->removeEventListener(args.at(0).toString(exec), listener, args.at(2).toBoolean(exec)); + JSValue listener = args.at(1); + if (!listener.isObject()) + return jsUndefined(); + impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec)); return jsUndefined(); } @@ -138,10 +150,10 @@ void JSNode::pushEventHandlerScope(ExecState*, ScopeChain&) const void JSNode::markChildren(MarkStack& markStack) { - Node* node = m_impl.get(); - Base::markChildren(markStack); - markEventListeners(markStack, node->eventListeners()); + + Node* node = m_impl.get(); + node->markEventListeners(markStack); // Nodes in the document are kept alive by JSDocument::mark, so, if we're in // the document, we need to mark the document, but we don't need to explicitly diff --git a/WebCore/bindings/js/JSNodeFilterCustom.cpp b/WebCore/bindings/js/JSNodeFilterCustom.cpp index 09fd110..2a99a93 100644 --- a/WebCore/bindings/js/JSNodeFilterCustom.cpp +++ b/WebCore/bindings/js/JSNodeFilterCustom.cpp @@ -48,7 +48,7 @@ JSValue JSNodeFilter::acceptNode(ExecState* exec, const ArgList& args) PassRefPtr<NodeFilter> toNodeFilter(JSValue value) { - if (value.isObject(&JSNodeFilter::s_info)) + if (value.inherits(&JSNodeFilter::s_info)) return static_cast<JSNodeFilter*>(asObject(value))->impl(); return NodeFilter::create(JSNodeFilterCondition::create(value)); diff --git a/WebCore/bindings/js/JSOptionConstructor.cpp b/WebCore/bindings/js/JSOptionConstructor.cpp index 2b8bd5d..7da0666 100644 --- a/WebCore/bindings/js/JSOptionConstructor.cpp +++ b/WebCore/bindings/js/JSOptionConstructor.cpp @@ -25,6 +25,7 @@ #include "JSHTMLOptionElement.h" #include "ScriptExecutionContext.h" #include "Text.h" +#include <runtime/Error.h> using namespace JSC; diff --git a/WebCore/bindings/js/JSPluginElementFunctions.cpp b/WebCore/bindings/js/JSPluginElementFunctions.cpp index 56b0eca..ada2a77 100644 --- a/WebCore/bindings/js/JSPluginElementFunctions.cpp +++ b/WebCore/bindings/js/JSPluginElementFunctions.cpp @@ -86,6 +86,22 @@ bool runtimeObjectCustomGetOwnPropertySlot(ExecState* exec, const Identifier& pr return true; } +bool runtimeObjectCustomGetOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, JSHTMLElement* element) +{ + RuntimeObjectImp* runtimeObject = getRuntimeObject(exec, element->impl()); + if (!runtimeObject) + return false; + if (!runtimeObject->hasProperty(exec, propertyName)) + return false; + PropertySlot slot; + slot.setCustom(element, runtimeObjectPropertyGetter); + // While we don't know what the plugin allows, we do know that we prevent + // enumeration or deletion of properties, so we mark plugin properties + // as DontEnum | DontDelete + descriptor.setDescriptor(slot.getValue(exec, propertyName), DontEnum | DontDelete); + return true; +} + bool runtimeObjectCustomPut(ExecState* exec, const Identifier& propertyName, JSValue value, HTMLElement* element, PutPropertySlot& slot) { RuntimeObjectImp* runtimeObject = getRuntimeObject(exec, element); diff --git a/WebCore/bindings/js/JSPluginElementFunctions.h b/WebCore/bindings/js/JSPluginElementFunctions.h index 8c9dfa7..a5a323a 100644 --- a/WebCore/bindings/js/JSPluginElementFunctions.h +++ b/WebCore/bindings/js/JSPluginElementFunctions.h @@ -33,6 +33,7 @@ namespace WebCore { JSC::JSValue runtimeObjectGetter(JSC::ExecState*, const JSC::Identifier&, const JSC::PropertySlot&); JSC::JSValue runtimeObjectPropertyGetter(JSC::ExecState*, const JSC::Identifier&, const JSC::PropertySlot&); bool runtimeObjectCustomGetOwnPropertySlot(JSC::ExecState*, const JSC::Identifier&, JSC::PropertySlot&, JSHTMLElement*); + bool runtimeObjectCustomGetOwnPropertyDescriptor(JSC::ExecState*, const JSC::Identifier&, JSC::PropertyDescriptor&, JSHTMLElement*); bool runtimeObjectCustomPut(JSC::ExecState*, const JSC::Identifier&, JSC::JSValue, HTMLElement*, JSC::PutPropertySlot&); JSC::CallType runtimeObjectGetCallData(HTMLElement*, JSC::CallData&); diff --git a/WebCore/bindings/js/JSQuarantinedObjectWrapper.cpp b/WebCore/bindings/js/JSQuarantinedObjectWrapper.cpp index 5f4dfd4..a0551a1 100644 --- a/WebCore/bindings/js/JSQuarantinedObjectWrapper.cpp +++ b/WebCore/bindings/js/JSQuarantinedObjectWrapper.cpp @@ -56,7 +56,7 @@ JSValue JSQuarantinedObjectWrapper::cachedValueGetter(ExecState*, const Identifi return v; } -JSQuarantinedObjectWrapper::JSQuarantinedObjectWrapper(ExecState* unwrappedExec, JSObject* unwrappedObject, PassRefPtr<Structure> structure) +JSQuarantinedObjectWrapper::JSQuarantinedObjectWrapper(ExecState* unwrappedExec, JSObject* unwrappedObject, NonNullPassRefPtr<Structure> structure) : JSObject(structure) , m_unwrappedGlobalObject(unwrappedExec->lexicalGlobalObject()) , m_unwrappedObject(unwrappedObject) @@ -138,6 +138,26 @@ bool JSQuarantinedObjectWrapper::getOwnPropertySlot(ExecState* exec, unsigned id return result; } +bool JSQuarantinedObjectWrapper::getOwnPropertyDescriptor(ExecState* exec, const Identifier& identifier, PropertyDescriptor& descriptor) +{ + if (!allowsGetProperty()) { + descriptor.setUndefined(); + return true; + } + + PropertyDescriptor unwrappedDescriptor; + bool result = m_unwrappedObject->getOwnPropertyDescriptor(unwrappedExecState(), identifier, unwrappedDescriptor); + + if (unwrappedDescriptor.isAccessorDescriptor()) { + descriptor.setAccessorDescriptor(wrapOutgoingValue(unwrappedExecState(), unwrappedDescriptor.getter()), + wrapOutgoingValue(unwrappedExecState(), unwrappedDescriptor.setter()), + unwrappedDescriptor.attributes()); + } else + descriptor.setDescriptor(wrapOutgoingValue(unwrappedExecState(), unwrappedDescriptor.value()), unwrappedDescriptor.attributes()); + transferExceptionToExecState(exec); + return result; +} + void JSQuarantinedObjectWrapper::put(ExecState* exec, const Identifier& identifier, JSValue value, PutPropertySlot& slot) { if (!allowsSetProperty()) @@ -158,6 +178,33 @@ void JSQuarantinedObjectWrapper::put(ExecState* exec, unsigned identifier, JSVal transferExceptionToExecState(exec); } +bool JSQuarantinedObjectWrapper::defineOwnProperty(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool shouldThrow) +{ + if (!allowsSetProperty()) + return false; + + PropertyDescriptor wrappedDescriptor; + if (descriptor.isDataDescriptor()) { + wrappedDescriptor.setValue(prepareIncomingValue(exec, descriptor.value())); + if (wrappedDescriptor.writablePresent()) + wrappedDescriptor.setWritable(descriptor.writable()); + } else if (descriptor.isAccessorDescriptor()) { + if (descriptor.getter()) + wrappedDescriptor.setGetter(prepareIncomingValue(exec, descriptor.getter())); + if (descriptor.setter()) + wrappedDescriptor.setSetter(prepareIncomingValue(exec, descriptor.setter())); + } + if (wrappedDescriptor.enumerablePresent()) + wrappedDescriptor.setEnumerable(descriptor.enumerable()); + if (wrappedDescriptor.configurablePresent()) + wrappedDescriptor.setConfigurable(descriptor.configurable()); + + bool result = m_unwrappedObject->defineOwnProperty(unwrappedExecState(), propertyName, wrappedDescriptor, shouldThrow); + + transferExceptionToExecState(exec); + return result; +} + bool JSQuarantinedObjectWrapper::deleteProperty(ExecState* exec, const Identifier& identifier) { if (!allowsDeleteProperty()) @@ -270,8 +317,16 @@ void JSQuarantinedObjectWrapper::getPropertyNames(ExecState*, PropertyNameArray& { if (!allowsGetPropertyNames()) return; - + m_unwrappedObject->getPropertyNames(unwrappedExecState(), array); } +void JSQuarantinedObjectWrapper::getOwnPropertyNames(ExecState*, PropertyNameArray& array) +{ + if (!allowsGetPropertyNames()) + return; + + m_unwrappedObject->getOwnPropertyNames(unwrappedExecState(), array); +} + } // namespace WebCore diff --git a/WebCore/bindings/js/JSQuarantinedObjectWrapper.h b/WebCore/bindings/js/JSQuarantinedObjectWrapper.h index 08935e7..94a92bd 100644 --- a/WebCore/bindings/js/JSQuarantinedObjectWrapper.h +++ b/WebCore/bindings/js/JSQuarantinedObjectWrapper.h @@ -51,16 +51,18 @@ namespace WebCore { } protected: - JSQuarantinedObjectWrapper(JSC::ExecState* unwrappedExec, JSC::JSObject* unwrappedObject, PassRefPtr<JSC::Structure>); + JSQuarantinedObjectWrapper(JSC::ExecState* unwrappedExec, JSC::JSObject* unwrappedObject, NonNullPassRefPtr<JSC::Structure>); virtual void markChildren(JSC::MarkStack&); private: virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier&, JSC::PropertySlot&); virtual bool getOwnPropertySlot(JSC::ExecState*, unsigned, JSC::PropertySlot&); + virtual bool getOwnPropertyDescriptor(JSC::ExecState*, const JSC::Identifier&, JSC::PropertyDescriptor&); virtual void put(JSC::ExecState*, const JSC::Identifier&, JSC::JSValue, JSC::PutPropertySlot&); virtual void put(JSC::ExecState*, unsigned, JSC::JSValue); + virtual bool defineOwnProperty(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertyDescriptor&, bool shouldThrow); virtual bool deleteProperty(JSC::ExecState*, const JSC::Identifier&); virtual bool deleteProperty(JSC::ExecState*, unsigned); @@ -69,8 +71,9 @@ namespace WebCore { virtual JSC::ConstructType getConstructData(JSC::ConstructData&); virtual bool hasInstance(JSC::ExecState*, JSC::JSValue, JSC::JSValue proto); - + virtual void getPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&); + virtual void getOwnPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&); virtual JSC::UString className() const { return m_unwrappedObject->className(); } diff --git a/WebCore/bindings/js/JSSQLTransactionCustom.cpp b/WebCore/bindings/js/JSSQLTransactionCustom.cpp index dbe8e3c..e022401 100644 --- a/WebCore/bindings/js/JSSQLTransactionCustom.cpp +++ b/WebCore/bindings/js/JSSQLTransactionCustom.cpp @@ -95,8 +95,7 @@ JSValue JSSQLTransaction::executeSql(ExecState* exec, const ArgList& args) return jsUndefined(); } - if (Frame* frame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame()) - callback = JSCustomSQLStatementCallback::create(object, frame); + callback = JSCustomSQLStatementCallback::create(object, static_cast<JSDOMGlobalObject*>(exec->dynamicGlobalObject())); } RefPtr<SQLStatementErrorCallback> errorCallback; @@ -107,8 +106,7 @@ JSValue JSSQLTransaction::executeSql(ExecState* exec, const ArgList& args) return jsUndefined(); } - if (Frame* frame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame()) - errorCallback = JSCustomSQLStatementErrorCallback::create(object, frame); + errorCallback = JSCustomSQLStatementErrorCallback::create(object, static_cast<JSDOMGlobalObject*>(exec->dynamicGlobalObject())); } ExceptionCode ec = 0; diff --git a/WebCore/bindings/js/JSSVGElementInstanceCustom.cpp b/WebCore/bindings/js/JSSVGElementInstanceCustom.cpp index 6e77f9b..571e302 100644 --- a/WebCore/bindings/js/JSSVGElementInstanceCustom.cpp +++ b/WebCore/bindings/js/JSSVGElementInstanceCustom.cpp @@ -54,9 +54,11 @@ JSValue JSSVGElementInstance::addEventListener(ExecState* exec, const ArgList& a if (!globalObject) return jsUndefined(); - if (RefPtr<JSEventListener> listener = globalObject->findOrCreateJSEventListener(args.at(1))) - impl()->addEventListener(args.at(0).toString(exec), listener.release(), args.at(2).toBoolean(exec)); + JSValue listener = args.at(1); + if (!listener.isObject()) + return jsUndefined(); + impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false), args.at(2).toBoolean(exec)); return jsUndefined(); } @@ -66,9 +68,11 @@ JSValue JSSVGElementInstance::removeEventListener(ExecState* exec, const ArgList if (!globalObject) return jsUndefined(); - if (JSEventListener* listener = globalObject->findJSEventListener(args.at(1))) - impl()->removeEventListener(args.at(0).toString(exec), listener, args.at(2).toBoolean(exec)); + JSValue listener = args.at(1); + if (!listener.isObject()) + return jsUndefined(); + impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec)); return jsUndefined(); } diff --git a/WebCore/bindings/js/JSSharedWorkerConstructor.cpp b/WebCore/bindings/js/JSSharedWorkerConstructor.cpp index e2f1136..c05b3d2 100644 --- a/WebCore/bindings/js/JSSharedWorkerConstructor.cpp +++ b/WebCore/bindings/js/JSSharedWorkerConstructor.cpp @@ -37,6 +37,7 @@ #include "JSDOMWindowCustom.h" #include "JSSharedWorker.h" #include "SharedWorker.h" +#include <runtime/Error.h> using namespace JSC; @@ -56,11 +57,14 @@ static JSObject* constructSharedWorker(ExecState* exec, JSObject* constructor, c { JSSharedWorkerConstructor* jsConstructor = static_cast<JSSharedWorkerConstructor*>(constructor); - if (args.size() < 2) + if (args.size() < 1) return throwError(exec, SyntaxError, "Not enough arguments"); UString scriptURL = args.at(0).toString(exec); - UString name = args.at(1).toString(exec); + UString name; + if (args.size() > 1) + name = args.at(1).toString(exec); + if (exec->hadException()) return 0; diff --git a/WebCore/bindings/js/JSStorageCustom.cpp b/WebCore/bindings/js/JSStorageCustom.cpp index 07cf2f8..e416d35 100644 --- a/WebCore/bindings/js/JSStorageCustom.cpp +++ b/WebCore/bindings/js/JSStorageCustom.cpp @@ -64,13 +64,13 @@ bool JSStorage::deleteProperty(ExecState* exec, const Identifier& propertyName) return true; } -void JSStorage::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +void JSStorage::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) { unsigned length = m_impl->length(); for (unsigned i = 0; i < length; ++i) propertyNames.add(Identifier(exec, m_impl->key(i))); - Base::getPropertyNames(exec, propertyNames); + Base::getOwnPropertyNames(exec, propertyNames); } bool JSStorage::putDelegate(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot&) diff --git a/WebCore/bindings/js/JSStyleSheetCustom.cpp b/WebCore/bindings/js/JSStyleSheetCustom.cpp index 43249dc..d711b6f 100644 --- a/WebCore/bindings/js/JSStyleSheetCustom.cpp +++ b/WebCore/bindings/js/JSStyleSheetCustom.cpp @@ -56,12 +56,19 @@ void JSStyleSheet::markChildren(MarkStack& markStack) { Base::markChildren(markStack); + StyleSheet* sheet = impl(); + JSGlobalData& globalData = *Heap::heap(this)->globalData(); + + unsigned length = sheet->length(); + for (unsigned i = 0; i < length; ++i) + markDOMObjectWrapper(markStack, globalData, sheet->item(i)); + // This prevents us from having a style sheet with a dangling ownerNode pointer. // A better solution would be to handle this on the DOM side -- if the style sheet // is kept around, then we want the node to stay around too. One possibility would // be to make ref/deref on the style sheet ref/deref the node instead, but there's // a lot of disentangling of the CSS DOM objects that would need to happen first. - if (Node* ownerNode = impl()->ownerNode()) { + if (Node* ownerNode = sheet->ownerNode()) { if (JSNode* ownerNodeWrapper = getCachedDOMNodeWrapper(ownerNode->document(), ownerNode)) markStack.append(ownerNodeWrapper); } diff --git a/WebCore/bindings/js/JSStyleSheetListCustom.cpp b/WebCore/bindings/js/JSStyleSheetListCustom.cpp index 1da6418..7bf9389 100644 --- a/WebCore/bindings/js/JSStyleSheetListCustom.cpp +++ b/WebCore/bindings/js/JSStyleSheetListCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,6 +35,18 @@ using namespace JSC; namespace WebCore { +void JSStyleSheetList::markChildren(MarkStack& markStack) +{ + Base::markChildren(markStack); + + StyleSheetList* list = impl(); + JSGlobalData& globalData = *Heap::heap(this)->globalData(); + + unsigned length = list->length(); + for (unsigned i = 0; i < length; ++i) + markDOMObjectWrapper(markStack, globalData, list->item(i)); +} + bool JSStyleSheetList::canGetItemsForName(ExecState*, StyleSheetList* styleSheetList, const Identifier& propertyName) { return styleSheetList->getNamedItem(propertyName); diff --git a/WebCore/bindings/js/JSWebSocketConstructor.cpp b/WebCore/bindings/js/JSWebSocketConstructor.cpp index ca2e104..5b34765 100644 --- a/WebCore/bindings/js/JSWebSocketConstructor.cpp +++ b/WebCore/bindings/js/JSWebSocketConstructor.cpp @@ -37,6 +37,7 @@ #include "JSWebSocket.h" #include "ScriptExecutionContext.h" #include "WebSocket.h" +#include <runtime/Error.h> using namespace JSC; diff --git a/WebCore/bindings/js/JSWebSocketCustom.cpp b/WebCore/bindings/js/JSWebSocketCustom.cpp index 3aa4b8b..d305502 100644 --- a/WebCore/bindings/js/JSWebSocketCustom.cpp +++ b/WebCore/bindings/js/JSWebSocketCustom.cpp @@ -38,19 +38,12 @@ #include "KURL.h" #include "WebSocket.h" #include "NotImplemented.h" +#include <runtime/Error.h> using namespace JSC; namespace WebCore { -void JSWebSocket::markChildren(MarkStack& markStack) -{ - Base::markChildren(markStack); - if (m_impl->readyState() != WebSocket::CLOSED) - markIfNotNull(markStack, m_impl->onmessage()); - // FIXME: mark if EventListeners is registered. -} - // Custom functions JSValue JSWebSocket::send(ExecState* exec, const ArgList& args) { diff --git a/WebCore/bindings/js/JSWorkerConstructor.cpp b/WebCore/bindings/js/JSWorkerConstructor.cpp index 9943cfb..69c05e7 100644 --- a/WebCore/bindings/js/JSWorkerConstructor.cpp +++ b/WebCore/bindings/js/JSWorkerConstructor.cpp @@ -34,6 +34,7 @@ #include "JSDOMWindowCustom.h" #include "JSWorker.h" #include "Worker.h" +#include <runtime/Error.h> using namespace JSC; diff --git a/WebCore/bindings/js/JSWorkerContextBase.cpp b/WebCore/bindings/js/JSWorkerContextBase.cpp index 1e4df42..741a269 100644 --- a/WebCore/bindings/js/JSWorkerContextBase.cpp +++ b/WebCore/bindings/js/JSWorkerContextBase.cpp @@ -44,7 +44,7 @@ ASSERT_CLASS_FITS_IN_CELL(JSWorkerContextBase); const ClassInfo JSWorkerContextBase::s_info = { "WorkerContext", 0, 0, 0 }; -JSWorkerContextBase::JSWorkerContextBase(PassRefPtr<JSC::Structure> structure, PassRefPtr<WorkerContext> impl) +JSWorkerContextBase::JSWorkerContextBase(NonNullPassRefPtr<JSC::Structure> structure, PassRefPtr<WorkerContext> impl) : JSDOMGlobalObject(structure, new JSDOMGlobalObjectData, this) , m_impl(impl) { diff --git a/WebCore/bindings/js/JSWorkerContextBase.h b/WebCore/bindings/js/JSWorkerContextBase.h index a9a6e63..45238f1 100644 --- a/WebCore/bindings/js/JSWorkerContextBase.h +++ b/WebCore/bindings/js/JSWorkerContextBase.h @@ -41,7 +41,7 @@ namespace WebCore { class JSWorkerContextBase : public JSDOMGlobalObject { typedef JSDOMGlobalObject Base; public: - JSWorkerContextBase(PassRefPtr<JSC::Structure>, PassRefPtr<WorkerContext>); + JSWorkerContextBase(NonNullPassRefPtr<JSC::Structure>, PassRefPtr<WorkerContext>); virtual ~JSWorkerContextBase(); virtual const JSC::ClassInfo* classInfo() const { return &s_info; } diff --git a/WebCore/bindings/js/JSWorkerContextCustom.cpp b/WebCore/bindings/js/JSWorkerContextCustom.cpp index 919c81f..e1c8a8c 100644 --- a/WebCore/bindings/js/JSWorkerContextCustom.cpp +++ b/WebCore/bindings/js/JSWorkerContextCustom.cpp @@ -43,6 +43,10 @@ #include "WorkerNavigator.h" #include <interpreter/Interpreter.h> +#if ENABLE(EVENTSOURCE) +#include "JSEventSourceConstructor.h" +#endif + using namespace JSC; namespace WebCore { @@ -58,15 +62,7 @@ void JSWorkerContext::markChildren(MarkStack& markStack) markDOMObjectWrapper(markStack, globalData, impl()->optionalLocation()); markDOMObjectWrapper(markStack, globalData, impl()->optionalNavigator()); - markIfNotNull(markStack, impl()->onerror()); - - typedef WorkerContext::EventListenersMap EventListenersMap; - typedef WorkerContext::ListenerVector ListenerVector; - EventListenersMap& eventListeners = impl()->eventListeners(); - for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) { - for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter) - (*vecIter)->markJSFunction(markStack); - } + impl()->markEventListeners(markStack); } bool JSWorkerContext::getOwnPropertySlotDelegate(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) @@ -77,6 +73,21 @@ bool JSWorkerContext::getOwnPropertySlotDelegate(ExecState* exec, const Identifi return false; } +bool JSWorkerContext::getOwnPropertyDescriptorDelegate(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + // Look for overrides before looking at any of our own properties. + if (JSGlobalObject::getOwnPropertyDescriptor(exec, propertyName, descriptor)) + return true; + return false; +} + +#if ENABLE(EVENTSOURCE) +JSValue JSWorkerContext::eventSource(ExecState* exec) const +{ + return getDOMConstructor<JSEventSourceConstructor>(exec, this); +} +#endif + JSValue JSWorkerContext::xmlHttpRequest(ExecState* exec) const { return getDOMConstructor<JSXMLHttpRequestConstructor>(exec, this); @@ -107,19 +118,21 @@ JSValue JSWorkerContext::importScripts(ExecState* exec, const ArgList& args) JSValue JSWorkerContext::addEventListener(ExecState* exec, const ArgList& args) { - RefPtr<JSEventListener> listener = findOrCreateJSEventListener(args.at(1)); - if (!listener) + JSValue listener = args.at(1); + if (!listener.isObject()) return jsUndefined(); - impl()->addEventListener(args.at(0).toString(exec), listener.release(), args.at(2).toBoolean(exec)); + + impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false), args.at(2).toBoolean(exec)); return jsUndefined(); } JSValue JSWorkerContext::removeEventListener(ExecState* exec, const ArgList& args) { - JSEventListener* listener = findJSEventListener(args.at(1)); - if (!listener) + JSValue listener = args.at(1); + if (!listener.isObject()) return jsUndefined(); - impl()->removeEventListener(args.at(0).toString(exec), listener, args.at(2).toBoolean(exec)); + + impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec)); return jsUndefined(); } diff --git a/WebCore/bindings/js/JSWorkerCustom.cpp b/WebCore/bindings/js/JSWorkerCustom.cpp index f5c394b..09b881a 100644 --- a/WebCore/bindings/js/JSWorkerCustom.cpp +++ b/WebCore/bindings/js/JSWorkerCustom.cpp @@ -30,17 +30,16 @@ #include "JSWorker.h" #include "JSDOMGlobalObject.h" +#include "JSMessagePortCustom.h" #include "Worker.h" using namespace JSC; namespace WebCore { - -void JSWorker::markChildren(MarkStack& markStack) -{ - Base::markChildren(markStack); - markIfNotNull(markStack, static_cast<Worker*>(impl())->onmessage()); +JSC::JSValue JSWorker::postMessage(JSC::ExecState* exec, const JSC::ArgList& args) +{ + return handlePostMessage(exec, args, impl()); } } // namespace WebCore diff --git a/WebCore/bindings/js/JSXMLHttpRequestConstructor.cpp b/WebCore/bindings/js/JSXMLHttpRequestConstructor.cpp index a644c9e..91fff9a 100644 --- a/WebCore/bindings/js/JSXMLHttpRequestConstructor.cpp +++ b/WebCore/bindings/js/JSXMLHttpRequestConstructor.cpp @@ -23,6 +23,7 @@ #include "JSXMLHttpRequest.h" #include "ScriptExecutionContext.h" #include "XMLHttpRequest.h" +#include <runtime/Error.h> using namespace JSC; diff --git a/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp b/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp index a591fae..4b44db2 100644 --- a/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp +++ b/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp @@ -59,20 +59,7 @@ void JSXMLHttpRequest::markChildren(MarkStack& markStack) markStack.append(wrapper); } - markIfNotNull(markStack, m_impl->onreadystatechange()); - markIfNotNull(markStack, m_impl->onabort()); - markIfNotNull(markStack, m_impl->onerror()); - markIfNotNull(markStack, m_impl->onload()); - markIfNotNull(markStack, m_impl->onloadstart()); - markIfNotNull(markStack, m_impl->onprogress()); - - typedef XMLHttpRequest::EventListenersMap EventListenersMap; - typedef XMLHttpRequest::ListenerVector ListenerVector; - EventListenersMap& eventListeners = m_impl->eventListeners(); - for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) { - for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter) - (*vecIter)->markJSFunction(markStack); - } + m_impl->markEventListeners(markStack); } // Custom functions @@ -123,9 +110,9 @@ JSValue JSXMLHttpRequest::send(ExecState* exec, const ArgList& args) JSValue val = args.at(0); if (val.isUndefinedOrNull()) impl()->send(ec); - else if (val.isObject(&JSDocument::s_info)) + else if (val.inherits(&JSDocument::s_info)) impl()->send(toDocument(val), ec); - else if (val.isObject(&JSFile::s_info)) + else if (val.inherits(&JSFile::s_info)) impl()->send(toFile(val), ec); else impl()->send(val.toString(exec), ec); @@ -168,10 +155,12 @@ JSValue JSXMLHttpRequest::addEventListener(ExecState* exec, const ArgList& args) JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext()); if (!globalObject) return jsUndefined(); - RefPtr<JSEventListener> listener = globalObject->findOrCreateJSEventListener(args.at(1)); - if (!listener) + + JSValue listener = args.at(1); + if (!listener.isObject()) return jsUndefined(); - impl()->addEventListener(args.at(0).toString(exec), listener.release(), args.at(2).toBoolean(exec)); + + impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false), args.at(2).toBoolean(exec)); return jsUndefined(); } @@ -180,10 +169,12 @@ JSValue JSXMLHttpRequest::removeEventListener(ExecState* exec, const ArgList& ar JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext()); if (!globalObject) return jsUndefined(); - JSEventListener* listener = globalObject->findJSEventListener(args.at(1)); - if (!listener) + + JSValue listener = args.at(1); + if (!listener.isObject()) return jsUndefined(); - impl()->removeEventListener(args.at(0).toString(exec), listener, args.at(2).toBoolean(exec)); + + impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec)); return jsUndefined(); } diff --git a/WebCore/bindings/js/JSXMLHttpRequestUploadCustom.cpp b/WebCore/bindings/js/JSXMLHttpRequestUploadCustom.cpp index cb6d5f2..dab0a3e 100644 --- a/WebCore/bindings/js/JSXMLHttpRequestUploadCustom.cpp +++ b/WebCore/bindings/js/JSXMLHttpRequestUploadCustom.cpp @@ -51,19 +51,7 @@ void JSXMLHttpRequestUpload::markChildren(MarkStack& markStack) markStack.append(wrapper); } - markIfNotNull(markStack, m_impl->onabort()); - markIfNotNull(markStack, m_impl->onerror()); - markIfNotNull(markStack, m_impl->onload()); - markIfNotNull(markStack, m_impl->onloadstart()); - markIfNotNull(markStack, m_impl->onprogress()); - - typedef XMLHttpRequestUpload::EventListenersMap EventListenersMap; - typedef XMLHttpRequestUpload::ListenerVector ListenerVector; - EventListenersMap& eventListeners = m_impl->eventListeners(); - for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) { - for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter) - (*vecIter)->markJSFunction(markStack); - } + m_impl->markEventListeners(markStack); } JSValue JSXMLHttpRequestUpload::addEventListener(ExecState* exec, const ArgList& args) @@ -71,10 +59,12 @@ JSValue JSXMLHttpRequestUpload::addEventListener(ExecState* exec, const ArgList& JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext()); if (!globalObject) return jsUndefined(); - RefPtr<JSEventListener> listener = globalObject->findOrCreateJSEventListener(args.at(1)); - if (!listener) + + JSValue listener = args.at(1); + if (!listener.isObject()) return jsUndefined(); - impl()->addEventListener(args.at(0).toString(exec), listener.release(), args.at(2).toBoolean(exec)); + + impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false), args.at(2).toBoolean(exec)); return jsUndefined(); } @@ -83,10 +73,12 @@ JSValue JSXMLHttpRequestUpload::removeEventListener(ExecState* exec, const ArgLi JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext()); if (!globalObject) return jsUndefined(); - JSEventListener* listener = globalObject->findJSEventListener(args.at(1)); - if (!listener) + + JSValue listener = args.at(1); + if (!listener.isObject()) return jsUndefined(); - impl()->removeEventListener(args.at(0).toString(exec), listener, args.at(2).toBoolean(exec)); + + impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec)); return jsUndefined(); } diff --git a/WebCore/bindings/js/JSXSLTProcessorCustom.cpp b/WebCore/bindings/js/JSXSLTProcessorCustom.cpp index 01e53a6..441bbc9 100644 --- a/WebCore/bindings/js/JSXSLTProcessorCustom.cpp +++ b/WebCore/bindings/js/JSXSLTProcessorCustom.cpp @@ -49,7 +49,7 @@ namespace WebCore { JSValue JSXSLTProcessor::importStylesheet(ExecState*, const ArgList& args) { JSValue nodeVal = args.at(0); - if (nodeVal.isObject(&JSNode::s_info)) { + if (nodeVal.inherits(&JSNode::s_info)) { JSNode* node = static_cast<JSNode*>(asObject(nodeVal)); impl()->importStylesheet(node->impl()); return jsUndefined(); @@ -62,7 +62,7 @@ JSValue JSXSLTProcessor::transformToFragment(ExecState* exec, const ArgList& arg { JSValue nodeVal = args.at(0); JSValue docVal = args.at(1); - if (nodeVal.isObject(&JSNode::s_info) && docVal.isObject(&JSDocument::s_info)) { + if (nodeVal.inherits(&JSNode::s_info) && docVal.inherits(&JSDocument::s_info)) { WebCore::Node* node = static_cast<JSNode*>(asObject(nodeVal))->impl(); Document* doc = static_cast<Document*>(static_cast<JSDocument*>(asObject(docVal))->impl()); return toJS(exec, impl()->transformToFragment(node, doc).get()); @@ -74,7 +74,7 @@ JSValue JSXSLTProcessor::transformToFragment(ExecState* exec, const ArgList& arg JSValue JSXSLTProcessor::transformToDocument(ExecState* exec, const ArgList& args) { JSValue nodeVal = args.at(0); - if (nodeVal.isObject(&JSNode::s_info)) { + if (nodeVal.inherits(&JSNode::s_info)) { JSNode* node = static_cast<JSNode*>(asObject(nodeVal)); RefPtr<Document> resultDocument = impl()->transformToDocument(node->impl()); if (resultDocument) diff --git a/WebCore/bindings/js/ScriptCachedFrameData.cpp b/WebCore/bindings/js/ScriptCachedFrameData.cpp index 8852611..77b8ca4 100644 --- a/WebCore/bindings/js/ScriptCachedFrameData.cpp +++ b/WebCore/bindings/js/ScriptCachedFrameData.cpp @@ -86,7 +86,7 @@ void ScriptCachedFrameData::clear() { JSLock lock(SilenceAssertionsOnly); - if (!m_window) { + if (m_window) { m_window = 0; gcController().garbageCollectSoon(); } diff --git a/WebCore/bindings/js/ScriptCallFrame.cpp b/WebCore/bindings/js/ScriptCallFrame.cpp index 58168d0..09752d1 100644 --- a/WebCore/bindings/js/ScriptCallFrame.cpp +++ b/WebCore/bindings/js/ScriptCallFrame.cpp @@ -40,7 +40,7 @@ namespace WebCore { ScriptCallFrame::ScriptCallFrame(const UString& functionName, const UString& urlString, int lineNumber, const ArgList& args, unsigned skipArgumentCount) : m_functionName(functionName) - , m_sourceURL(urlString) + , m_sourceURL(ParsedURLString, urlString) , m_lineNumber(lineNumber) { size_t argumentCount = args.size(); diff --git a/WebCore/bindings/js/ScriptController.cpp b/WebCore/bindings/js/ScriptController.cpp index 8908155..45f8c75 100644 --- a/WebCore/bindings/js/ScriptController.cpp +++ b/WebCore/bindings/js/ScriptController.cpp @@ -33,16 +33,23 @@ #include "ScriptSourceCode.h" #include "ScriptValue.h" #include "Settings.h" +#include "StorageNamespace.h" #include "XSSAuditor.h" #include "npruntime_impl.h" #include "runtime_root.h" #include <debugger/Debugger.h> +#include <runtime/InitializeThreading.h> #include <runtime/JSLock.h> using namespace JSC; namespace WebCore { +void ScriptController::initializeThreading() +{ + JSC::initializeThreading(); +} + ScriptController::ScriptController(Frame* frame) : m_frame(frame) , m_handlerLineNumber(0) @@ -84,12 +91,7 @@ ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode) const SourceCode& jsSourceCode = sourceCode.jsSourceCode(); String sourceURL = jsSourceCode.provider()->url(); - if (sourceURL.isNull() && !m_XSSAuditor->canEvaluateJavaScriptURL(sourceCode.source())) { - // This JavaScript URL is not safe to be evaluated. - return JSValue(); - } - - if (!sourceURL.isNull() && !m_XSSAuditor->canEvaluate(sourceCode.source())) { + if (!m_XSSAuditor->canEvaluate(sourceCode.source())) { // This script is not safe to be evaluated. return JSValue(); } @@ -130,6 +132,14 @@ ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode) return JSValue(); } +void ScriptController::evaluateInIsolatedWorld(unsigned /* worldID */, const Vector<ScriptSourceCode>& sourceCode) +{ + // FIXME: Actually support isolated worlds! + unsigned size = sourceCode.size(); + for (unsigned i = 0; i < size; ++i) + evaluate(sourceCode[i]); +} + void ScriptController::clearWindowShell() { if (!m_windowShell) diff --git a/WebCore/bindings/js/ScriptController.h b/WebCore/bindings/js/ScriptController.h index 4528495..9ae10fb 100644 --- a/WebCore/bindings/js/ScriptController.h +++ b/WebCore/bindings/js/ScriptController.h @@ -80,7 +80,12 @@ public: return m_windowShell->window(); } + // This function must be called from the main thread. It is safe to call it repeatedly. + // Darwin is an exception to this rule: it is OK to call this function from any thread, even reentrantly. + static void initializeThreading(); + ScriptValue evaluate(const ScriptSourceCode&); + void evaluateInIsolatedWorld(unsigned worldID, const Vector<ScriptSourceCode>&); void setEventHandlerLineNumber(int lineno) { m_handlerLineNumber = lineno; } int eventHandlerLineNumber() { return m_handlerLineNumber; } diff --git a/WebCore/bindings/js/ScriptControllerHaiku.cpp b/WebCore/bindings/js/ScriptControllerHaiku.cpp index b573b97..3fe471d 100644 --- a/WebCore/bindings/js/ScriptControllerHaiku.cpp +++ b/WebCore/bindings/js/ScriptControllerHaiku.cpp @@ -28,8 +28,8 @@ #include "ScriptController.h" #include "PluginView.h" -#include "runtime_root.h" #include "runtime.h" +#include "runtime_root.h" namespace WebCore { diff --git a/WebCore/bindings/js/ScriptEventListener.cpp b/WebCore/bindings/js/ScriptEventListener.cpp index 878c535..0b0047b 100644 --- a/WebCore/bindings/js/ScriptEventListener.cpp +++ b/WebCore/bindings/js/ScriptEventListener.cpp @@ -33,12 +33,11 @@ #include "Attribute.h" #include "Document.h" +#include "EventListener.h" #include "JSNode.h" #include "Frame.h" #include "XSSAuditor.h" -#include <runtime/JSLock.h> - using namespace JSC; namespace WebCore { @@ -54,29 +53,25 @@ PassRefPtr<JSLazyEventListener> createAttributeEventListener(Node* node, Attribu { ASSERT(node); - Frame* frame = node->document()->frame(); - if (!frame) - return 0; - - ScriptController* scriptController = frame->script(); - if (!scriptController->isEnabled()) - return 0; - - if (!scriptController->xssAuditor()->canCreateInlineEventListener(attr->localName().string(), attr->value())) { - // This script is not safe to execute. - return 0; - } + int lineNumber = 1; + String sourceURL; - JSDOMWindow* globalObject = scriptController->globalObject(); - - // Ensure that 'node' has a JavaScript wrapper to mark the event listener we're creating. - { - JSLock lock(SilenceAssertionsOnly); - // FIXME: Should pass the global object associated with the node - toJS(globalObject->globalExec(), globalObject, node); + // FIXME: We should be able to provide accurate source information for frameless documents, too (e.g. for importing nodes from XMLHttpRequest.responseXML). + if (Frame* frame = node->document()->frame()) { + ScriptController* scriptController = frame->script(); + if (!scriptController->isEnabled()) + return 0; + + if (!scriptController->xssAuditor()->canCreateInlineEventListener(attr->localName().string(), attr->value())) { + // This script is not safe to execute. + return 0; + } + + lineNumber = scriptController->eventHandlerLineNumber(); + sourceURL = node->document()->url().string(); } - return JSLazyEventListener::create(attr->localName().string(), eventParameterName(node->isSVGElement()), attr->value(), globalObject, node, scriptController->eventHandlerLineNumber()); + return JSLazyEventListener::create(attr->localName().string(), eventParameterName(node->isSVGElement()), attr->value(), node, sourceURL, lineNumber); } PassRefPtr<JSLazyEventListener> createAttributeEventListener(Frame* frame, Attribute* attr) @@ -84,19 +79,29 @@ PassRefPtr<JSLazyEventListener> createAttributeEventListener(Frame* frame, Attri if (!frame) return 0; + int lineNumber = 1; + String sourceURL; + ScriptController* scriptController = frame->script(); if (!scriptController->isEnabled()) return 0; - + if (!scriptController->xssAuditor()->canCreateInlineEventListener(attr->localName().string(), attr->value())) { // This script is not safe to execute. return 0; } - // 'globalObject' is the JavaScript wrapper that will mark the event listener we're creating. - JSDOMWindow* globalObject = scriptController->globalObject(); + lineNumber = scriptController->eventHandlerLineNumber(); + sourceURL = frame->document()->url().string(); + return JSLazyEventListener::create(attr->localName().string(), eventParameterName(frame->document()->isSVGDocument()), attr->value(), 0, sourceURL, lineNumber); +} - return JSLazyEventListener::create(attr->localName().string(), eventParameterName(frame->document()->isSVGDocument()), attr->value(), globalObject, 0, scriptController->eventHandlerLineNumber()); +String getEventListenerHandlerBody(ScriptExecutionContext* context, ScriptState* scriptState, EventListener* eventListener) +{ + JSC::JSObject* functionObject = eventListener->jsFunction(context); + if (!functionObject) + return ""; + return functionObject->toString(scriptState); } } // namespace WebCore diff --git a/WebCore/bindings/js/ScriptEventListener.h b/WebCore/bindings/js/ScriptEventListener.h index 8299d29..3396541 100644 --- a/WebCore/bindings/js/ScriptEventListener.h +++ b/WebCore/bindings/js/ScriptEventListener.h @@ -32,17 +32,20 @@ #define ScriptEventListener_h #include "JSLazyEventListener.h" +#include "ScriptState.h" #include <wtf/PassRefPtr.h> namespace WebCore { class Attribute; + class EventListener; class Frame; class Node; PassRefPtr<JSLazyEventListener> createAttributeEventListener(Node*, Attribute*); PassRefPtr<JSLazyEventListener> createAttributeEventListener(Frame*, Attribute*); + String getEventListenerHandlerBody(ScriptExecutionContext*, ScriptState*, EventListener*); } // namespace WebCore diff --git a/WebCore/bindings/js/ScriptObject.cpp b/WebCore/bindings/js/ScriptObject.cpp index beadc4a..b69ef2b 100644 --- a/WebCore/bindings/js/ScriptObject.cpp +++ b/WebCore/bindings/js/ScriptObject.cpp @@ -106,6 +106,14 @@ bool ScriptObject::set(const char* name, int value) return handleException(m_scriptState); } +bool ScriptObject::set(const char* name, unsigned value) +{ + JSLock lock(SilenceAssertionsOnly); + PutPropertySlot slot; + jsObject()->put(m_scriptState, Identifier(m_scriptState, name), jsNumber(m_scriptState, value), slot); + return handleException(m_scriptState); +} + bool ScriptObject::set(const char* name, bool value) { JSLock lock(SilenceAssertionsOnly); @@ -128,6 +136,7 @@ bool ScriptGlobalObject::set(ScriptState* scriptState, const char* name, const S } #if ENABLE(JAVASCRIPT_DEBUGGER) +#if ENABLE(INSPECTOR) bool ScriptGlobalObject::set(ScriptState* scriptState, const char* name, InspectorBackend* value) { JSLock lock(SilenceAssertionsOnly); @@ -135,6 +144,7 @@ bool ScriptGlobalObject::set(ScriptState* scriptState, const char* name, Inspect globalObject->putDirect(Identifier(scriptState, name), toJS(scriptState, globalObject, value)); return handleException(scriptState); } +#endif // ENABLE(INSPECTOR) #endif bool ScriptGlobalObject::get(ScriptState* scriptState, const char* name, ScriptObject& value) diff --git a/WebCore/bindings/js/ScriptObject.h b/WebCore/bindings/js/ScriptObject.h index 50b63ad..31381f3 100644 --- a/WebCore/bindings/js/ScriptObject.h +++ b/WebCore/bindings/js/ScriptObject.h @@ -52,6 +52,7 @@ namespace WebCore { bool set(const char* name, double); bool set(const char* name, long long); bool set(const char* name, int); + bool set(const char* name, unsigned); bool set(const char* name, bool); static ScriptObject createNew(ScriptState*); @@ -63,7 +64,9 @@ namespace WebCore { class ScriptGlobalObject { public: static bool set(ScriptState*, const char* name, const ScriptObject&); +#if ENABLE(INSPECTOR) static bool set(ScriptState*, const char* name, InspectorBackend*); +#endif static bool get(ScriptState*, const char* name, ScriptObject&); static bool remove(ScriptState*, const char* name); private: diff --git a/WebCore/bindings/js/ScriptObjectQuarantine.cpp b/WebCore/bindings/js/ScriptObjectQuarantine.cpp index 89553ef..b48556e 100644 --- a/WebCore/bindings/js/ScriptObjectQuarantine.cpp +++ b/WebCore/bindings/js/ScriptObjectQuarantine.cpp @@ -31,6 +31,8 @@ #include "config.h" #include "ScriptObjectQuarantine.h" +#if ENABLE(INSPECTOR) + #include "Document.h" #include "Frame.h" #include "JSDOMBinding.h" @@ -38,6 +40,7 @@ #include "JSNode.h" #include "ScriptObject.h" #include "ScriptValue.h" +#include "Storage.h" #include <runtime/JSLock.h> @@ -80,10 +83,11 @@ bool getQuarantinedScriptObject(Database* database, ScriptObject& quarantinedObj #endif #if ENABLE(DOM_STORAGE) -bool getQuarantinedScriptObject(Frame* frame, Storage* storage, ScriptObject& quarantinedObject) +bool getQuarantinedScriptObject(Storage* storage, ScriptObject& quarantinedObject) { - ASSERT(frame); ASSERT(storage); + Frame* frame = storage->frame(); + ASSERT(frame); JSDOMGlobalObject* globalObject = toJSDOMWindow(frame); ExecState* exec = globalObject->globalExec(); @@ -123,3 +127,5 @@ bool getQuarantinedScriptObject(DOMWindow* domWindow, ScriptObject& quarantinedO } // namespace WebCore + +#endif // ENABLE(INSPECTOR) diff --git a/WebCore/bindings/js/ScriptObjectQuarantine.h b/WebCore/bindings/js/ScriptObjectQuarantine.h index d70acd7..df52379 100644 --- a/WebCore/bindings/js/ScriptObjectQuarantine.h +++ b/WebCore/bindings/js/ScriptObjectQuarantine.h @@ -37,7 +37,6 @@ namespace WebCore { class Database; class DOMWindow; - class Frame; class Node; class ScriptObject; class ScriptValue; @@ -49,7 +48,7 @@ namespace WebCore { bool getQuarantinedScriptObject(Database* database, ScriptObject& quarantinedObject); #endif #if ENABLE(DOM_STORAGE) - bool getQuarantinedScriptObject(Frame* frame, Storage* storage, ScriptObject& quarantinedObject); + bool getQuarantinedScriptObject(Storage* storage, ScriptObject& quarantinedObject); #endif bool getQuarantinedScriptObject(Node* node, ScriptObject& quarantinedObject); bool getQuarantinedScriptObject(DOMWindow* domWindow, ScriptObject& quarantinedObject); diff --git a/WebCore/bindings/js/ScriptValue.cpp b/WebCore/bindings/js/ScriptValue.cpp index d427cee..6eac102 100644 --- a/WebCore/bindings/js/ScriptValue.cpp +++ b/WebCore/bindings/js/ScriptValue.cpp @@ -74,4 +74,11 @@ bool ScriptValue::isUndefined() const return m_value.get().isUndefined(); } +bool ScriptValue::isObject() const +{ + if (!m_value) + return false; + return m_value.get().isObject(); +} + } // namespace WebCore diff --git a/WebCore/bindings/js/ScriptValue.h b/WebCore/bindings/js/ScriptValue.h index 209ce06..19bb693 100644 --- a/WebCore/bindings/js/ScriptValue.h +++ b/WebCore/bindings/js/ScriptValue.h @@ -50,6 +50,7 @@ public: bool isEqual(ScriptState*, const ScriptValue&) const; bool isNull() const; bool isUndefined() const; + bool isObject() const; bool hasNoValue() const { return m_value == JSC::JSValue(); } private: diff --git a/WebCore/bindings/js/SerializedScriptValue.cpp b/WebCore/bindings/js/SerializedScriptValue.cpp new file mode 100644 index 0000000..48cd92d --- /dev/null +++ b/WebCore/bindings/js/SerializedScriptValue.cpp @@ -0,0 +1,839 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "config.h" +#include "SerializedScriptValue.h" + +#include <runtime/DateInstance.h> +#include <runtime/ExceptionHelpers.h> +#include <runtime/PropertyNameArray.h> +#include <wtf/HashTraits.h> +#include <wtf/Vector.h> + +using namespace JSC; + +namespace WebCore { + +class SerializedObject : public SharedSerializedData +{ +public: + typedef Vector<RefPtr<StringImpl> > PropertyNameList; + typedef Vector<SerializedScriptValueData> ValueList; + + void set(const Identifier& propertyName, const SerializedScriptValueData& value) + { + ASSERT(m_names.size() == m_values.size()); + m_names.append(String(propertyName.ustring()).crossThreadString().impl()); + m_values.append(value); + } + + PropertyNameList& names() { return m_names; } + + ValueList& values() { return m_values; } + + static PassRefPtr<SerializedObject> create() + { + return adoptRef(new SerializedObject); + } + + void clear() + { + m_names.clear(); + m_values.clear(); + } + +private: + SerializedObject() { } + PropertyNameList m_names; + ValueList m_values; +}; + +class SerializedArray : public SharedSerializedData +{ + typedef HashMap<unsigned, SerializedScriptValueData, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned> > SparseMap; +public: + void setIndex(unsigned index, const SerializedScriptValueData& value) + { + ASSERT(index < m_length); + if (index == m_compactStorage.size()) + m_compactStorage.append(value); + else + m_sparseStorage.set(index, value); + } + + bool canDoFastRead(unsigned index) const + { + ASSERT(index < m_length); + return index < m_compactStorage.size(); + } + + const SerializedScriptValueData& getIndex(unsigned index) + { + ASSERT(index < m_compactStorage.size()); + return m_compactStorage[index]; + } + + SerializedScriptValueData getSparseIndex(unsigned index, bool& hasIndex) + { + ASSERT(index >= m_compactStorage.size()); + ASSERT(index < m_length); + SparseMap::iterator iter = m_sparseStorage.find(index); + if (iter == m_sparseStorage.end()) { + hasIndex = false; + return SerializedScriptValueData(); + } + hasIndex = true; + return iter->second; + } + + unsigned length() const + { + return m_length; + } + + static PassRefPtr<SerializedArray> create(unsigned length) + { + return adoptRef(new SerializedArray(length)); + } + + void clear() + { + m_compactStorage.clear(); + m_sparseStorage.clear(); + m_length = 0; + } +private: + SerializedArray(unsigned length) + : m_length(length) + { + } + + Vector<SerializedScriptValueData> m_compactStorage; + SparseMap m_sparseStorage; + unsigned m_length; +}; + +SerializedScriptValueData::SerializedScriptValueData(RefPtr<SerializedObject> data) + : m_type(ObjectType) + , m_sharedData(data) +{ +} + +SerializedScriptValueData::SerializedScriptValueData(RefPtr<SerializedArray> data) + : m_type(ArrayType) + , m_sharedData(data) +{ +} + +SerializedArray* SharedSerializedData::asArray() +{ + return static_cast<SerializedArray*>(this); +} + +SerializedObject* SharedSerializedData::asObject() +{ + return static_cast<SerializedObject*>(this); +} + +static const unsigned maximumFilterRecursion = 40000; +enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember, + ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember }; +template <typename TreeWalker> typename TreeWalker::OutputType walk(TreeWalker& context, typename TreeWalker::InputType in) +{ + typedef typename TreeWalker::InputObject InputObject; + typedef typename TreeWalker::InputArray InputArray; + typedef typename TreeWalker::OutputObject OutputObject; + typedef typename TreeWalker::OutputArray OutputArray; + typedef typename TreeWalker::InputType InputType; + typedef typename TreeWalker::OutputType OutputType; + typedef typename TreeWalker::PropertyList PropertyList; + + Vector<uint32_t, 16> indexStack; + Vector<uint32_t, 16> lengthStack; + Vector<PropertyList, 16> propertyStack; + Vector<InputObject, 16> inputObjectStack; + Vector<InputArray, 16> inputArrayStack; + Vector<OutputObject, 16> outputObjectStack; + Vector<OutputArray, 16> outputArrayStack; + Vector<WalkerState, 16> stateStack; + WalkerState state = StateUnknown; + InputType inValue = in; + OutputType outValue = context.null(); + + unsigned tickCount = context.ticksUntilNextCheck(); + while (1) { + switch (state) { + arrayStartState: + case ArrayStartState: { + ASSERT(context.isArray(inValue)); + if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion) { + context.throwStackOverflow(); + return context.null(); + } + + InputArray inArray = context.asInputArray(inValue); + unsigned length = context.length(inArray); + OutputArray outArray = context.createOutputArray(length); + if (!context.startArray(inArray, outArray)) + return context.null(); + inputArrayStack.append(inArray); + outputArrayStack.append(outArray); + indexStack.append(0); + lengthStack.append(length); + // fallthrough + } + arrayStartVisitMember: + case ArrayStartVisitMember: { + if (!--tickCount) { + if (context.didTimeOut()) { + context.throwInterruptedException(); + return context.null(); + } + tickCount = context.ticksUntilNextCheck(); + } + + InputArray array = inputArrayStack.last(); + uint32_t index = indexStack.last(); + if (index == lengthStack.last()) { + InputArray inArray = inputArrayStack.last(); + OutputArray outArray = outputArrayStack.last(); + context.endArray(inArray, outArray); + outValue = outArray; + inputArrayStack.removeLast(); + outputArrayStack.removeLast(); + indexStack.removeLast(); + lengthStack.removeLast(); + break; + } + if (context.canDoFastRead(array, index)) + inValue = context.getIndex(array, index); + else { + bool hasIndex = false; + inValue = context.getSparseIndex(array, index, hasIndex); + if (!hasIndex) { + indexStack.last()++; + goto arrayStartVisitMember; + } + } + + if (OutputType transformed = context.convertIfTerminal(inValue)) + outValue = transformed; + else { + stateStack.append(ArrayEndVisitMember); + goto stateUnknown; + } + // fallthrough + } + case ArrayEndVisitMember: { + OutputArray outArray = outputArrayStack.last(); + context.putProperty(outArray, indexStack.last(), outValue); + indexStack.last()++; + goto arrayStartVisitMember; + } + objectStartState: + case ObjectStartState: { + ASSERT(context.isObject(inValue)); + if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion) { + context.throwStackOverflow(); + return context.null(); + } + InputObject inObject = context.asInputObject(inValue); + OutputObject outObject = context.createOutputObject(); + if (!context.startObject(inObject, outObject)) + return context.null(); + inputObjectStack.append(inObject); + outputObjectStack.append(outObject); + indexStack.append(0); + context.getPropertyNames(inObject, propertyStack); + // fallthrough + } + objectStartVisitMember: + case ObjectStartVisitMember: { + if (!--tickCount) { + if (context.didTimeOut()) { + context.throwInterruptedException(); + return context.null(); + } + tickCount = context.ticksUntilNextCheck(); + } + + InputObject object = inputObjectStack.last(); + uint32_t index = indexStack.last(); + PropertyList& properties = propertyStack.last(); + if (index == properties.size()) { + InputObject inObject = inputObjectStack.last(); + OutputObject outObject = outputObjectStack.last(); + context.endObject(inObject, outObject); + outValue = outObject; + inputObjectStack.removeLast(); + outputObjectStack.removeLast(); + indexStack.removeLast(); + propertyStack.removeLast(); + break; + } + inValue = context.getProperty(object, properties[index], index); + + if (context.shouldTerminate()) + return context.null(); + + if (OutputType transformed = context.convertIfTerminal(inValue)) + outValue = transformed; + else { + stateStack.append(ObjectEndVisitMember); + goto stateUnknown; + } + // fallthrough + } + case ObjectEndVisitMember: { + context.putProperty(outputObjectStack.last(), propertyStack.last()[indexStack.last()], outValue); + if (context.shouldTerminate()) + return context.null(); + + indexStack.last()++; + goto objectStartVisitMember; + } + stateUnknown: + case StateUnknown: + if (OutputType transformed = context.convertIfTerminal(inValue)) { + outValue = transformed; + break; + } + if (context.isArray(inValue)) + goto arrayStartState; + goto objectStartState; + } + if (stateStack.isEmpty()) + break; + + state = stateStack.last(); + stateStack.removeLast(); + + if (!--tickCount) { + if (context.didTimeOut()) { + context.throwInterruptedException(); + return context.null(); + } + tickCount = context.ticksUntilNextCheck(); + } + } + return outValue; +} + +struct BaseWalker { + BaseWalker(ExecState* exec) + : m_exec(exec) + , m_timeoutChecker(exec->globalData().timeoutChecker) + { + m_timeoutChecker.reset(); + } + ExecState* m_exec; + TimeoutChecker m_timeoutChecker; + MarkedArgumentBuffer m_gcBuffer; + + bool shouldTerminate() + { + return m_exec->hadException(); + } + + unsigned ticksUntilNextCheck() + { + return m_timeoutChecker.ticksUntilNextCheck(); + } + + bool didTimeOut() + { + return m_timeoutChecker.didTimeOut(m_exec); + } + + void throwStackOverflow() + { + m_exec->setException(createStackOverflowError(m_exec)); + } + + void throwInterruptedException() + { + m_exec->setException(createInterruptedExecutionException(&m_exec->globalData())); + } +}; + +struct SerializingTreeWalker : public BaseWalker { + typedef JSValue InputType; + typedef JSArray* InputArray; + typedef JSObject* InputObject; + typedef SerializedScriptValueData OutputType; + typedef RefPtr<SerializedArray> OutputArray; + typedef RefPtr<SerializedObject> OutputObject; + typedef PropertyNameArray PropertyList; + + SerializingTreeWalker(ExecState* exec) + : BaseWalker(exec) + { + } + + OutputType null() { return SerializedScriptValueData(); } + + bool isArray(JSValue value) + { + if (!value.isObject()) + return false; + JSObject* object = asObject(value); + return isJSArray(&m_exec->globalData(), object) || object->inherits(&JSArray::info); + } + + bool isObject(JSValue value) + { + return value.isObject(); + } + + JSArray* asInputArray(JSValue value) + { + return asArray(value); + } + + JSObject* asInputObject(JSValue value) + { + return asObject(value); + } + + PassRefPtr<SerializedArray> createOutputArray(unsigned length) + { + return SerializedArray::create(length); + } + + PassRefPtr<SerializedObject> createOutputObject() + { + return SerializedObject::create(); + } + + uint32_t length(JSValue array) + { + ASSERT(array.isObject()); + JSObject* object = asObject(array); + return object->get(m_exec, m_exec->propertyNames().length).toUInt32(m_exec); + } + + bool canDoFastRead(JSArray* array, unsigned index) + { + return isJSArray(&m_exec->globalData(), array) && array->canGetIndex(index); + } + + JSValue getIndex(JSArray* array, unsigned index) + { + return array->getIndex(index); + } + + JSValue getSparseIndex(JSObject* object, unsigned propertyName, bool& hasIndex) + { + PropertySlot slot(object); + if (object->getOwnPropertySlot(m_exec, propertyName, slot)) { + hasIndex = true; + return slot.getValue(m_exec, propertyName); + } + hasIndex = false; + return jsNull(); + } + + JSValue getProperty(JSObject* object, const Identifier& propertyName, unsigned) + { + PropertySlot slot(object); + if (object->getOwnPropertySlot(m_exec, propertyName, slot)) + return slot.getValue(m_exec, propertyName); + return jsNull(); + } + + SerializedScriptValueData convertIfTerminal(JSValue value) + { + if (!value.isCell()) + return SerializedScriptValueData(value); + + if (value.isString()) + return SerializedScriptValueData(asString(value)->value()); + + if (value.isNumber()) + return SerializedScriptValueData(SerializedScriptValueData::NumberType, value.uncheckedGetNumber()); + + if (value.isObject() && asObject(value)->inherits(&DateInstance::info)) + return SerializedScriptValueData(SerializedScriptValueData::DateType, asDateInstance(value)->internalNumber()); + + if (isArray(value)) + return SerializedScriptValueData(); + + CallData unusedData; + if (value.isObject() && value.getCallData(unusedData) == CallTypeNone) + return SerializedScriptValueData(); + + // Any other types are expected to serialize as null. + return SerializedScriptValueData(jsNull()); + } + + void getPropertyNames(JSObject* object, Vector<PropertyNameArray, 16>& propertyStack) + { + propertyStack.append(PropertyNameArray(m_exec)); + object->getOwnPropertyNames(m_exec, propertyStack.last()); + } + + void putProperty(RefPtr<SerializedArray> array, unsigned propertyName, const SerializedScriptValueData& value) + { + array->setIndex(propertyName, value); + } + + void putProperty(RefPtr<SerializedObject> object, const Identifier& propertyName, const SerializedScriptValueData& value) + { + object->set(propertyName, value); + } + + bool startArray(JSArray* inArray, RefPtr<SerializedArray>) + { + // Cycle detection + if (!m_cycleDetector.add(inArray).second) { + m_exec->setException(createTypeError(m_exec, "Cannot post cyclic structures.")); + return false; + } + m_gcBuffer.append(inArray); + return true; + } + + void endArray(JSArray* inArray, RefPtr<SerializedArray>) + { + m_cycleDetector.remove(inArray); + m_gcBuffer.removeLast(); + } + + bool startObject(JSObject* inObject, RefPtr<SerializedObject>) + { + // Cycle detection + if (!m_cycleDetector.add(inObject).second) { + m_exec->setException(createTypeError(m_exec, "Cannot post cyclic structures.")); + return false; + } + m_gcBuffer.append(inObject); + return true; + } + + void endObject(JSObject* inObject, RefPtr<SerializedObject>) + { + m_cycleDetector.remove(inObject); + m_gcBuffer.removeLast(); + } + +private: + HashSet<JSObject*> m_cycleDetector; +}; + +SerializedScriptValueData SerializedScriptValueData::serialize(ExecState* exec, JSValue inValue) +{ + SerializingTreeWalker context(exec); + return walk<SerializingTreeWalker>(context, inValue); +} + + +struct DeserializingTreeWalker : public BaseWalker { + typedef SerializedScriptValueData InputType; + typedef RefPtr<SerializedArray> InputArray; + typedef RefPtr<SerializedObject> InputObject; + typedef JSValue OutputType; + typedef JSArray* OutputArray; + typedef JSObject* OutputObject; + typedef SerializedObject::PropertyNameList PropertyList; + + DeserializingTreeWalker(ExecState* exec, bool mustCopy) + : BaseWalker(exec) + , m_mustCopy(mustCopy) + { + } + + OutputType null() { return jsNull(); } + + bool isArray(const SerializedScriptValueData& value) + { + return value.type() == SerializedScriptValueData::ArrayType; + } + + bool isObject(const SerializedScriptValueData& value) + { + return value.type() == SerializedScriptValueData::ObjectType; + } + + SerializedArray* asInputArray(const SerializedScriptValueData& value) + { + return value.asArray(); + } + + SerializedObject* asInputObject(const SerializedScriptValueData& value) + { + return value.asObject(); + } + + JSArray* createOutputArray(unsigned length) + { + JSArray* array = constructEmptyArray(m_exec); + array->setLength(length); + return array; + } + + JSObject* createOutputObject() + { + return constructEmptyObject(m_exec); + } + + uint32_t length(RefPtr<SerializedArray> array) + { + return array->length(); + } + + bool canDoFastRead(RefPtr<SerializedArray> array, unsigned index) + { + return array->canDoFastRead(index); + } + + SerializedScriptValueData getIndex(RefPtr<SerializedArray> array, unsigned index) + { + return array->getIndex(index); + } + + SerializedScriptValueData getSparseIndex(RefPtr<SerializedArray> array, unsigned propertyName, bool& hasIndex) + { + return array->getSparseIndex(propertyName, hasIndex); + } + + SerializedScriptValueData getProperty(RefPtr<SerializedObject> object, const RefPtr<StringImpl>& propertyName, unsigned propertyIndex) + { + ASSERT(object->names()[propertyIndex] == propertyName); + UNUSED_PARAM(propertyName); + return object->values()[propertyIndex]; + } + + JSValue convertIfTerminal(SerializedScriptValueData& value) + { + switch (value.type()) { + case SerializedScriptValueData::ArrayType: + case SerializedScriptValueData::ObjectType: + return JSValue(); + case SerializedScriptValueData::StringType: + return jsString(m_exec, value.asString().crossThreadString()); + case SerializedScriptValueData::ImmediateType: + return value.asImmediate(); + case SerializedScriptValueData::NumberType: + return jsNumber(m_exec, value.asDouble()); + case SerializedScriptValueData::DateType: + return new (m_exec) DateInstance(m_exec, value.asDouble()); + default: + ASSERT_NOT_REACHED(); + return JSValue(); + } + } + + void getPropertyNames(RefPtr<SerializedObject> object, Vector<SerializedObject::PropertyNameList, 16>& properties) + { + properties.append(object->names()); + } + + void putProperty(JSArray* array, unsigned propertyName, JSValue value) + { + array->put(m_exec, propertyName, value); + } + + void putProperty(JSObject* object, const RefPtr<StringImpl> propertyName, JSValue value) + { + object->putDirect(Identifier(m_exec, String(propertyName)), value); + } + + bool startArray(RefPtr<SerializedArray>, JSArray* outArray) + { + m_gcBuffer.append(outArray); + return true; + } + void endArray(RefPtr<SerializedArray>, JSArray*) + { + m_gcBuffer.removeLast(); + } + bool startObject(RefPtr<SerializedObject>, JSObject* outObject) + { + m_gcBuffer.append(outObject); + return true; + } + void endObject(RefPtr<SerializedObject>, JSObject*) + { + m_gcBuffer.removeLast(); + } + +private: + bool m_mustCopy; +}; + +JSValue SerializedScriptValueData::deserialize(ExecState* exec, bool mustCopy) const +{ + DeserializingTreeWalker context(exec, mustCopy); + return walk<DeserializingTreeWalker>(context, *this); +} + +struct TeardownTreeWalker { + typedef SerializedScriptValueData InputType; + typedef RefPtr<SerializedArray> InputArray; + typedef RefPtr<SerializedObject> InputObject; + typedef bool OutputType; + typedef bool OutputArray; + typedef bool OutputObject; + typedef SerializedObject::PropertyNameList PropertyList; + + bool shouldTerminate() + { + return false; + } + + unsigned ticksUntilNextCheck() + { + return 0xFFFFFFFF; + } + + bool didTimeOut() + { + return false; + } + + void throwStackOverflow() + { + } + + void throwInterruptedException() + { + } + + bool null() { return false; } + + bool isArray(const SerializedScriptValueData& value) + { + return value.type() == SerializedScriptValueData::ArrayType; + } + + bool isObject(const SerializedScriptValueData& value) + { + return value.type() == SerializedScriptValueData::ObjectType; + } + + SerializedArray* asInputArray(const SerializedScriptValueData& value) + { + return value.asArray(); + } + + SerializedObject* asInputObject(const SerializedScriptValueData& value) + { + return value.asObject(); + } + + bool createOutputArray(unsigned) + { + return false; + } + + bool createOutputObject() + { + return false; + } + + uint32_t length(RefPtr<SerializedArray> array) + { + return array->length(); + } + + bool canDoFastRead(RefPtr<SerializedArray> array, unsigned index) + { + return array->canDoFastRead(index); + } + + SerializedScriptValueData getIndex(RefPtr<SerializedArray> array, unsigned index) + { + return array->getIndex(index); + } + + SerializedScriptValueData getSparseIndex(RefPtr<SerializedArray> array, unsigned propertyName, bool& hasIndex) + { + return array->getSparseIndex(propertyName, hasIndex); + } + + SerializedScriptValueData getProperty(RefPtr<SerializedObject> object, const RefPtr<StringImpl>& propertyName, unsigned propertyIndex) + { + ASSERT(object->names()[propertyIndex] == propertyName); + UNUSED_PARAM(propertyName); + return object->values()[propertyIndex]; + } + + bool convertIfTerminal(SerializedScriptValueData& value) + { + switch (value.type()) { + case SerializedScriptValueData::ArrayType: + case SerializedScriptValueData::ObjectType: + return false; + case SerializedScriptValueData::StringType: + case SerializedScriptValueData::ImmediateType: + case SerializedScriptValueData::NumberType: + return true; + default: + ASSERT_NOT_REACHED(); + return JSValue(); + } + } + + void getPropertyNames(RefPtr<SerializedObject> object, Vector<SerializedObject::PropertyNameList, 16>& properties) + { + properties.append(object->names()); + } + + void putProperty(bool, unsigned, bool) + { + } + + void putProperty(bool, const RefPtr<StringImpl>&, bool) + { + } + + bool startArray(RefPtr<SerializedArray>, bool) + { + return true; + } + void endArray(RefPtr<SerializedArray> array, bool) + { + array->clear(); + } + bool startObject(RefPtr<SerializedObject>, bool) + { + return true; + } + void endObject(RefPtr<SerializedObject> object, bool) + { + object->clear(); + } +}; + +void SerializedScriptValueData::tearDownSerializedData() +{ + if (m_sharedData && m_sharedData->refCount() > 1) + return; + TeardownTreeWalker context; + walk<TeardownTreeWalker>(context, *this); +} + +} diff --git a/WebCore/bindings/js/SerializedScriptValue.h b/WebCore/bindings/js/SerializedScriptValue.h new file mode 100644 index 0000000..f8a126f --- /dev/null +++ b/WebCore/bindings/js/SerializedScriptValue.h @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * 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 + * 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 + * 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 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef SerializedScriptValue_h +#define SerializedScriptValue_h + +#include "ScriptValue.h" + +namespace WebCore { + class SerializedObject; + class SerializedArray; + + class SharedSerializedData : public RefCounted<SharedSerializedData> { + public: + virtual ~SharedSerializedData() { } + SerializedArray* asArray(); + SerializedObject* asObject(); + }; + + class SerializedScriptValue; + + class SerializedScriptValueData { + public: + enum SerializedType { + EmptyType, + DateType, + NumberType, + ImmediateType, + ObjectType, + ArrayType, + StringType + }; + + SerializedType type() const { return m_type; } + static SerializedScriptValueData serialize(JSC::ExecState*, JSC::JSValue); + JSC::JSValue deserialize(JSC::ExecState*, bool mustCopy) const; + + ~SerializedScriptValueData() + { + if (m_sharedData) + tearDownSerializedData(); + } + + SerializedScriptValueData() + : m_type(EmptyType) + { + } + + explicit SerializedScriptValueData(const String& string) + : m_type(StringType) + , m_string(string.crossThreadString()) // FIXME: Should be able to just share the Rep + { + } + + explicit SerializedScriptValueData(JSC::JSValue value) + : m_type(ImmediateType) + { + ASSERT(!value.isCell()); + m_data.m_immediate = JSC::JSValue::encode(value); + } + + SerializedScriptValueData(SerializedType type, double value) + : m_type(type) + { + m_data.m_double = value; + } + + SerializedScriptValueData(RefPtr<SerializedObject>); + SerializedScriptValueData(RefPtr<SerializedArray>); + + JSC::JSValue asImmediate() const + { + ASSERT(m_type == ImmediateType); + return JSC::JSValue::decode(m_data.m_immediate); + } + + double asDouble() const + { + ASSERT(m_type == NumberType || m_type == DateType); + return m_data.m_double; + } + + String asString() const + { + ASSERT(m_type == StringType); + return m_string; + } + + SerializedObject* asObject() const + { + ASSERT(m_type == ObjectType); + ASSERT(m_sharedData); + return m_sharedData->asObject(); + } + + SerializedArray* asArray() const + { + ASSERT(m_type == ArrayType); + ASSERT(m_sharedData); + return m_sharedData->asArray(); + } + + operator bool() const { return m_type != EmptyType; } + + SerializedScriptValueData release() + { + SerializedScriptValueData result = *this; + *this = SerializedScriptValueData(); + return result; + } + + private: + void tearDownSerializedData(); + SerializedType m_type; + RefPtr<SharedSerializedData> m_sharedData; + String m_string; + union { + double m_double; + JSC::EncodedJSValue m_immediate; + } m_data; + }; + + class SerializedScriptValue : public RefCounted<SerializedScriptValue> { + public: + static PassRefPtr<SerializedScriptValue> create(JSC::ExecState* exec, JSC::JSValue value) + { + return adoptRef(new SerializedScriptValue(SerializedScriptValueData::serialize(exec, value))); + } + + static PassRefPtr<SerializedScriptValue> create(String string) + { + return adoptRef(new SerializedScriptValue(SerializedScriptValueData(string))); + } + + static PassRefPtr<SerializedScriptValue> create() + { + return adoptRef(new SerializedScriptValue(SerializedScriptValueData())); + } + + PassRefPtr<SerializedScriptValue> release() + { + PassRefPtr<SerializedScriptValue> result = adoptRef(new SerializedScriptValue(m_value)); + m_value = SerializedScriptValueData(); + result->m_mustCopy = true; + return result; + } + + String toString() + { + if (m_value.type() != SerializedScriptValueData::StringType) + return ""; + return m_value.asString(); + } + + JSC::JSValue deserialize(JSC::ExecState* exec) + { + if (!m_value) + return JSC::jsNull(); + return m_value.deserialize(exec, m_mustCopy); + } + + ~SerializedScriptValue() {} + + private: + SerializedScriptValue(SerializedScriptValueData value) + : m_value(value) + , m_mustCopy(false) + { + } + + SerializedScriptValueData m_value; + bool m_mustCopy; + }; +} + +#endif // SerializedScriptValue_h diff --git a/WebCore/bindings/objc/DOM.mm b/WebCore/bindings/objc/DOM.mm index 62bf1de..63a3b2a 100644 --- a/WebCore/bindings/objc/DOM.mm +++ b/WebCore/bindings/objc/DOM.mm @@ -29,21 +29,23 @@ #import "DOMInternal.h" // import first to make the private/public trick work #import "DOM.h" -#import "DOMRangeInternal.h" #import "DOMElementInternal.h" -#import "DOMNodeInternal.h" #import "DOMHTMLCanvasElement.h" +#import "DOMNodeInternal.h" +#import "DOMPrivate.h" +#import "DOMRangeInternal.h" #import "Frame.h" -#import "HTMLNames.h" #import "HTMLElement.h" -#import "RenderImage.h" +#import "HTMLNames.h" #import "NodeFilter.h" +#import "RenderImage.h" #import "WebScriptObjectPrivate.h" #import <wtf/HashMap.h> #if ENABLE(SVG_DOM_OBJC_BINDINGS) #import "DOMSVG.h" #import "SVGElementInstance.h" +#import "SVGNames.h" #endif using namespace JSC; @@ -154,9 +156,6 @@ static void createElementClassMap() addElementClass(SVGNames::circleTag, [DOMSVGCircleElement class]); addElementClass(SVGNames::clipPathTag, [DOMSVGClipPathElement class]); addElementClass(SVGNames::cursorTag, [DOMSVGCursorElement class]); -#if ENABLE(SVG_FONTS) - addElementClass(SVGNames::definition_srcTag, [DOMSVGDefinitionSrcElement class]); -#endif addElementClass(SVGNames::defsTag, [DOMSVGDefsElement class]); addElementClass(SVGNames::descTag, [DOMSVGDescElement class]); addElementClass(SVGNames::ellipseTag, [DOMSVGEllipseElement class]); @@ -359,20 +358,6 @@ id <DOMEventTarget> kit(WebCore::EventTarget* eventTarget) return renderer->absoluteBoundingBoxRect(); } -- (NSArray *)textRects -{ - // FIXME: Could we move this function to WebCore::Node and autogenerate? - core(self)->document()->updateLayoutIgnorePendingStylesheets(); - if (!core(self)->renderer()) - return nil; - RefPtr<Range> range = Range::create(core(self)->document()); - WebCore::ExceptionCode ec = 0; - range->selectNodeContents(core(self), ec); - Vector<WebCore::IntRect> rects; - range->textRects(rects); - return kit(rects); -} - - (NSArray *)lineBoxRects { return [self textRects]; @@ -392,6 +377,19 @@ id <DOMEventTarget> kit(WebCore::EventTarget* eventTarget) return frame->nodeImage(node); } +- (NSArray *)textRects +{ + // FIXME: Could we move this function to WebCore::Node and autogenerate? + core(self)->document()->updateLayoutIgnorePendingStylesheets(); + if (!core(self)->renderer()) + return nil; + RefPtr<Range> range = Range::create(core(self)->document()); + WebCore::ExceptionCode ec = 0; + range->selectNodeContents(core(self), ec); + Vector<WebCore::IntRect> rects; + range->textRects(rects); + return kit(rects); +} @end @implementation DOMRange (DOMRangeExtensions) diff --git a/WebCore/bindings/objc/DOMCSS.mm b/WebCore/bindings/objc/DOMCSS.mm index 0149273..22a9cb2 100644 --- a/WebCore/bindings/objc/DOMCSS.mm +++ b/WebCore/bindings/objc/DOMCSS.mm @@ -47,6 +47,7 @@ #import "DOMStyleSheetInternal.h" #import "DOMWebKitCSSKeyframeRule.h" #import "DOMWebKitCSSKeyframesRule.h" +#import "DOMWebKitCSSTransformValue.h" #if ENABLE(SVG_DOM_OBJC_BINDINGS) #import "DOMSVGPaint.h" @@ -102,6 +103,8 @@ Class kitClass(WebCore::CSSValue* impl) case WebCore::CSSValue::CSS_PRIMITIVE_VALUE: return [DOMCSSPrimitiveValue class]; case WebCore::CSSValue::CSS_VALUE_LIST: + if (impl->isWebKitCSSTransformValue()) + return [DOMWebKitCSSTransformValue class]; return [DOMCSSValueList class]; case WebCore::CSSValue::CSS_INHERIT: case WebCore::CSSValue::CSS_INITIAL: diff --git a/WebCore/bindings/objc/DOMInternal.h b/WebCore/bindings/objc/DOMInternal.h index 48f5d2f..72f63d2 100644 --- a/WebCore/bindings/objc/DOMInternal.h +++ b/WebCore/bindings/objc/DOMInternal.h @@ -61,7 +61,6 @@ namespace WebCore { // Create an NSMapTable mapping from pointers to ObjC objects held with zeroing weak references. NSMapTable* createWrapperCache(); -NSMapTable* createWrapperCacheWithIntegerKeys(); // Same, but from integers to ObjC objects. id createDOMWrapper(JSC::JSObject*, PassRefPtr<JSC::Bindings::RootObject> origin, PassRefPtr<JSC::Bindings::RootObject> current); diff --git a/WebCore/bindings/objc/DOMInternal.mm b/WebCore/bindings/objc/DOMInternal.mm index 9b26e59..993a3ad 100644 --- a/WebCore/bindings/objc/DOMInternal.mm +++ b/WebCore/bindings/objc/DOMInternal.mm @@ -49,18 +49,6 @@ NSMapTable* createWrapperCache() #endif } -NSMapTable* createWrapperCacheWithIntegerKeys() -{ -#ifdef BUILDING_ON_TIGER - return NSCreateMapTable(NSIntMapKeyCallBacks, NSNonRetainedObjectMapValueCallBacks, 0); -#else - // NSMapTable with zeroing weak pointers is the recommended way to build caches like this under garbage collection. - NSPointerFunctionsOptions keyOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsIntegerPersonality; - NSPointerFunctionsOptions valueOptions = NSPointerFunctionsZeroingWeakMemory | NSPointerFunctionsObjectPersonality; - return [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0]; -#endif -} - NSObject* getDOMWrapper(DOMObjectInternal* impl) { if (!DOMWrapperCache) diff --git a/WebCore/bindings/objc/DOMSVG.h b/WebCore/bindings/objc/DOMSVG.h index f1321d8..cb74544 100644 --- a/WebCore/bindings/objc/DOMSVG.h +++ b/WebCore/bindings/objc/DOMSVG.h @@ -50,7 +50,6 @@ #import <WebCore/DOMSVGColor.h> #import <WebCore/DOMSVGComponentTransferFunctionElement.h> #import <WebCore/DOMSVGCursorElement.h> -#import <WebCore/DOMSVGDefinitionSrcElement.h> #import <WebCore/DOMSVGDefsElement.h> #import <WebCore/DOMSVGDescElement.h> #import <WebCore/DOMSVGDocument.h> diff --git a/WebCore/bindings/objc/ObjCEventListener.h b/WebCore/bindings/objc/ObjCEventListener.h index 6056b01..434ef45 100644 --- a/WebCore/bindings/objc/ObjCEventListener.h +++ b/WebCore/bindings/objc/ObjCEventListener.h @@ -39,13 +39,22 @@ namespace WebCore { public: static PassRefPtr<ObjCEventListener> wrap(id <DOMEventListener>); + static const ObjCEventListener* cast(const EventListener* listener) + { + return listener->type() == ObjCEventListenerType + ? static_cast<const ObjCEventListener*>(listener) + : 0; + } + + virtual bool operator==(const EventListener& other); + private: static ObjCEventListener* find(id <DOMEventListener>); ObjCEventListener(id <DOMEventListener>); virtual ~ObjCEventListener(); - virtual void handleEvent(Event*, bool isWindowEvent); + virtual void handleEvent(ScriptExecutionContext*, Event*); id <DOMEventListener> m_listener; }; diff --git a/WebCore/bindings/objc/ObjCEventListener.mm b/WebCore/bindings/objc/ObjCEventListener.mm index 77c6ad2..d73ac30 100644 --- a/WebCore/bindings/objc/ObjCEventListener.mm +++ b/WebCore/bindings/objc/ObjCEventListener.mm @@ -56,7 +56,8 @@ PassRefPtr<ObjCEventListener> ObjCEventListener::wrap(id <DOMEventListener> list } ObjCEventListener::ObjCEventListener(id <DOMEventListener> listener) - : m_listener([listener retain]) + : EventListener(ObjCEventListenerType) + , m_listener([listener retain]) { ListenerMap* map = listenerMap; if (!map) { @@ -72,9 +73,16 @@ ObjCEventListener::~ObjCEventListener() [m_listener release]; } -void ObjCEventListener::handleEvent(Event* event, bool) +void ObjCEventListener::handleEvent(ScriptExecutionContext*, Event* event) { [m_listener handleEvent:kit(event)]; } +bool ObjCEventListener::operator==(const EventListener& listener) +{ + if (const ObjCEventListener* objCEventListener = ObjCEventListener::cast(&listener)) + return m_listener == objCEventListener->m_listener; + return false; +} + } // namespace WebCore diff --git a/WebCore/bindings/scripts/CodeGenerator.pm b/WebCore/bindings/scripts/CodeGenerator.pm index 341c607..92bd390 100644 --- a/WebCore/bindings/scripts/CodeGenerator.pm +++ b/WebCore/bindings/scripts/CodeGenerator.pm @@ -4,6 +4,7 @@ # Copyright (C) 2005 Nikolas Zimmermann <wildfox@kde.org> # Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> # Copyright (C) 2007 Apple Inc. All rights reserved. +# Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au> # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public @@ -23,12 +24,16 @@ package CodeGenerator; +use File::Find; + my $useDocument = ""; my $useGenerator = ""; my $useOutputDir = ""; my $useDirectories = ""; my $useLayerOnTop = 0; my $preprocessor; +my $writeDependencies = 0; +my $defines = ""; my $codeGenerator = 0; @@ -54,12 +59,8 @@ my %svgAnimatedTypeHash = ("SVGAnimatedAngle" => 1, "SVGAnimatedBoolean" => 1, "SVGAnimatedRect" => 1, "SVGAnimatedString" => 1, "SVGAnimatedTransformList" => 1); -# Helpers for 'ScanDirectory' -my $endCondition = 0; -my $foundFilename = ""; -my @foundFilenames = (); -my $ignoreParent = 1; -my $defines = ""; +# Cache of IDL file pathnames. +my $idlFiles; # Default constructor sub new @@ -72,6 +73,7 @@ sub new $useOutputDir = shift; $useLayerOnTop = shift; $preprocessor = shift; + $writeDependencies = shift; bless($reference, $object); return $reference; @@ -95,7 +97,7 @@ sub ProcessDocument # Dynamically load external code generation perl module require $ifaceName . ".pm"; - $codeGenerator = $ifaceName->new($object, $useOutputDir, $useLayerOnTop, $preprocessor); + $codeGenerator = $ifaceName->new($object, $useOutputDir, $useLayerOnTop, $preprocessor, $writeDependencies); unless (defined($codeGenerator)) { my $classes = $useDocument->classes; foreach my $class (@$classes) { @@ -116,100 +118,83 @@ sub ProcessDocument $codeGenerator->finish(); } -# Necessary for V8 bindings to determine whether an interface is descendant from Node. -# Node descendants are treated differently by DOMMap and this allows inferring the -# type statically. See more at the original change: http://codereview.chromium.org/3195. -# FIXME: Figure out a way to eliminate this JS bindings dichotomy. -sub FindParentsRecursively +sub ForAllParents { my $object = shift; my $dataNode = shift; - my @parents = ($dataNode->name); - foreach (@{$dataNode->parents}) { - my $interface = $object->StripModule($_); - - $endCondition = 0; - $foundFilename = ""; - foreach (@{$useDirectories}) { - $object->ScanDirectory("$interface.idl", $_, $_, 0) if ($foundFilename eq ""); - } + my $beforeRecursion = shift; + my $afterRecursion = shift; + my $parentsOnly = shift; - if ($foundFilename ne "") { - print " | |> Parsing parent IDL \"$foundFilename\" for interface \"$interface\"\n" if $verbose; + my $recurse; + $recurse = sub { + my $interface = shift; - # Step #2: Parse the found IDL file (in quiet mode). - my $parser = IDLParser->new(1); - my $document = $parser->Parse($foundFilename, $defines, $preprocessor, 1); + for (@{$interface->parents}) { + my $interfaceName = $object->StripModule($_); + my $parentInterface = $object->ParseInterface($interfaceName, $parentsOnly); - foreach my $class (@{$document->classes}) { - @parents = (@parents, FindParentsRecursively($object, $class)); + if ($beforeRecursion) { + &$beforeRecursion($parentInterface) eq 'prune' and next; } - } else { - die("Could NOT find specified parent interface \"$interface\"!\n") + &$recurse($parentInterface); + &$afterRecursion($parentInterface) if $afterRecursion; } - } - return @parents; + }; + + &$recurse($dataNode); } sub AddMethodsConstantsAndAttributesFromParentClasses { - # For the passed interface, recursively parse all parent - # IDLs in order to find out all inherited properties/methods. + # Add to $dataNode all of its inherited interface members, except for those + # inherited through $dataNode's first listed parent. If an array reference + # is passed in as $parents, the names of all ancestor interfaces visited + # will be appended to the array. If $collectDirectParents is true, then + # even the names of $dataNode's first listed parent and its ancestors will + # be appended to $parents. my $object = shift; my $dataNode = shift; + my $parents = shift; + my $collectDirectParents = shift; - my @parents = @{$dataNode->parents}; - my $parentsMax = @{$dataNode->parents}; + my $first = 1; - my $constantsRef = $dataNode->constants; - my $functionsRef = $dataNode->functions; - my $attributesRef = $dataNode->attributes; + $object->ForAllParents($dataNode, sub { + my $interface = shift; - foreach (@{$dataNode->parents}) { - if ($ignoreParent) { + if ($first) { # Ignore first parent class, already handled by the generation itself. - $ignoreParent = 0; - next; - } - - my $interface = $object->StripModule($_); - - # Step #1: Find the IDL file associated with 'interface' - $endCondition = 0; - $foundFilename = ""; + $first = 0; + + if ($collectDirectParents) { + # Just collect the names of the direct ancestor interfaces, + # if necessary. + push(@$parents, $interface->name); + $object->ForAllParents($interface, sub { + my $interface = shift; + push(@$parents, $interface->name); + }, undef, 1); + } - foreach (@{$useDirectories}) { - $object->ScanDirectory("$interface.idl", $_, $_, 0) if ($foundFilename eq ""); + # Prune the recursion here. + return 'prune'; } - if ($foundFilename ne "") { - print " | |> Parsing parent IDL \"$foundFilename\" for interface \"$interface\"\n" if $verbose; - - # Step #2: Parse the found IDL file (in quiet mode). - my $parser = IDLParser->new(1); - my $document = $parser->Parse($foundFilename, $defines, $preprocessor); + # Collect the name of this additional parent. + push(@$parents, $interface->name) if $parents; - foreach my $class (@{$document->classes}) { - # Step #3: Enter recursive parent search - AddMethodsConstantsAndAttributesFromParentClasses($object, $class); + print " | |> -> Inheriting " + . @{$interface->constants} . " constants, " + . @{$interface->functions} . " functions, " + . @{$interface->attributes} . " attributes...\n | |>\n" if $verbose; - # Step #4: Collect constants & functions & attributes of this parent-class - my $constantsMax = @{$class->constants}; - my $functionsMax = @{$class->functions}; - my $attributesMax = @{$class->attributes}; - - print " | |> -> Inheriting $constantsMax constants, $functionsMax functions, $attributesMax attributes...\n | |>\n" if $verbose; - - # Step #5: Concatenate data - push(@$constantsRef, $_) foreach (@{$class->constants}); - push(@$functionsRef, $_) foreach (@{$class->functions}); - push(@$attributesRef, $_) foreach (@{$class->attributes}); - } - } else { - die("Could NOT find specified parent interface \"$interface\"!\n"); - } - } + # Add this parent's members to $dataNode. + push(@{$dataNode->constants}, @{$interface->constants}); + push(@{$dataNode->functions}, @{$interface->functions}); + push(@{$dataNode->attributes}, @{$interface->attributes}); + }); } sub GetMethodsAndAttributesFromParentClasses @@ -220,76 +205,67 @@ sub GetMethodsAndAttributesFromParentClasses my $object = shift; my $dataNode = shift; - my @parents = @{$dataNode->parents}; - - return if @{$dataNode->parents} == 0; - my @parentList = (); - foreach (@{$dataNode->parents}) { - my $interface = $object->StripModule($_); + $object->ForAllParents($dataNode, undef, sub { + my $interface = shift; - # Step #1: Find the IDL file associated with 'interface' - $endCondition = 0; - $foundFilename = ""; + my $hash = { + "name" => $interface->name, + "functions" => $interface->functions, + "attributes" => $interface->attributes + }; - foreach (@{$useDirectories}) { - $object->ScanDirectory("${interface}.idl", $_, $_, 0) if $foundFilename eq ""; - } - - die("Could NOT find specified parent interface \"$interface\"!\n") if $foundFilename eq ""; - - print " | |> Parsing parent IDL \"$foundFilename\" for interface \"$interface\"\n" if $verbose; + unshift(@parentList, $hash); + }); - # Step #2: Parse the found IDL file (in quiet mode). - my $parser = IDLParser->new(1); - my $document = $parser->Parse($foundFilename, $defines); + return @parentList; +} - foreach my $class (@{$document->classes}) { - # Step #3: Enter recursive parent search - push(@parentList, GetMethodsAndAttributesFromParentClasses($object, $class)); +sub IDLFileForInterface +{ + my $object = shift; + my $interfaceName = shift; - # Step #4: Collect constants & functions & attributes of this parent-class + unless ($idlFiles) { + my $sourceRoot = $ENV{SOURCE_ROOT}; + my @directories = map { $_ = "$sourceRoot/$_" if $sourceRoot && -d "$sourceRoot/$_"; $_ } @$useDirectories; - # print " | |> -> Inheriting $functionsMax functions amd $attributesMax attributes...\n | |>\n" if $verbose; - my $hash = { - "name" => $class->name, - "functions" => $class->functions, - "attributes" => $class->attributes - }; + $idlFiles = { }; - # Step #5: Concatenate data - unshift(@parentList, $hash); - } + my $wanted = sub { + $idlFiles->{$1} = $File::Find::name if /^([A-Z].*)\.idl$/; + $File::Find::prune = 1 if /^\../; + }; + find($wanted, @directories); } - return @parentList; + return $idlFiles->{$interfaceName}; } sub ParseInterface { - my ($object, $interfaceName) = @_; + my $object = shift; + my $interfaceName = shift; + my $parentsOnly = shift; - # Step #1: Find the IDL file associated with 'interface' - $endCondition = 0; - $foundFilename = ""; + return undef if $interfaceName eq 'Object'; - foreach (@{$useDirectories}) { - $object->ScanDirectory("${interfaceName}.idl", $_, $_, 0) if $foundFilename eq ""; - } - die "Could NOT find specified parent interface \"$interfaceName\"!\n" if $foundFilename eq ""; + # Step #1: Find the IDL file associated with 'interface' + my $filename = $object->IDLFileForInterface($interfaceName) + or die("Could NOT find IDL file for interface \"$interfaceName\"!\n"); - print " | |> Parsing parent IDL \"$foundFilename\" for interface \"$interfaceName\"\n" if $verbose; + print " | |> Parsing parent IDL \"$filename\" for interface \"$interfaceName\"\n" if $verbose; # Step #2: Parse the found IDL file (in quiet mode). my $parser = IDLParser->new(1); - my $document = $parser->Parse($foundFilename, $defines); + my $document = $parser->Parse($filename, $defines, $preprocessor, $parentsOnly); foreach my $interface (@{$document->classes}) { return $interface if $interface->name eq $interfaceName; } - die "Interface definition not found"; + die("Could NOT find interface definition for $interface in $filename"); } # Helpers for all CodeGenerator***.pm modules @@ -348,56 +324,6 @@ sub IsSVGAnimatedType return 0; } -# Internal Helper -sub ScanDirectory -{ - my $object = shift; - - my $interface = shift; - my $directory = shift; - my $useDirectory = shift; - my $reportAllFiles = shift; - - return if ($endCondition eq 1) and ($reportAllFiles eq 0); - - my $sourceRoot = $ENV{SOURCE_ROOT}; - my $thisDir = $sourceRoot ? "$sourceRoot/$directory" : $directory; - - if (!opendir(DIR, $thisDir)) { - opendir(DIR, $directory) or die "[ERROR] Can't open directory $thisDir or $directory: \"$!\"\n"; - $thisDir = $directory; - } - - my @names = readdir(DIR) or die "[ERROR] Cant't read directory $thisDir \"$!\"\n"; - closedir(DIR); - - foreach my $name (@names) { - # Skip if we already found the right file or - # if we encounter 'exotic' stuff (ie. '.', '..', '.svn') - next if ($endCondition eq 1) or ($name =~ /^\./); - - # Recurisvely enter directory - if (-d "$thisDir/$name") { - $object->ScanDirectory($interface, "$directory/$name", $useDirectory, $reportAllFiles); - next; - } - - # Check wheter we found the desired file - my $condition = ($name eq $interface); - $condition = 1 if ($interface eq "allidls") and ($name =~ /\.idl$/); - - if ($condition) { - $foundFilename = "$thisDir/$name"; - - if ($reportAllFiles eq 0) { - $endCondition = 1; - } else { - push(@foundFilenames, $foundFilename); - } - } - } -} - # Uppercase the first letter while respecting WebKit style guidelines. # E.g., xmlEncoding becomes XMLEncoding, but xmlllang becomes Xmllang. sub WK_ucfirst diff --git a/WebCore/bindings/scripts/CodeGeneratorCOM.pm b/WebCore/bindings/scripts/CodeGeneratorCOM.pm index 6641305..4d5cb96 100644 --- a/WebCore/bindings/scripts/CodeGeneratorCOM.pm +++ b/WebCore/bindings/scripts/CodeGeneratorCOM.pm @@ -326,9 +326,8 @@ sub AddIncludesForTypeInCPPImplementation sub GetAdditionalInterfaces { + # This function does nothing, but it stays here for future multiple inheritance support. my $type = $codeGenerator->StripModule(shift); - - return ("EventTarget") if $type eq "Node"; return (); } diff --git a/WebCore/bindings/scripts/CodeGeneratorJS.pm b/WebCore/bindings/scripts/CodeGeneratorJS.pm index 1918aef..095c75f 100644 --- a/WebCore/bindings/scripts/CodeGeneratorJS.pm +++ b/WebCore/bindings/scripts/CodeGeneratorJS.pm @@ -4,6 +4,7 @@ # Copyright (C) 2006, 2007 Samuel Weinig <sam@webkit.org> # Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org> # Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. +# Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au> # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public @@ -26,6 +27,7 @@ use File::stat; my $module = ""; my $outputDir = ""; +my $writeDependencies = 0; my @headerContentHeader = (); my @headerContent = (); @@ -34,6 +36,7 @@ my %headerIncludes = (); my @implContentHeader = (); my @implContent = (); my %implIncludes = (); +my @depsContent = (); # Default .h template my $headerTemplate = << "EOF"; @@ -66,6 +69,9 @@ sub new $codeGenerator = shift; $outputDir = shift; + shift; # $useLayerOnTop + shift; # $preprocessor + $writeDependencies = shift; bless($reference, $object); return $reference; @@ -100,9 +106,16 @@ sub GenerateInterface # Open files for writing my $headerFileName = "$outputDir/JS$name.h"; my $implFileName = "$outputDir/JS$name.cpp"; + my $depsFileName = "$outputDir/JS$name.dep"; + + # Remove old dependency file. + unlink($depsFileName); open($IMPL, ">$implFileName") || die "Couldn't open file $implFileName"; open($HEADER, ">$headerFileName") || die "Couldn't open file $headerFileName"; + if (@depsContent) { + open($DEPS, ">$depsFileName") || die "Couldn't open file $depsFileName"; + } } # Params: 'idlDocument' struct @@ -300,11 +313,11 @@ sub GenerateGetOwnPropertySlotBody &$manualLookupGetterGeneration(); } - if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"}) { + if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) { push(@getOwnPropertySlotImpl, " bool ok;\n"); push(@getOwnPropertySlotImpl, " unsigned index = propertyName.toUInt32(&ok, false);\n"); push(@getOwnPropertySlotImpl, " if (ok && index < static_cast<$implClassName*>(impl())->length()) {\n"); - if ($dataNode->extendedAttributes->{"HasCustomIndexGetter"}) { + if ($dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) { push(@getOwnPropertySlotImpl, " slot.setValue(getByIndex(exec, index));\n"); } else { push(@getOwnPropertySlotImpl, " slot.setCustomIndex(this, index, indexGetter);\n"); @@ -348,6 +361,99 @@ sub GenerateGetOwnPropertySlotBody return @getOwnPropertySlotImpl; } +sub GenerateGetOwnPropertyDescriptorBody +{ + my ($dataNode, $interfaceName, $className, $implClassName, $hasAttributes, $inlined) = @_; + + my $namespaceMaybe = ($inlined ? "JSC::" : ""); + + my @getOwnPropertyDescriptorImpl = (); + + if ($interfaceName eq "NamedNodeMap" or $interfaceName eq "HTMLCollection") { + push(@getOwnPropertyDescriptorImpl, " ${namespaceMaybe}JSValue proto = prototype();\n"); + push(@getOwnPropertyDescriptorImpl, " if (proto.isObject() && static_cast<${namespaceMaybe}JSObject*>(asObject(proto))->hasProperty(exec, propertyName))\n"); + push(@getOwnPropertyDescriptorImpl, " return false;\n\n"); + } + + my $manualLookupGetterGeneration = sub { + my $requiresManualLookup = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNameGetter"}; + if ($requiresManualLookup) { + push(@getOwnPropertyDescriptorImpl, " const ${namespaceMaybe}HashEntry* entry = ${className}Table.entry(exec, propertyName);\n"); + push(@getOwnPropertyDescriptorImpl, " if (entry) {\n"); + push(@getOwnPropertyDescriptorImpl, " PropertySlot slot;\n"); + push(@getOwnPropertyDescriptorImpl, " slot.setCustom(this, entry->propertyGetter());\n"); + push(@getOwnPropertyDescriptorImpl, " descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());\n"); + push(@getOwnPropertyDescriptorImpl, " return true;\n"); + push(@getOwnPropertyDescriptorImpl, " }\n"); + } + }; + + if (!$dataNode->extendedAttributes->{"HasOverridingNameGetter"}) { + &$manualLookupGetterGeneration(); + } + + if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) { + push(@getOwnPropertyDescriptorImpl, " bool ok;\n"); + push(@getOwnPropertyDescriptorImpl, " unsigned index = propertyName.toUInt32(&ok, false);\n"); + push(@getOwnPropertyDescriptorImpl, " if (ok && index < static_cast<$implClassName*>(impl())->length()) {\n"); + if ($dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) { + # Assume that if there's a setter, the index will be writable + if ($dataNode->extendedAttributes->{"HasIndexSetter"} || $dataNode->extendedAttributes->{"HasCustomIndexSetter"}) { + push(@getOwnPropertyDescriptorImpl, " descriptor.setDescriptor(getByIndex(exec, index), ${namespaceMaybe}DontDelete);\n"); + } else { + push(@getOwnPropertyDescriptorImpl, " descriptor.setDescriptor(getByIndex(exec, index), ${namespaceMaybe}DontDelete | ${namespaceMaybe}ReadOnly);\n"); + } + } else { + push(@getOwnPropertyDescriptorImpl, " ${namespaceMaybe}PropertySlot slot;\n"); + push(@getOwnPropertyDescriptorImpl, " slot.setCustomIndex(this, index, indexGetter);\n"); + # Assume that if there's a setter, the index will be writable + if ($dataNode->extendedAttributes->{"HasIndexSetter"} || $dataNode->extendedAttributes->{"HasCustomIndexSetter"}) { + push(@getOwnPropertyDescriptorImpl, " descriptor.setDescriptor(slot.getValue(exec, propertyName), ${namespaceMaybe}DontDelete);\n"); + } else { + push(@getOwnPropertyDescriptorImpl, " descriptor.setDescriptor(slot.getValue(exec, propertyName), ${namespaceMaybe}DontDelete | ${namespaceMaybe}ReadOnly);\n"); + } + } + push(@getOwnPropertyDescriptorImpl, " return true;\n"); + push(@getOwnPropertyDescriptorImpl, " }\n"); + } + + if ($dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"}) { + push(@getOwnPropertyDescriptorImpl, " if (canGetItemsForName(exec, static_cast<$implClassName*>(impl()), propertyName)) {\n"); + push(@getOwnPropertyDescriptorImpl, " ${namespaceMaybe}PropertySlot slot;\n"); + push(@getOwnPropertyDescriptorImpl, " slot.setCustom(this, nameGetter);\n"); + push(@getOwnPropertyDescriptorImpl, " descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);\n"); + push(@getOwnPropertyDescriptorImpl, " return true;\n"); + push(@getOwnPropertyDescriptorImpl, " }\n"); + if ($inlined) { + $headerIncludes{"AtomicString.h"} = 1; + } else { + $implIncludes{"AtomicString.h"} = 1; + } + } + + if ($dataNode->extendedAttributes->{"HasOverridingNameGetter"}) { + &$manualLookupGetterGeneration(); + } + + if ($dataNode->extendedAttributes->{"DelegatingGetOwnPropertySlot"}) { + push(@getOwnPropertyDescriptorImpl, " if (getOwnPropertyDescriptorDelegate(exec, propertyName, descriptor))\n"); + push(@getOwnPropertyDescriptorImpl, " return true;\n"); + } + + if ($hasAttributes) { + if ($inlined) { + die "Cannot inline if NoStaticTables is set." if ($dataNode->extendedAttributes->{"NoStaticTables"}); + push(@getOwnPropertyDescriptorImpl, " return ${namespaceMaybe}getStaticValueDescriptor<$className, Base>(exec, s_info.staticPropHashTable, this, propertyName, descriptor);\n"); + } else { + push(@getOwnPropertyDescriptorImpl, " return ${namespaceMaybe}getStaticValueDescriptor<$className, Base>(exec, " . hashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", this, propertyName, descriptor);\n"); + } + } else { + push(@getOwnPropertyDescriptorImpl, " return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);\n"); + } + + return @getOwnPropertyDescriptorImpl; +} + sub GenerateHeader { my $object = shift; @@ -356,11 +462,12 @@ sub GenerateHeader my $interfaceName = $dataNode->name; my $className = "JS$interfaceName"; my $implClassName = $interfaceName; + my @ancestorInterfaceNames = (); # We only support multiple parents with SVG (for now). if (@{$dataNode->parents} > 1) { die "A class can't have more than one parent" unless $interfaceName =~ /SVG/; - $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode); + $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode, \@ancestorInterfaceNames); } my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"}; @@ -369,7 +476,9 @@ sub GenerateHeader my $parentClassName = GetParentClassName($dataNode); my $conditional = $dataNode->extendedAttributes->{"Conditional"}; my $needsSVGContext = IsSVGTypeNeedingContextParameter($interfaceName); - + my $eventTarget = $dataNode->extendedAttributes->{"EventTarget"}; + my $needsMarkChildren = $dataNode->extendedAttributes->{"CustomMarkFunction"} || $dataNode->extendedAttributes->{"EventTarget"}; + # - Add default header template @headerContentHeader = split("\r", $headerTemplate); @@ -431,17 +540,17 @@ sub GenerateHeader # Constructor if ($interfaceName eq "DOMWindow") { - push(@headerContent, " $className(PassRefPtr<JSC::Structure>, PassRefPtr<$implType>, JSDOMWindowShell*);\n"); + push(@headerContent, " $className(NonNullPassRefPtr<JSC::Structure>, PassRefPtr<$implType>, JSDOMWindowShell*);\n"); } elsif ($dataNode->extendedAttributes->{"IsWorkerContext"}) { - push(@headerContent, " $className(PassRefPtr<JSC::Structure>, PassRefPtr<$implType>);\n"); + push(@headerContent, " $className(NonNullPassRefPtr<JSC::Structure>, PassRefPtr<$implType>);\n"); } elsif (IsSVGTypeNeedingContextParameter($implClassName)) { - push(@headerContent, " $className(PassRefPtr<JSC::Structure>, JSDOMGlobalObject*, PassRefPtr<$implType>, SVGElement* context);\n"); + push(@headerContent, " $className(NonNullPassRefPtr<JSC::Structure>, JSDOMGlobalObject*, PassRefPtr<$implType>, SVGElement* context);\n"); } else { - push(@headerContent, " $className(PassRefPtr<JSC::Structure>, JSDOMGlobalObject*, PassRefPtr<$implType>);\n"); + push(@headerContent, " $className(NonNullPassRefPtr<JSC::Structure>, JSDOMGlobalObject*, PassRefPtr<$implType>);\n"); } # Destructor - push(@headerContent, " virtual ~$className();\n") if (!$hasParent or $interfaceName eq "Document" or $interfaceName eq "DOMWindow"); + push(@headerContent, " virtual ~$className();\n") if (!$hasParent or $eventTarget or $interfaceName eq "Document" or $interfaceName eq "DOMWindow"); # Prototype push(@headerContent, " static JSC::JSObject* createPrototype(JSC::ExecState*, JSC::JSGlobalObject*);\n") unless ($dataNode->extendedAttributes->{"ExtendsDOMGlobalObject"}); @@ -452,6 +561,7 @@ sub GenerateHeader || $dataNode->extendedAttributes->{"GenerateConstructor"} || $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} + || $dataNode->extendedAttributes->{"HasNumericIndexGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"} || $dataNode->extendedAttributes->{"DelegatingGetOwnPropertySlot"} || $dataNode->extendedAttributes->{"HasNameGetter"} @@ -460,8 +570,10 @@ sub GenerateHeader # Getters if ($hasGetter) { push(@headerContent, " virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&);\n"); - push(@headerContent, " virtual bool getOwnPropertySlot(JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&);\n") if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"}) && !$dataNode->extendedAttributes->{"HasOverridingNameGetter"}; + push(@headerContent, " virtual bool getOwnPropertyDescriptor(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertyDescriptor&);\n"); + push(@headerContent, " virtual bool getOwnPropertySlot(JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&);\n") if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) && !$dataNode->extendedAttributes->{"HasOverridingNameGetter"}; push(@headerContent, " bool getOwnPropertySlotDelegate(JSC::ExecState*, const JSC::Identifier&, JSC::PropertySlot&);\n") if $dataNode->extendedAttributes->{"DelegatingGetOwnPropertySlot"}; + push(@headerContent, " bool getOwnPropertyDescriptorDelegate(JSC::ExecState*, const JSC::Identifier&, JSC::PropertyDescriptor&);\n") if $dataNode->extendedAttributes->{"DelegatingGetOwnPropertySlot"}; } # Check if we have any writable properties @@ -503,8 +615,8 @@ sub GenerateHeader " }\n\n"); } - # Custom mark function - push(@headerContent, " virtual void markChildren(JSC::MarkStack&);\n\n") if $dataNode->extendedAttributes->{"CustomMarkFunction"}; + # markChildren function + push(@headerContent, " virtual void markChildren(JSC::MarkStack&);\n\n") if $needsMarkChildren; # Custom pushEventHandlerScope function push(@headerContent, " virtual void pushEventHandlerScope(JSC::ExecState*, JSC::ScopeChain&) const;\n\n") if $dataNode->extendedAttributes->{"CustomPushEventHandlerScope"}; @@ -515,17 +627,23 @@ sub GenerateHeader # Custom deleteProperty function push(@headerContent, " virtual bool deleteProperty(JSC::ExecState*, const JSC::Identifier&);\n") if $dataNode->extendedAttributes->{"CustomDeleteProperty"}; - # Custom getPropertyNames function - push(@headerContent, " virtual void getPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&);\n") if ($dataNode->extendedAttributes->{"CustomGetPropertyNames"} || $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"}); + # Custom getPropertyNames function exists on DOMWindow + push(@headerContent, " virtual void getPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&);\n") if $interfaceName eq "DOMWindow"; + + # Custom defineProperty function exists on DOMWindow + push(@headerContent, " virtual bool defineOwnProperty(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertyDescriptor&, bool shouldThrow);\n") if $interfaceName eq "DOMWindow"; + + # Custom getOwnPropertyNames function + push(@headerContent, " virtual void getOwnPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&);\n") if ($dataNode->extendedAttributes->{"CustomGetPropertyNames"} || $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}); # Custom getPropertyAttributes function push(@headerContent, " virtual bool getPropertyAttributes(JSC::ExecState*, const JSC::Identifier&, unsigned& attributes) const;\n") if $dataNode->extendedAttributes->{"CustomGetPropertyAttributes"}; # Custom defineGetter function - push(@headerContent, " virtual void defineGetter(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* getterFunction);\n") if $dataNode->extendedAttributes->{"CustomDefineGetter"}; + push(@headerContent, " virtual void defineGetter(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* getterFunction, unsigned attributes);\n") if $dataNode->extendedAttributes->{"CustomDefineGetter"}; # Custom defineSetter function - push(@headerContent, " virtual void defineSetter(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* setterFunction);\n") if $dataNode->extendedAttributes->{"CustomDefineSetter"}; + push(@headerContent, " virtual void defineSetter(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* setterFunction, unsigned attributes);\n") if $dataNode->extendedAttributes->{"CustomDefineSetter"}; # Custom lookupGetter function push(@headerContent, " virtual JSC::JSValue lookupGetter(JSC::ExecState*, const JSC::Identifier& propertyName);\n") if $dataNode->extendedAttributes->{"CustomLookupGetter"}; @@ -599,7 +717,7 @@ sub GenerateHeader if ($dataNode->extendedAttributes->{"HasIndexGetter"}) { push(@headerContent, " static JSC::JSValue indexGetter(JSC::ExecState*, const JSC::Identifier&, const JSC::PropertySlot&);\n"); } - if ($dataNode->extendedAttributes->{"HasCustomIndexGetter"}) { + if ($dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) { push(@headerContent, " JSC::JSValue getByIndex(JSC::ExecState*, unsigned index);\n"); } @@ -621,6 +739,10 @@ sub GenerateHeader push(@headerContent, "{\n"); push(@headerContent, GenerateGetOwnPropertySlotBody($dataNode, $interfaceName, $className, $implClassName, $numAttributes > 0, 1)); push(@headerContent, "}\n\n"); + push(@headerContent, "ALWAYS_INLINE bool ${className}::getOwnPropertyDescriptor(JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::PropertyDescriptor& descriptor)\n"); + push(@headerContent, "{\n"); + push(@headerContent, GenerateGetOwnPropertyDescriptorBody($dataNode, $interfaceName, $className, $implClassName, $numAttributes > 0, 1)); + push(@headerContent, "}\n\n"); } if (!$hasParent || $dataNode->extendedAttributes->{"GenerateToJS"} || $dataNode->extendedAttributes->{"CustomToJS"}) { @@ -662,11 +784,19 @@ sub GenerateHeader push(@headerContent, " static const JSC::ClassInfo s_info;\n"); if ($numFunctions > 0 || $numConstants > 0 || $dataNode->extendedAttributes->{"DelegatingPrototypeGetOwnPropertySlot"}) { push(@headerContent, " virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier&, JSC::PropertySlot&);\n"); + push(@headerContent, " virtual bool getOwnPropertyDescriptor(JSC::ExecState*, const JSC::Identifier&, JSC::PropertyDescriptor&);\n"); push(@headerContent, " bool getOwnPropertySlotDelegate(JSC::ExecState*, const JSC::Identifier&, JSC::PropertySlot&);\n") if $dataNode->extendedAttributes->{"DelegatingPrototypeGetOwnPropertySlot"}; + push(@headerContent, " bool getOwnPropertyDescriptorDelegate(JSC::ExecState*, const JSC::Identifier&, JSC::PropertyDescriptor&);\n") if $dataNode->extendedAttributes->{"DelegatingPrototypeGetOwnPropertySlot"}; push(@headerContent, " static PassRefPtr<JSC::Structure> createStructure(JSC::JSValue prototype)\n" . " {\n" . + " return JSC::Structure::create(prototype, JSC::TypeInfo(JSC::ObjectType" . ($needsMarkChildren ? "" : ", JSC::HasDefaultMark") . "));\n" . + " }\n"); + } elsif ($dataNode->extendedAttributes->{"CustomMarkFunction"}) { + push(@headerContent, + " static PassRefPtr<JSC::Structure> createStructure(JSC::JSValue prototype)\n" . + " {\n" . " return JSC::Structure::create(prototype, JSC::TypeInfo(JSC::ObjectType));\n" . " }\n"); } @@ -676,9 +806,9 @@ sub GenerateHeader } # Custom defineGetter function - push(@headerContent, " virtual void defineGetter(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* getterFunction);\n") if $dataNode->extendedAttributes->{"CustomPrototypeDefineGetter"}; + push(@headerContent, " virtual void defineGetter(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* getterFunction, unsigned attributes);\n") if $dataNode->extendedAttributes->{"CustomPrototypeDefineGetter"}; - push(@headerContent, " ${className}Prototype(PassRefPtr<JSC::Structure> structure) : JSC::JSObject(structure) { }\n"); + push(@headerContent, " ${className}Prototype(NonNullPassRefPtr<JSC::Structure> structure) : JSC::JSObject(structure) { }\n"); push(@headerContent, "};\n\n"); @@ -718,6 +848,12 @@ sub GenerateHeader push(@headerContent, "\n} // namespace WebCore\n\n"); push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditional; push(@headerContent, "#endif\n"); + + # - Generate dependencies. + if ($writeDependencies && @ancestorInterfaceNames) { + push(@depsContent, "$className.h : ", join(" ", map { "$_.idl" } @ancestorInterfaceNames), "\n"); + push(@depsContent, map { "$_.idl :\n" } @ancestorInterfaceNames); + } } sub GenerateImplementation @@ -734,6 +870,8 @@ sub GenerateImplementation my $parentClassName = GetParentClassName($dataNode); my $conditional = $dataNode->extendedAttributes->{"Conditional"}; my $visibleClassName = GetVisibleClassName($interfaceName); + my $eventTarget = $dataNode->extendedAttributes->{"EventTarget"}; + my $needsMarkChildren = $dataNode->extendedAttributes->{"CustomMarkFunction"} || $dataNode->extendedAttributes->{"EventTarget"}; # - Add default header template @implContentHeader = split("\r", $headerTemplate); @@ -749,7 +887,7 @@ sub GenerateImplementation AddIncludesForSVGAnimatedType($interfaceName) if $className =~ /^JSSVGAnimated/; $implIncludes{"<wtf/GetPtr.h>"} = 1; - $implIncludes{"<runtime/PropertyNameArray.h>"} = 1 if $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"}; + $implIncludes{"<runtime/PropertyNameArray.h>"} = 1 if $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}; AddIncludesForType($interfaceName); @@ -933,6 +1071,25 @@ sub GenerateImplementation push(@implContent, " return getStaticPropertySlot<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", this, propertyName, slot);\n"); } push(@implContent, "}\n\n"); + + push(@implContent, "bool ${className}Prototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)\n"); + push(@implContent, "{\n"); + + if ($dataNode->extendedAttributes->{"DelegatingPrototypeGetOwnPropertySlot"}) { + push(@implContent, " if (getOwnPropertyDescriptorDelegate(exec, propertyName, descriptor))\n"); + push(@implContent, " return true;\n"); + } + + if ($numConstants eq 0 && $numFunctions eq 0) { + push(@implContent, " return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);\n"); + } elsif ($numConstants eq 0) { + push(@implContent, " return getStaticFunctionDescriptor<JSObject>(exec, " . prototypeHashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", this, propertyName, descriptor);\n"); + } elsif ($numFunctions eq 0) { + push(@implContent, " return getStaticValueDescriptor<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", this, propertyName, descriptor);\n"); + } else { + push(@implContent, " return getStaticPropertyDescriptor<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", this, propertyName, descriptor);\n"); + } + push(@implContent, "}\n\n"); } if ($dataNode->extendedAttributes->{"DelegatingPrototypePutFunction"}) { @@ -980,15 +1137,15 @@ sub GenerateImplementation # Constructor if ($interfaceName eq "DOMWindow") { AddIncludesForType("JSDOMWindowShell"); - push(@implContent, "${className}::$className(PassRefPtr<Structure> structure, PassRefPtr<$implType> impl, JSDOMWindowShell* shell)\n"); + push(@implContent, "${className}::$className(NonNullPassRefPtr<Structure> structure, PassRefPtr<$implType> impl, JSDOMWindowShell* shell)\n"); push(@implContent, " : $parentClassName(structure, impl, shell)\n"); } elsif ($dataNode->extendedAttributes->{"IsWorkerContext"}) { AddIncludesForType($interfaceName); - push(@implContent, "${className}::$className(PassRefPtr<Structure> structure, PassRefPtr<$implType> impl)\n"); + push(@implContent, "${className}::$className(NonNullPassRefPtr<Structure> structure, PassRefPtr<$implType> impl)\n"); push(@implContent, " : $parentClassName(structure, impl)\n"); } else { my $contextArg = $needsSVGContext ? ", SVGElement* context" : ""; - push(@implContent, "${className}::$className(PassRefPtr<Structure> structure, JSDOMGlobalObject* globalObject, PassRefPtr<$implType> impl$contextArg)\n"); + push(@implContent, "${className}::$className(NonNullPassRefPtr<Structure> structure, JSDOMGlobalObject* globalObject, PassRefPtr<$implType> impl$contextArg)\n"); if ($hasParent) { push(@implContent, " : $parentClassName(structure, globalObject, impl" . ($parentNeedsSVGContext ? ", context" : "") . ")\n"); } else { @@ -1000,17 +1157,17 @@ sub GenerateImplementation push(@implContent, "}\n\n"); # Destructor - if (!$hasParent || $interfaceName eq "DOMWindow") { + if (!$hasParent || $eventTarget) { push(@implContent, "${className}::~$className()\n"); push(@implContent, "{\n"); + if ($eventTarget) { + $implIncludes{"RegisteredEventListener.h"} = 1; + push(@implContent, " impl()->invalidateEventListeners();\n"); + } + if ($interfaceName eq "Node") { - $implIncludes{"RegisteredEventListener.h"} = 1; - push(@implContent, " invalidateEventListeners(m_impl->eventListeners());\n"); - push(@implContent, " forgetDOMNode(m_impl->document(), m_impl.get());\n"); - } elsif ($interfaceName eq "DOMWindow") { - $implIncludes{"RegisteredEventListener.h"} = 1; - push(@implContent, " invalidateEventListeners(impl()->eventListeners());\n"); + push(@implContent, " forgetDOMNode(impl()->document(), impl());\n"); } else { if ($podType) { my $animatedType = $implClassName; @@ -1021,7 +1178,7 @@ sub GenerateImplementation push(@implContent, " JSSVGDynamicPODTypeWrapperCache<$podType, $animatedType>::forgetWrapper(m_impl.get());\n"); } } - push(@implContent, " forgetDOMObject(*Heap::heap(this)->globalData(), m_impl.get());\n"); + push(@implContent, " forgetDOMObject(*Heap::heap(this)->globalData(), impl());\n"); } push(@implContent, "}\n\n"); @@ -1034,6 +1191,14 @@ sub GenerateImplementation push(@implContent, "{\n forgetDOMObject(*Heap::heap(this)->globalData(), static_cast<${implClassName}*>(impl()));\n}\n\n"); } + if ($needsMarkChildren && !$dataNode->extendedAttributes->{"CustomMarkFunction"}) { + push(@implContent, "void ${className}::markChildren(MarkStack& markStack)\n"); + push(@implContent, "{\n"); + push(@implContent, " Base::markChildren(markStack);\n"); + push(@implContent, " impl()->markEventListeners(markStack);\n"); + push(@implContent, "}\n\n"); + } + if (!$dataNode->extendedAttributes->{"ExtendsDOMGlobalObject"}) { push(@implContent, "JSObject* ${className}::createPrototype(ExecState* exec, JSGlobalObject* globalObject)\n"); push(@implContent, "{\n"); @@ -1049,6 +1214,7 @@ sub GenerateImplementation || $dataNode->extendedAttributes->{"GenerateConstructor"} || $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} + || $dataNode->extendedAttributes->{"HasNumericIndexGetter"} || $dataNode->extendedAttributes->{"DelegatingGetOwnPropertySlot"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"} || $dataNode->extendedAttributes->{"HasNameGetter"} @@ -1061,14 +1227,18 @@ sub GenerateImplementation push(@implContent, "{\n"); push(@implContent, GenerateGetOwnPropertySlotBody($dataNode, $interfaceName, $className, $implClassName, $numAttributes > 0, 0)); push(@implContent, "}\n\n"); + push(@implContent, "bool ${className}::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)\n"); + push(@implContent, "{\n"); + push(@implContent, GenerateGetOwnPropertyDescriptorBody($dataNode, $interfaceName, $className, $implClassName, $numAttributes > 0, 0)); + push(@implContent, "}\n\n"); } - if (($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"}) + if (($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) && !$dataNode->extendedAttributes->{"HasOverridingNameGetter"}) { push(@implContent, "bool ${className}::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)\n"); push(@implContent, "{\n"); push(@implContent, " if (propertyName < static_cast<$implClassName*>(impl())->length()) {\n"); - if ($dataNode->extendedAttributes->{"HasCustomIndexGetter"}) { + if ($dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) { push(@implContent, " slot.setValue(getByIndex(exec, propertyName));\n"); } else { push(@implContent, " slot.setCustomIndex(this, propertyName, indexGetter);\n"); @@ -1124,7 +1294,11 @@ sub GenerateImplementation push(@implContent, " UNUSED_PARAM(exec);\n"); push(@implContent, " $implClassName* imp = static_cast<$implClassName*>(castedThis->impl());\n"); push(@implContent, " if (EventListener* listener = imp->$implGetterFunctionName()) {\n"); - push(@implContent, " if (JSObject* jsFunction = listener->jsFunction())\n"); + if ($implClassName eq "Document" || $implClassName eq "WorkerContext" || $implClassName eq "SharedWorkerContext" || $implClassName eq "DedicatedWorkerContext") { + push(@implContent, " if (JSObject* jsFunction = listener->jsFunction(imp))\n"); + } else { + push(@implContent, " if (JSObject* jsFunction = listener->jsFunction(imp->scriptExecutionContext()))\n"); + } push(@implContent, " return jsFunction;\n"); push(@implContent, " }\n"); push(@implContent, " return jsNull();\n"); @@ -1333,14 +1507,14 @@ sub GenerateImplementation } } - if (($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"}) && !$dataNode->extendedAttributes->{"CustomGetPropertyNames"}) { - push(@implContent, "void ${className}::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)\n"); + if (($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) && !$dataNode->extendedAttributes->{"CustomGetPropertyNames"}) { + push(@implContent, "void ${className}::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)\n"); push(@implContent, "{\n"); - if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"}) { + if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) { push(@implContent, " for (unsigned i = 0; i < static_cast<${implClassName}*>(impl())->length(); ++i)\n"); push(@implContent, " propertyNames.add(Identifier::from(exec, i));\n"); } - push(@implContent, " Base::getPropertyNames(exec, propertyNames);\n"); + push(@implContent, " Base::getOwnPropertyNames(exec, propertyNames);\n"); push(@implContent, "}\n\n"); } @@ -1373,7 +1547,7 @@ sub GenerateImplementation push(@implContent, " if (!castedThisObj)\n"); push(@implContent, " return throwError(exec, TypeError);\n"); } else { - push(@implContent, " if (!thisValue.isObject(&${className}::s_info))\n"); + push(@implContent, " if (!thisValue.inherits(&${className}::s_info))\n"); push(@implContent, " return throwError(exec, TypeError);\n"); push(@implContent, " $className* castedThisObj = static_cast<$className*>(asObject(thisValue));\n"); } @@ -1507,6 +1681,17 @@ sub GenerateImplementation $implIncludes{"Node.h"} = 1; } } + + if ($dataNode->extendedAttributes->{"HasNumericIndexGetter"}) { + push(@implContent, "\nJSValue ${className}::getByIndex(ExecState* exec, unsigned index)\n"); + push(@implContent, "{\n"); + push(@implContent, " return jsNumber(exec, static_cast<$implClassName*>(impl())->item(index));\n"); + push(@implContent, "}\n"); + if ($interfaceName eq "HTMLCollection") { + $implIncludes{"JSNode.h"} = 1; + $implIncludes{"Node.h"} = 1; + } + } if ((!$hasParent or $dataNode->extendedAttributes->{"GenerateToJS"}) and !$dataNode->extendedAttributes->{"CustomToJS"}) { if ($podType) { @@ -1537,7 +1722,7 @@ sub GenerateImplementation push(@implContent, "{\n"); - push(@implContent, " return value.isObject(&${className}::s_info) ? " . ($podType ? "($podType) *" : "") . "static_cast<$className*>(asObject(value))->impl() : "); + push(@implContent, " return value.inherits(&${className}::s_info) ? " . ($podType ? "($podType) *" : "") . "static_cast<$className*>(asObject(value))->impl() : "); if ($podType and $podType ne "float") { push(@implContent, "$podType();\n}\n"); } else { @@ -1657,6 +1842,11 @@ sub JSValueToNative return "$value.toString(exec)"; } + if ($type eq "SerializedScriptValue") { + $implIncludes{"SerializedScriptValue.h"} = 1; + return "SerializedScriptValue::create(exec, $value)"; + } + $implIncludes{"FloatPoint.h"} = 1 if $type eq "SVGPoint"; $implIncludes{"FloatRect.h"} = 1 if $type eq "SVGRect"; $implIncludes{"HTMLOptionElement.h"} = 1 if $type eq "HTMLOptionElement"; @@ -1762,6 +1952,9 @@ sub NativeToJSValue $joinedName = $type; $joinedName =~ s/Abs|Rel//; $implIncludes{"$joinedName.h"} = 1; + } elsif ($type eq "SerializedScriptValue") { + $implIncludes{"$type.h"} = 1; + return "$value->deserialize(exec)"; } else { # Default, include header with same name. $implIncludes{"JS$type.h"} = 1; @@ -2021,6 +2214,15 @@ sub WriteData @headerContent = (); %headerIncludes = (); } + + if (defined($DEPS)) { + # Write dependency file. + print $DEPS @depsContent; + close($DEPS); + undef($DEPS); + + @depsContent = (); + } } sub constructorFor @@ -2041,6 +2243,7 @@ public: putDirect(exec->propertyNames().prototype, ${protoClassName}::self(exec, globalObject), None); } virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual const ClassInfo* classInfo() const { return &s_info; } static const ClassInfo s_info; @@ -2074,6 +2277,11 @@ bool ${constructorClassName}::getOwnPropertySlot(ExecState* exec, const Identifi return getStaticValueSlot<${constructorClassName}, DOMObject>(exec, &${constructorClassName}Table, this, propertyName, slot); } +bool ${constructorClassName}::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + return getStaticValueDescriptor<${constructorClassName}, DOMObject>(exec, &${constructorClassName}Table, this, propertyName, descriptor); +} + EOF $implJSCInclude{"JSNumberCell.h"} = 1; # FIXME: What is this for? diff --git a/WebCore/bindings/scripts/CodeGeneratorObjC.pm b/WebCore/bindings/scripts/CodeGeneratorObjC.pm index f449e19..317086b 100644 --- a/WebCore/bindings/scripts/CodeGeneratorObjC.pm +++ b/WebCore/bindings/scripts/CodeGeneratorObjC.pm @@ -4,6 +4,7 @@ # Copyright (C) 2006, 2007 Samuel Weinig <sam@webkit.org> # Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org> # Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. +# Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au> # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public @@ -28,6 +29,7 @@ use File::stat; # Global Variables my $module = ""; my $outputDir = ""; +my $writeDependencies = 0; my %publicInterfaces = (); my $newPublicClass = 0; my $interfaceAvailabilityVersion = ""; @@ -49,6 +51,7 @@ my @internalHeaderContent = (); my @implContentHeader = (); my @implContent = (); my %implIncludes = (); +my @depsContent = (); # Hashes my %protocolTypeHash = ("XPathNSResolver" => 1, "EventListener" => 1, "EventTarget" => 1, "NodeFilter" => 1, @@ -194,6 +197,9 @@ sub new $codeGenerator = shift; $outputDir = shift; + shift; # $useLayerOnTop + shift; # $preprocessor + $writeDependencies = shift; bless($reference, $object); return $reference; @@ -305,7 +311,7 @@ sub GetClassName my $name = $codeGenerator->StripModule(shift); # special cases - return "NSString" if $codeGenerator->IsStringType($name); + return "NSString" if $codeGenerator->IsStringType($name) or $name eq "SerializedScriptValue"; return "NS$name" if IsNativeObjCType($name); return "BOOL" if $name eq "boolean"; return "unsigned" if $name eq "unsigned long"; @@ -486,6 +492,11 @@ sub GetObjCTypeGetter return "WTF::getPtr(nativeEventListener)" if $type eq "EventListener"; return "WTF::getPtr(nativeNodeFilter)" if $type eq "NodeFilter"; return "WTF::getPtr(nativeResolver)" if $type eq "XPathNSResolver"; + + if ($type eq "SerializedScriptValue") { + $implIncludes{"SerializedScriptValue.h"} = 1; + return "WebCore::SerializedScriptValue::create(WebCore::String($argName))"; + } return "core($argName)"; } @@ -601,6 +612,11 @@ sub AddIncludesForType return; } + if ($type eq "SerializedScriptValue") { + $implIncludes{"SerializedScriptValue.h"} = 1; + return; + } + # FIXME: won't compile without these $implIncludes{"CSSMutableStyleDeclaration.h"} = 1 if $type eq "CSSStyleDeclaration"; $implIncludes{"NameNodeList.h"} = 1 if $type eq "NodeList"; @@ -976,8 +992,10 @@ sub GenerateImplementation my $object = shift; my $dataNode = shift; + my @ancestorInterfaceNames = (); + if (@{$dataNode->parents} > 1) { - $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode); + $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode, \@ancestorInterfaceNames); } my $interfaceName = $dataNode->name; @@ -1204,6 +1222,9 @@ sub GenerateImplementation } elsif ($idlType eq "Color") { $getterContentHead = "WebCore::nsColor($getterContentHead"; $getterContentTail .= ")"; + } elsif ($attribute->signature->type eq "SerializedScriptValue") { + $getterContentHead = "$getterContentHead"; + $getterContentTail .= "->toString()"; } elsif (ConversionNeeded($attribute->signature->type)) { $getterContentHead = "kit(WTF::getPtr($getterContentHead"; $getterContentTail .= "))"; @@ -1438,6 +1459,8 @@ sub GenerateImplementation push(@functionContent, " return $toReturn;\n"); push(@functionContent, " return nil;\n"); } + } elsif ($returnType eq "SerializedScriptValue") { + $content = "foo"; } else { if (ConversionNeeded($function->signature->type)) { if ($codeGenerator->IsPodType($function->signature->type)) { @@ -1543,6 +1566,12 @@ sub GenerateImplementation # - End the ifdef conditional if necessary push(@implContent, "\n#endif // ${conditionalString}\n") if $conditional; + + # - Generate dependencies. + if ($writeDependencies && @ancestorInterfaceNames) { + push(@depsContent, "$className.h : ", join(" ", map { "$_.idl" } @ancestorInterfaceNames), "\n"); + push(@depsContent, map { "$_.idl :\n" } @ancestorInterfaceNames); + } } # Internal helper @@ -1556,12 +1585,14 @@ sub WriteData my $privateHeaderFileName = "$outputDir/" . $name . "Private.h"; my $implFileName = "$outputDir/" . $name . ".mm"; my $internalHeaderFileName = "$outputDir/" . $name . "Internal.h"; + my $depsFileName = "$outputDir/" . $name . ".dep"; # Remove old files. unlink($headerFileName); unlink($privateHeaderFileName); unlink($implFileName); unlink($internalHeaderFileName); + unlink($depsFileName); # Write public header. open(HEADER, ">$headerFileName") or die "Couldn't open file $headerFileName"; @@ -1624,6 +1655,14 @@ sub WriteData @internalHeaderContent = (); } + + # Write dependency file. + if (@depsContent) { + open(DEPS, ">$depsFileName") or die "Couldn't open file $depsFileName"; + print DEPS @depsContent; + close(DEPS); + @depsContent = (); + } } 1; diff --git a/WebCore/bindings/scripts/CodeGeneratorV8.pm b/WebCore/bindings/scripts/CodeGeneratorV8.pm index 439f368..b65da53 100644 --- a/WebCore/bindings/scripts/CodeGeneratorV8.pm +++ b/WebCore/bindings/scripts/CodeGeneratorV8.pm @@ -5,6 +5,7 @@ # Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org> # Copyright (C) 2006 Apple Computer, Inc. # Copyright (C) 2007, 2008, 2009 Google Inc. +# Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au> # # This file is part of the KDE project # @@ -90,26 +91,6 @@ sub leftShift($$) { return (($value << $distance) & 0xFFFFFFFF); } -# Uppercase the first letter, while respecting WebKit style guidelines. -# E.g., xmlEncoding becomes XMLEncoding, but xmlllang becomes Xmllang. -sub WK_ucfirst -{ - my $param = shift; - my $ret = ucfirst($param); - $ret =~ s/Xml/XML/ if $ret =~ /^Xml[^a-z]/; - return $ret; -} - -# Lowercase the first letter while respecting WebKit style guidelines. -# URL becomes url, but SetURL becomes setURL. -sub WK_lcfirst -{ - my $param = shift; - my $ret = lcfirst($param); - $ret =~ s/uRL/url/; - return $ret; -} - # Workaround for V8 bindings difference where RGBColor is not a POD type. sub IsPodType { @@ -266,7 +247,7 @@ sub GenerateHeader # Copy contents of parent classes except the first parent or if it is # EventTarget. - $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode); + $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode, \@allParents, 1); my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"}; my $conditionalString = GenerateConditionalString($dataNode); @@ -345,6 +326,28 @@ sub IsNodeSubType return 0; } +sub GetHiddenDependencyIndex +{ + my $dataNode = shift; + my $attribute = shift; + my $name = $dataNode->name; + return "V8Custom::kNodeEventListenerCacheIndex" if IsNodeSubType($dataNode); + return "V8Custom::kSVGElementInstanceEventListenerCacheIndex" if $name eq "SVGElementInstance"; + return "V8Custom::kAbstractWorkerRequestCacheIndex" if $name eq "AbstractWorker"; + return "V8Custom::kWorkerRequestCacheIndex" if $name eq "Worker"; + return "V8Custom::kDedicatedWorkerContextRequestCacheIndex" if $name eq "DedicatedWorkerContext"; + return "V8Custom::kWorkerContextRequestCacheIndex" if $name eq "WorkerContext"; + return "V8Custom::kWorkerContextRequestCacheIndex" if $name eq "SharedWorkerContext"; + return "V8Custom::kMessagePortRequestCacheIndex" if $name eq "MessagePort"; + return "V8Custom::kWebSocketCacheIndex" if $name eq "WebSocket"; + return "V8Custom::kXMLHttpRequestCacheIndex" if $name eq "XMLHttpRequest"; + return "V8Custom::kXMLHttpRequestCacheIndex" if $name eq "XMLHttpRequestUpload"; + return "V8Custom::kDOMApplicationCacheCacheIndex" if $name eq "DOMApplicationCache"; + return "V8Custom::kNotificationRequestCacheIndex" if $name eq "Notification"; + return "V8Custom::kDOMWindowEventListenerCacheIndex" if $name eq "DOMWindow"; + die "Unexpected name " . $name . " when generating " . $attribute; +} + sub HolderToNative { my $dataNode = shift; @@ -513,11 +516,17 @@ END } } elsif ($attrExt->{"v8OnProto"} || $attrExt->{"V8DisallowShadowing"}) { + if ($classIndex eq "DOMWINDOW") { + push(@implContentDecls, <<END); + v8::Handle<v8::Object> holder = info.Holder(); +END + } else { # perform lookup first push(@implContentDecls, <<END); v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::$classIndex, info.This()); if (holder.IsEmpty()) return v8::Undefined(); END + } HolderToNative($dataNode, $implClassName, $classIndex); } else { push(@implContentDecls, <<END); @@ -543,7 +552,7 @@ END $attrName = $attribute->signature->extendedAttributes->{"v8referenceattr"}; } - my $getterFunc = WK_lcfirst($attrName); + my $getterFunc = $codeGenerator->WK_lcfirst($attrName); $getterFunc .= "Animated" if $codeGenerator->IsSVGAnimatedType($attribute->signature->type); my $returnType = GetTypeFromSignature($attribute->signature); @@ -582,7 +591,7 @@ END my $getter = $getterString; $getter =~ s/imp->//; $getter =~ s/\(\)//; - my $setter = "set" . WK_ucfirst($getter); + my $setter = "set" . $codeGenerator->WK_ucfirst($getter); my $implClassIsAnimatedType = $codeGenerator->IsSVGAnimatedType($implClassName); if (not $implClassIsAnimatedType and $codeGenerator->IsPodTypeWithWriteableProperties($attrType) and not defined $attribute->signature->extendedAttributes->{"Immutable"}) { @@ -607,6 +616,10 @@ END } } else { + if ($attribute->signature->type eq "EventListener" && $dataNode->name eq "DOMWindow") { + push(@implContentDecls, " if (!imp->document())\n"); + push(@implContentDecls, " return v8::Undefined();\n"); + } push(@implContentDecls, " $nativeType v = "); push(@implContentDecls, "$getterString;\n"); @@ -685,11 +698,17 @@ sub GenerateNormalAttrSetter push(@implContentDecls, " $implClassName* imp = &imp_instance;\n"); } elsif ($attrExt->{"v8OnProto"}) { + if ($classIndex eq "DOMWINDOW") { + push(@implContentDecls, <<END); + v8::Handle<v8::Object> holder = info.Holder(); +END + } else { # perform lookup first push(@implContentDecls, <<END); v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::$classIndex, info.This()); - if (holder.IsEmpty()) return v8::Undefined(); + if (holder.IsEmpty()) return; END + } HolderToNative($dataNode, $implClassName, $classIndex); } else { push(@implContentDecls, <<END); @@ -699,7 +718,15 @@ END } my $nativeType = GetNativeTypeFromSignature($attribute->signature, 0); - push(@implContentDecls, " $nativeType v = " . JSValueToNative($attribute->signature, "value") . ";\n"); + if ($attribute->signature->type eq "EventListener") { + if ($dataNode->name eq "DOMWindow") { + push(@implContentDecls, " if (!imp->document())\n"); + push(@implContentDecls, " return;\n"); + } + push(@implContentDecls, " $nativeType v = V8DOMWrapper::getEventListener(imp, value, true, ListenerFindOrCreate);\n"); + } else { + push(@implContentDecls, " $nativeType v = " . JSValueToNative($attribute->signature, "value") . ";\n"); + } my $result = ""; if ($nativeType eq "int" and $attribute->signature->extendedAttributes->{"ConvertFromString"}) { @@ -724,13 +751,27 @@ END if ($implClassName eq "double") { push(@implContentDecls, " *imp = $result;\n"); } else { - my $implSetterFunctionName = WK_ucfirst($attrName); + my $implSetterFunctionName = $codeGenerator->WK_ucfirst($attrName); my $reflect = $attribute->signature->extendedAttributes->{"Reflect"}; my $reflectURL = $attribute->signature->extendedAttributes->{"ReflectURL"}; if ($reflect || $reflectURL) { $implIncludes{"HTMLNames.h"} = 1; my $contentAttributeName = ($reflect || $reflectURL) eq "1" ? $attrName : ($reflect || $reflectURL); push(@implContentDecls, " imp->setAttribute(HTMLNames::${contentAttributeName}Attr, $result"); + } elsif ($attribute->signature->type eq "EventListener") { + $implIncludes{"V8AbstractEventListener.h"} = 1; + $implIncludes{"V8CustomBinding.h"} = 1; + $cacheIndex = GetHiddenDependencyIndex($dataNode, $attrName); + push(@implContentDecls, " $nativeType old = imp->$attrName();\n"); + push(@implContentDecls, " V8AbstractEventListener* oldListener = old ? V8AbstractEventListener::cast(old.get()) : 0;\n"); + push(@implContentDecls, " if (oldListener) {\n"); + push(@implContentDecls, " v8::Local<v8::Object> oldListenerObject = oldListener->getExistingListenerObject();\n"); + push(@implContentDecls, " if (!oldListenerObject.IsEmpty())\n"); + push(@implContentDecls, " removeHiddenDependency(holder, oldListenerObject, $cacheIndex);\n"); + push(@implContentDecls, " }\n"); + push(@implContentDecls, " imp->set$implSetterFunctionName($result);\n"); + push(@implContentDecls, " if ($result)\n"); + push(@implContentDecls, " createHiddenDependency(holder, value, $cacheIndex"); } else { push(@implContentDecls, " imp->set$implSetterFunctionName(" . $result); } @@ -779,7 +820,7 @@ sub GenerateNewFunctionTemplate my $customFunc = $function->signature->extendedAttributes->{"Custom"} || $function->signature->extendedAttributes->{"V8Custom"}; if ($customFunc eq 1) { - $customFunc = $interfaceName . WK_ucfirst($name); + $customFunc = $interfaceName . $codeGenerator->WK_ucfirst($name); } return "v8::FunctionTemplate::New(V8Custom::v8${customFunc}Callback, v8::Handle<v8::Value>(), $signature)"; } else { @@ -841,6 +882,11 @@ END push(@implContentDecls, " ScriptCallStack callStack(args, $numParameters);\n"); $implIncludes{"ScriptCallStack.h"} = 1; } + if ($function->signature->extendedAttributes->{"SVGCheckSecurityDocument"}) { + push(@implContentDecls, +" if (!V8Proxy::checkNodeSecurity(imp->getSVGDocument(ec)))\n" . +" return v8::Undefined();\n"); + } my $paramIndex = 0; foreach my $parameter (@{$function->parameters}) { @@ -893,7 +939,8 @@ END sub GenerateBatchedAttributeData { - my $interfaceName = shift; + my $dataNode = shift; + my $interfaceName = $dataNode->name; my $attributes = shift; foreach my $attribute (@$attributes) { @@ -926,7 +973,7 @@ sub GenerateBatchedAttributeData ""; if ($customAccessor eq 1) { # use the naming convension, interface + (capitalize) attr name - $customAccessor = $interfaceName . WK_ucfirst($attrName); + $customAccessor = $interfaceName . $codeGenerator->WK_ucfirst($attrName); } my $getter; @@ -950,79 +997,41 @@ sub GenerateBatchedAttributeData my $constructorType = $codeGenerator->StripModule($attribute->signature->type); $constructorType =~ s/Constructor$//; my $constructorIndex = uc($constructorType); - $data = "V8ClassIndex::${constructorIndex}"; - $getter = "${interfaceName}Internal::${interfaceName}ConstructorGetter"; - $setter = "0"; - $propAttr = "v8::ReadOnly"; - - # EventListeners - } elsif ($attribute->signature->type eq "EventListener") { - if ($interfaceName eq "DOMWindow") { - $getter = "V8Custom::v8DOMWindowEventHandlerAccessorGetter"; - $setter = "V8Custom::v8DOMWindowEventHandlerAccessorSetter"; - } elsif ($interfaceName eq "Element" || $interfaceName eq "Document" || $interfaceName eq "HTMLBodyElement" || $interfaceName eq "SVGElementInstance" || $interfaceName eq "HTMLFrameSetElement") { - $getter = "V8Custom::v8NodeEventHandlerAccessorGetter"; - $setter = "V8Custom::v8NodeEventHandlerAccessorSetter"; - } elsif ($interfaceName eq "DOMApplicationCache") { - $getter = "V8Custom::v8DOMApplicationCacheEventHandlerAccessorGetter"; - $setter = "V8Custom::v8DOMApplicationCacheEventHandlerAccessorSetter"; - } else { + if ($customAccessor) { $getter = "V8Custom::v8${customAccessor}AccessorGetter"; - if ($interfaceName eq "WorkerContext" and $attrName eq "self") { - $setter = "0"; - $propAttr = "v8::ReadOnly"; - } else { - $setter = "V8Custom::v8${customAccessor}AccessorSetter"; - } - } - - # Custom Getter and Setter - } elsif ($attrExt->{"Custom"} || $attrExt->{"V8Custom"}) { - $getter = "V8Custom::v8${customAccessor}AccessorGetter"; - if ($interfaceName eq "WorkerContext" and $attrName eq "self") { - $setter = "0"; - $propAttr = "v8::ReadOnly"; } else { - $hasCustomSetter = 1; - $setter = "V8Custom::v8${customAccessor}AccessorSetter"; + $data = "V8ClassIndex::${constructorIndex}"; + $getter = "${interfaceName}Internal::${interfaceName}ConstructorGetter"; } + $setter = "0"; + $propAttr = "v8::ReadOnly"; - # Custom Setter - } elsif ($attrExt->{"CustomSetter"} || $attrExt->{"V8CustomSetter"}) { - $hasCustomSetter = 1; + } else { + # Default Getter and Setter $getter = "${interfaceName}Internal::${attrName}AttrGetter"; - $setter = "V8Custom::v8${customAccessor}AccessorSetter"; - - # Custom Getter - } elsif ($attrExt->{"CustomGetter"}) { - $getter = "V8Custom::v8${customAccessor}AccessorGetter"; $setter = "${interfaceName}Internal::${attrName}AttrSetter"; - # Replaceable - } elsif ($attrExt->{"Replaceable"}) { - # Replaceable accessor is put on instance template with ReadOnly attribute. - $getter = "${interfaceName}Internal::${attrName}AttrGetter"; - $setter = "0"; - - # Mark to avoid duplicate v8::ReadOnly flags in output. - $hasCustomSetter = 1; - - # Handle the special case of window.top being marked upstream as Replaceable. - # FIXME: Investigate why [Replaceable] is not marked as ReadOnly - # upstream and reach parity. - if (!($interfaceName eq "DOMWindow" and $attrName eq "top")) { - $propAttr .= "|v8::ReadOnly"; + # Custom Setter + if ($attrExt->{"CustomSetter"} || $attrExt->{"V8CustomSetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) { + $hasCustomSetter = 1; + $setter = "V8Custom::v8${customAccessor}AccessorSetter"; } - # Normal - } else { - $getter = "${interfaceName}Internal::${attrName}AttrGetter"; - $setter = "${interfaceName}Internal::${attrName}AttrSetter"; + # Custom Getter + if ($attrExt->{"CustomGetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) { + $getter = "V8Custom::v8${customAccessor}AccessorGetter"; + } } + # Replaceable if ($attrExt->{"Replaceable"} && !$hasCustomSetter) { $setter = "0"; - $propAttr .= "|v8::ReadOnly"; + # Handle the special case of window.top being marked as Replaceable. + # FIXME: Investigate whether we could treat window.top as replaceable + # and allow shadowing without it being a security hole. + if (!($interfaceName eq "DOMWindow" and $attrName eq "top")) { + $propAttr .= "|v8::ReadOnly"; + } } # Read only attributes @@ -1068,8 +1077,6 @@ sub GenerateImplementation my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"}; my $conditionalString = GenerateConditionalString($dataNode); - @allParents = $codeGenerator->FindParentsRecursively($dataNode); - # - Add default header template @implContentHeader = split("\r", $headerTemplate); @@ -1104,20 +1111,16 @@ sub GenerateImplementation # Generate special code for the constructor attributes. if ($attrType =~ /Constructor$/) { - $hasConstructors = 1; + if ($attribute->signature->extendedAttributes->{"CustomGetter"}) { + $implIncludes{"V8CustomBinding.h"} = 1; + } else { + $hasConstructors = 1; + } next; } - # Make EventListeners always custom. - # FIXME: make the perl code capable of generating the - # event setters/getters. For now, WebKit has started removing the - # [Custom] attribute, so just automatically insert it to avoid forking - # other files. This should be okay because we can't generate stubs - # for any event getter/setters anyway. - if ($attrType eq "EventListener") { - $attribute->signature->extendedAttributes->{"Custom"} = 1; - $implIncludes{"V8CustomBinding.h"} = 1; - next; + if ($attrType eq "EventListener" && $interfaceName eq "DOMWindow") { + $attribute->signature->extendedAttributes->{"v8OnProto"} = 1; } # Do not generate accessor if this is a custom attribute. The @@ -1186,7 +1189,7 @@ sub GenerateImplementation # Put the attributes that disallow shadowing on the shadow object. $attributes = \@normal; push(@implContent, "static const BatchedAttribute shadow_attrs[] = {\n"); - GenerateBatchedAttributeData($interfaceName, \@disallows_shadowing); + GenerateBatchedAttributeData($dataNode, \@disallows_shadowing); push(@implContent, "};\n"); } @@ -1194,7 +1197,7 @@ sub GenerateImplementation if (@$attributes) { $has_attributes = 1; push(@implContent, "static const BatchedAttribute ${interfaceName}_attrs[] = {\n"); - GenerateBatchedAttributeData($interfaceName, $attributes); + GenerateBatchedAttributeData($dataNode, $attributes); push(@implContent, "};\n"); } @@ -1472,7 +1475,7 @@ sub GenerateFunctionCallString() $paramName = "SVGPODListItem<" . GetNativeType($paramType, 1) . ">::copy($paramName)"; } - if ($parameter->type eq "NodeFilter") { + if ($parameter->type eq "NodeFilter" || $parameter->type eq "XPathNSResolver") { $functionString .= "$paramName.get()"; } else { $functionString .= $paramName; @@ -1590,7 +1593,7 @@ sub GetTypeFromSignature my $signature = shift; my $type = $codeGenerator->StripModule($signature->type); - if (($type eq "DOMString") && $signature->extendedAttributes->{"V8Custom"}) { + if (($type eq "DOMString") && $signature->extendedAttributes->{"HintAtomic"}) { $type = "AtomicString"; } @@ -1605,6 +1608,11 @@ sub GetNativeTypeFromSignature my $type = GetTypeFromSignature($signature); + if ($type eq "unsigned long" and $signature->extendedAttributes->{"IsIndex"}) { + # Special-case index arguments because we need to check that they aren't < 0. + return "int"; + } + return GetNativeType($type, $isParameter); } @@ -1612,7 +1620,24 @@ sub IsRefPtrType { my $type = shift; return 1 if $type eq "Attr"; + return 1 if $type eq "CanvasArray"; + return 1 if $type eq "CanvasArrayBuffer"; + return 1 if $type eq "CanvasBooleanArray"; + return 1 if $type eq "CanvasByteArray"; + return 1 if $type eq "CanvasBuffer"; + return 1 if $type eq "CanvasFloatArray"; + return 1 if $type eq "CanvasFramebuffer"; return 1 if $type eq "CanvasGradient"; + return 1 if $type eq "CanvasIntArray"; + return 1 if $type eq "CanvasObject"; + return 1 if $type eq "CanvasProgram"; + return 1 if $type eq "CanvasRenderbuffer"; + return 1 if $type eq "CanvasShader"; + return 1 if $type eq "CanvasShortArray"; + return 1 if $type eq "CanvasTexture"; + return 1 if $type eq "CanvasUnsignedByteArray"; + return 1 if $type eq "CanvasUnsignedIntArray"; + return 1 if $type eq "CanvasUnsignedShortArray"; return 1 if $type eq "ClientRect"; return 1 if $type eq "ClientRectList"; return 1 if $type eq "CDATASection"; @@ -1636,6 +1661,7 @@ sub IsRefPtrType return 1 if $type eq "Element"; return 1 if $type eq "EntityReference"; return 1 if $type eq "Event"; + return 1 if $type eq "EventListener"; return 1 if $type eq "FileList"; return 1 if $type eq "HTMLCollection"; return 1 if $type eq "HTMLDocument"; @@ -1653,6 +1679,7 @@ sub IsRefPtrType return 1 if $type eq "Plugin"; return 1 if $type eq "ProcessingInstruction"; return 1 if $type eq "Range"; + return 1 if $type eq "RGBColor"; return 1 if $type eq "Text"; return 1 if $type eq "TextMetrics"; return 1 if $type eq "TimeRanges"; @@ -1708,7 +1735,8 @@ sub GetNativeType return "int" if $type eq "int"; return "int" if $type eq "short" or $type eq "unsigned short"; - return "int" if $type eq "long" or $type eq "unsigned long"; + return "unsigned" if $type eq "unsigned long"; + return "int" if $type eq "long"; return "unsigned long long" if $type eq "unsigned long long"; return "bool" if $type eq "boolean"; return "String" if $type eq "DOMString"; @@ -1729,6 +1757,9 @@ sub GetNativeType # temporary hack return "RefPtr<NodeFilter>" if $type eq "NodeFilter"; + # necessary as resolvers could be constructed on fly. + return "RefPtr<XPathNSResolver>" if $type eq "XPathNSResolver"; + return "RefPtr<${type}>" if IsRefPtrType($type) and not $isParameter; # Default, assume native type is a pointer with same type name as idl type @@ -1739,6 +1770,19 @@ sub GetNativeType my %typeCanFailConversion = ( "AtomicString" => 0, "Attr" => 1, + "CanvasArray" => 0, + "CanvasBuffer" => 0, + "CanvasByteArray" => 0, + "CanvasFloatArray" => 0, + "CanvasFramebuffer" => 0, + "CanvasGradient" => 0, + "CanvasIntArray" => 0, + "CanvasPixelArray" => 0, + "CanvasProgram" => 0, + "CanvasRenderbuffer" => 0, + "CanvasShader" => 0, + "CanvasShortArray" => 0, + "CanvasTexture" => 0, "CompareHow" => 0, "DataGridColumn" => 0, "DOMString" => 0, @@ -1748,8 +1792,11 @@ my %typeCanFailConversion = ( "Event" => 0, "EventListener" => 0, "EventTarget" => 0, + "HTMLCanvasElement" => 0, "HTMLElement" => 0, + "HTMLImageElement" => 0, "HTMLOptionElement" => 0, + "HTMLVideoElement" => 0, "Node" => 0, "NodeFilter" => 0, "MessagePort" => 0, @@ -1837,7 +1884,11 @@ sub JSValueToNative return "static_cast<Range::CompareHow>($value->Int32Value())" if $type eq "CompareHow"; return "static_cast<SVGPaint::SVGPaintType>($value->ToInt32()->Int32Value())" if $type eq "SVGPaintType"; - return "v8ValueToAtomicWebCoreString($value)" if $type eq "AtomicString"; + if ($type eq "AtomicString") { + return "v8ValueToAtomicWebCoreStringWithNullCheck($value)" if $signature->extendedAttributes->{"ConvertNullToNullString"}; + return "v8ValueToAtomicWebCoreString($value)"; + } + return "toWebCoreString($value)" if $type eq "DOMUserData"; if ($type eq "DOMString") { return "toWebCoreStringWithNullCheck($value)" if $signature->extendedAttributes->{"ConvertNullToNullString"}; @@ -1845,6 +1896,11 @@ sub JSValueToNative return "toWebCoreString($value)"; } + if ($type eq "SerializedScriptValue") { + $implIncludes{"SerializedScriptValue.h"} = 1; + return "SerializedScriptValue::create($value)"; + } + if ($type eq "NodeFilter") { return "V8DOMWrapper::wrapNativeNodeFilter($value)"; } @@ -1866,6 +1922,10 @@ sub JSValueToNative return "V8Node::HasInstance($value) ? V8DOMWrapper::convertDOMWrapperToNode<Node>(v8::Handle<v8::Object>::Cast($value)) : 0"; } + if ($type eq "XPathNSResolver") { + return "V8DOMWrapper::getXPathNSResolver($value)"; + } + AddIncludesForType($type); # $implIncludes{"$type.h"} = 1 unless AvoidInclusionOfType($type); @@ -1917,10 +1977,16 @@ sub CreateCustomSignature if ($first) { $first = 0; } else { $result .= ", "; } if (IsWrapperType($parameter->type)) { - my $type = $parameter->type; - my $header = GetV8HeaderName($type); - $implIncludes{$header} = 1; - $result .= "V8${type}::GetRawTemplate()"; + if ($parameter->type eq "XPathNSResolver") { + # Special case for XPathNSResolver. All other browsers accepts a callable, + # so, even though it's against IDL, accept objects here. + $result .= "v8::Handle<v8::FunctionTemplate>()"; + } else { + my $type = $parameter->type; + my $header = GetV8HeaderName($type); + $implIncludes{$header} = 1; + $result .= "V8${type}::GetRawTemplate()"; + } } else { $result .= "v8::Handle<v8::FunctionTemplate>()"; } @@ -2063,12 +2129,17 @@ sub ReturnNativeToJSValue return "return V8DOMWrapper::convertEventListenerToV8Object($value)"; } + if ($type eq "SerializedScriptValue") { + $implIncludes{"$type.h"} = 1; + return "return v8String($value->toString())"; + } + if ($type eq "DedicatedWorkerContext" or $type eq "WorkerContext" or $type eq "SharedWorkerContext") { $implIncludes{"WorkerContextExecutionProxy.h"} = 1; return "return WorkerContextExecutionProxy::convertWorkerContextToV8Object($value)"; } - if ($type eq "WorkerLocation" or $type eq "WorkerNavigator") { + if ($type eq "WorkerLocation" or $type eq "WorkerNavigator" or $type eq "NotificationCenter") { $implIncludes{"WorkerContextExecutionProxy.h"} = 1; my $classIndex = uc($type); diff --git a/WebCore/bindings/scripts/IDLParser.pm b/WebCore/bindings/scripts/IDLParser.pm index c4cb041..4abdb45 100644 --- a/WebCore/bindings/scripts/IDLParser.pm +++ b/WebCore/bindings/scripts/IDLParser.pm @@ -309,7 +309,11 @@ sub ParseInterface $methodException =~ s/\s+//g; @{$newDataNode->raisesExceptions} = split(/,/, $methodException); - my @params = split(/,/, $methodSignature); + # Split arguments at commas but only if the comma + # is not within attribute brackets, expressed here + # as being followed by a ']' without a preceding '['. + # Note that this assumes that attributes don't nest. + my @params = split(/,(?![^[]*\])/, $methodSignature); foreach(@params) { my $line = $_; diff --git a/WebCore/bindings/scripts/generate-bindings.pl b/WebCore/bindings/scripts/generate-bindings.pl index 9c374bf..c7adeb3 100755 --- a/WebCore/bindings/scripts/generate-bindings.pl +++ b/WebCore/bindings/scripts/generate-bindings.pl @@ -42,12 +42,14 @@ my $outputDirectory; my $generator; my $defines; my $preprocessor; +my $writeDependencies; GetOptions('include=s@' => \@idlDirectories, 'outputDir=s' => \$outputDirectory, 'generator=s' => \$generator, 'defines=s' => \$defines, - 'preprocessor=s' => \$preprocessor); + 'preprocessor=s' => \$preprocessor, + 'write-dependencies' => \$writeDependencies); my $idlFile = $ARGV[0]; @@ -65,5 +67,5 @@ my $parser = IDLParser->new(1); my $document = $parser->Parse($idlFile, $defines, $preprocessor); # Generate desired output for given IDL file. -my $codeGen = CodeGenerator->new(\@idlDirectories, $generator, $outputDirectory, 0, $preprocessor); +my $codeGen = CodeGenerator->new(\@idlDirectories, $generator, $outputDirectory, 0, $preprocessor, $writeDependencies); $codeGen->ProcessDocument($document, $defines); diff --git a/WebCore/bindings/v8/ChildThreadDOMData.h b/WebCore/bindings/v8/ChildThreadDOMData.h index ab90e5b..173a5e8 100644 --- a/WebCore/bindings/v8/ChildThreadDOMData.h +++ b/WebCore/bindings/v8/ChildThreadDOMData.h @@ -39,7 +39,9 @@ namespace WebCore { class ChildThreadDOMData : public DOMData { public: ChildThreadDOMData(); +#if PLATFORM(ANDROID) virtual ~ChildThreadDOMData() { } +#endif DOMDataStore& getStore(); diff --git a/WebCore/bindings/v8/DOMData.h b/WebCore/bindings/v8/DOMData.h index 07e14e5..e67adb4 100644 --- a/WebCore/bindings/v8/DOMData.h +++ b/WebCore/bindings/v8/DOMData.h @@ -45,7 +45,9 @@ namespace WebCore { class DOMData : public Noncopyable { public: DOMData(); +#if PLATFORM(ANDROID) virtual ~DOMData() { } +#endif static DOMData* getCurrent(); static DOMData* getCurrentMainThread(); // Caller must be on the main thread. diff --git a/WebCore/bindings/v8/DOMObjectsInclude.h b/WebCore/bindings/v8/DOMObjectsInclude.h index 6f36f3b..fb7ba81 100644 --- a/WebCore/bindings/v8/DOMObjectsInclude.h +++ b/WebCore/bindings/v8/DOMObjectsInclude.h @@ -31,13 +31,31 @@ #ifndef DOMObjectsInclude_h #define DOMObjectsInclude_h -#include "AbstractWorker.h" #include "BarInfo.h" +#include "BeforeLoadEvent.h" +#include "CanvasArray.h" +#include "CanvasArrayBuffer.h" +#include "CanvasBuffer.h" +#include "CanvasByteArray.h" +#include "CanvasFloatArray.h" +#include "CanvasFramebuffer.h" #include "CanvasGradient.h" +#include "CanvasIntArray.h" +#include "CanvasObject.h" #include "CanvasPattern.h" #include "CanvasPixelArray.h" +#include "CanvasProgram.h" +#include "CanvasRenderbuffer.h" +#include "CanvasRenderingContext.h" #include "CanvasRenderingContext2D.h" +#include "CanvasRenderingContext3D.h" +#include "CanvasShader.h" +#include "CanvasShortArray.h" +#include "CanvasUnsignedByteArray.h" +#include "CanvasUnsignedIntArray.h" +#include "CanvasUnsignedShortArray.h" #include "CanvasStyle.h" +#include "CanvasTexture.h" #include "CharacterData.h" #include "ClientRect.h" #include "ClientRectList.h" @@ -57,7 +75,6 @@ #include "CSSValueList.h" #include "CSSVariablesDeclaration.h" #include "CSSVariablesRule.h" -#include "Database.h" #include "DocumentType.h" #include "DocumentFragment.h" #include "DOMCoreException.h" @@ -86,7 +103,6 @@ #include "HTMLSelectElement.h" #include "HTMLOptionsCollection.h" #include "ImageData.h" -#include "InspectorBackend.h" #include "KeyboardEvent.h" #include "Location.h" #include "Media.h" @@ -106,6 +122,7 @@ #include "NodeIterator.h" #include "OverflowEvent.h" #include "Page.h" +#include "PageTransitionEvent.h" #include "Plugin.h" #include "PluginArray.h" #include "ProcessingInstruction.h" @@ -118,11 +135,6 @@ #include "ScriptExecutionContext.h" #include "SecurityOrigin.h" #include "Settings.h" -#include "SharedWorker.h" -#include "SharedWorkerContext.h" -#include "SQLTransaction.h" -#include "SQLResultSet.h" -#include "SQLResultSetRowList.h" #include "StyleSheet.h" #include "StyleSheetList.h" #include "TextEvent.h" @@ -135,9 +147,7 @@ #include "V8HTMLElement.h" #include "V8LazyEventListener.h" #include "V8NodeFilterCondition.h" -#include "V8ObjectEventListener.h" #include "ValidityState.h" -#include "VoidCallback.h" #include "WebKitAnimationEvent.h" #include "WebKitCSSKeyframeRule.h" #include "WebKitCSSKeyframesRule.h" @@ -151,16 +161,18 @@ #include "XMLHttpRequestProgressEvent.h" #include "XMLHttpRequestUpload.h" #include "XMLSerializer.h" -#include "XPathException.h" -#include "XPathExpression.h" -#include "XPathNSResolver.h" -#include "XPathResult.h" -#include "XSLTProcessor.h" #if ENABLE(OFFLINE_WEB_APPLICATIONS) #include "DOMApplicationCache.h" #endif +#if ENABLE(DATABASE) +#include "Database.h" +#include "SQLTransaction.h" +#include "SQLResultSet.h" +#include "SQLResultSetRowList.h" +#endif // DATABASE + #if ENABLE(DATAGRID) #include "DataGridColumn.h" #include "DataGridColumnList.h" @@ -215,13 +227,21 @@ #include "V8SVGPODTypeWrapper.h" #endif // SVG +#if PLATFORM(ANDROID) +// TODO: Upstream TOUCH_EVENTS guard. #if ENABLE(TOUCH_EVENTS) #include "Touch.h" #include "TouchList.h" #include "TouchEvent.h" #endif +#endif + +#if ENABLE(WEB_SOCKETS) +#include "WebSocket.h" +#endif #if ENABLE(WORKERS) +#include "AbstractWorker.h" #include "DedicatedWorkerContext.h" #include "Worker.h" #include "WorkerContext.h" @@ -229,10 +249,32 @@ #include "WorkerNavigator.h" #endif // WORKERS +#if ENABLE(SHARED_WORKERS) +#include "SharedWorker.h" +#include "SharedWorkerContext.h" +#endif // SHARED_WORKERS + +#if ENABLE(NOTIFICATIONS) +#include "Notification.h" +#include "NotificationCenter.h" +#endif // NOTIFICATIONS + #if ENABLE(XPATH) #include "XPathEvaluator.h" +#include "XPathException.h" +#include "XPathExpression.h" +#include "XPathNSResolver.h" +#include "XPathResult.h" #endif // XPATH +#if ENABLE(XSLT) +#include "XSLTProcessor.h" +#endif // XSLT + +#if ENABLE(INSPECTOR) +#include "InspectorBackend.h" +#endif // INSPECTOR + namespace WebCore { // A helper class for undetectable document.all diff --git a/WebCore/bindings/v8/DateExtension.cpp b/WebCore/bindings/v8/DateExtension.cpp new file mode 100644 index 0000000..778a15a --- /dev/null +++ b/WebCore/bindings/v8/DateExtension.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DateExtension.h" + +#include "V8Proxy.h" +#include "V8HiddenPropertyName.h" + +namespace WebCore { + +DateExtension* DateExtension::extension; + +static const char* dateExtensionName = "v8/DateExtension"; +static const char* dateExtensionScript = + "(function () {" + " var counter;" + " var orig_getTime;" + " function getTimeOverride() {" + " if (++counter > 1000)" + " OnSleepDetected();" + " return orig_getTime.call(this);" + " };" + " function enableSleepDetection(enable) {" + " if (enable) {" + " counter = 0;" + " orig_getTime = Date.prototype.getTime;" + " Date.prototype.getTime = getTimeOverride;" + " } else {" + " Date.prototype.getTime = orig_getTime;" + " }" + " };" + " native function Setup();" + " native function OnSleepDetected();" + " Setup(Date, enableSleepDetection);" + "})()"; + +DateExtension::DateExtension() : v8::Extension(dateExtensionName, dateExtensionScript) +{ +} + +DateExtension* DateExtension::get() +{ + if (!extension) + extension = new DateExtension(); + return extension; +} + +void DateExtension::setAllowSleep(bool allow) +{ + v8::Local<v8::Value> result = V8Proxy::retrieve()->context()->Global()->Get(v8::String::New("Date")); + if (result.IsEmpty()) + return; + + v8::Handle<v8::Object> dateObject = v8::Handle<v8::Object>::Cast(result); + if (dateObject.IsEmpty()) + return; + + v8::Local<v8::Value> sleepFunctionHandle = dateObject->GetHiddenValue(V8HiddenPropertyName::sleepFunction()); + if (sleepFunctionHandle.IsEmpty() || !sleepFunctionHandle->IsFunction()) + return; + + v8::Handle<v8::Value> argv[1]; + argv[0] = v8::String::New(allow ? "false" : "true"); + v8::Handle<v8::Function>::Cast(sleepFunctionHandle)->Call(v8::Object::New(), 1, argv); +} + +v8::Handle<v8::FunctionTemplate> DateExtension::GetNativeFunction(v8::Handle<v8::String> name) +{ + if (name->Equals(v8::String::New("Setup"))) + return v8::FunctionTemplate::New(Setup); + if (name->Equals(v8::String::New("OnSleepDetected"))) + return v8::FunctionTemplate::New(OnSleepDetected); + + return v8::Handle<v8::FunctionTemplate>(); +} + +v8::Handle<v8::Value> DateExtension::Setup(const v8::Arguments& args) +{ + if (args.Length() != 2 || !args[0]->IsObject() || !args[1]->IsFunction()) + return v8::Undefined(); + + v8::Handle<v8::Object> dateObject = v8::Handle<v8::Object>::Cast(args[0]); + v8::Handle<v8::Function> enableSleepDetectionFunction = v8::Handle<v8::Function>::Cast(args[1]); + + dateObject->SetHiddenValue(V8HiddenPropertyName::sleepFunction(), enableSleepDetectionFunction); + return v8::Undefined(); +} + +v8::Handle<v8::Value> DateExtension::OnSleepDetected(const v8::Arguments&) +{ + v8::V8::TerminateExecution(); + return v8::Undefined(); +} + +} // namespace WebCore diff --git a/WebCore/bindings/v8/DateExtension.h b/WebCore/bindings/v8/DateExtension.h new file mode 100644 index 0000000..2bccac4 --- /dev/null +++ b/WebCore/bindings/v8/DateExtension.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DateExtension_h +#define DateExtension_h + +#include <v8.h> + +namespace WebCore { + +// Prevent "sleep" calls in unload handlers. +class DateExtension : public v8::Extension { +public: + static DateExtension* get(); + void setAllowSleep(bool allow); + +private: + DateExtension(); + virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(v8::Handle<v8::String>); + static v8::Handle<v8::Value> Setup(const v8::Arguments&); + static v8::Handle<v8::Value> OnSleepDetected(const v8::Arguments&); + + static DateExtension* extension; +}; + +} // namespace WebCore + +#endif // DateExtension_h diff --git a/WebCore/bindings/v8/DerivedSourcesAllInOne.cpp b/WebCore/bindings/v8/DerivedSourcesAllInOne.cpp index e52a505..98832f3 100644 --- a/WebCore/bindings/v8/DerivedSourcesAllInOne.cpp +++ b/WebCore/bindings/v8/DerivedSourcesAllInOne.cpp @@ -33,10 +33,28 @@ #include "bindings/V8Attr.cpp" #include "bindings/V8BarInfo.cpp" +#include "bindings/V8BeforeLoadEvent.cpp" +#include "bindings/V8CanvasArray.cpp" +#include "bindings/V8CanvasArrayBuffer.cpp" +#include "bindings/V8CanvasBuffer.cpp" +#include "bindings/V8CanvasByteArray.cpp" +#include "bindings/V8CanvasFloatArray.cpp" +#include "bindings/V8CanvasFramebuffer.cpp" #include "bindings/V8CanvasGradient.cpp" +#include "bindings/V8CanvasIntArray.cpp" #include "bindings/V8CanvasPattern.cpp" #include "bindings/V8CanvasPixelArray.cpp" +#include "bindings/V8CanvasProgram.cpp" +#include "bindings/V8CanvasRenderbuffer.cpp" +#include "bindings/V8CanvasRenderingContext.cpp" #include "bindings/V8CanvasRenderingContext2D.cpp" +#include "bindings/V8CanvasRenderingContext3D.cpp" +#include "bindings/V8CanvasShader.cpp" +#include "bindings/V8CanvasShortArray.cpp" +#include "bindings/V8CanvasTexture.cpp" +#include "bindings/V8CanvasUnsignedByteArray.cpp" +#include "bindings/V8CanvasUnsignedIntArray.cpp" +#include "bindings/V8CanvasUnsignedShortArray.cpp" #include "bindings/V8CDATASection.cpp" #include "bindings/V8CharacterData.cpp" #include "bindings/V8ClientRect.cpp" @@ -150,11 +168,6 @@ #include "bindings/V8HTMLUListElement.cpp" #include "bindings/V8HTMLVideoElement.cpp" #include "bindings/V8ImageData.cpp" -#if PLATFORM(ANDROID) -// No inspector for now -#else -#include "bindings/V8InspectorBackend.cpp" -#endif #include "bindings/V8KeyboardEvent.cpp" #include "bindings/V8Location.cpp" #include "bindings/V8Media.cpp" @@ -175,6 +188,7 @@ #include "bindings/V8NodeList.cpp" #include "bindings/V8Notation.cpp" #include "bindings/V8OverflowEvent.cpp" +#include "bindings/V8PageTransitionEvent.cpp" #include "bindings/V8Plugin.cpp" #include "bindings/V8PluginArray.cpp" #include "bindings/V8ProcessingInstruction.cpp" @@ -207,6 +221,18 @@ #include "bindings/V8XMLHttpRequestUpload.cpp" #include "bindings/V8XMLSerializer.cpp" +#if ENABLE(OFFLINE_WEB_APPLICATIONS) +#include "bindings/V8DOMApplicationCache.cpp" +#endif + +#if ENABLE(DOM_STORAGE) +#include "bindings/V8Storage.cpp" +#include "bindings/V8StorageEvent.cpp" +#endif + +#if ENABLE(WEB_SOCKETS) +#include "bindings/V8WebSocket.cpp" +#endif #if ENABLE(DATABASE) #include "bindings/V8Database.cpp" @@ -216,14 +242,17 @@ #include "bindings/V8SQLTransaction.cpp" #endif - -#if ENABLE(OFFLINE_WEB_APPLICATIONS) -#include "bindings/V8DOMApplicationCache.cpp" +#if ENABLE(WORKERS) +#include "bindings/V8AbstractWorker.cpp" +#include "bindings/V8DedicatedWorkerContext.cpp" +#include "bindings/V8Worker.cpp" +#include "bindings/V8WorkerContext.cpp" +#include "bindings/V8WorkerLocation.cpp" +#include "bindings/V8WorkerNavigator.cpp" #endif -#if ENABLE(DOM_STORAGE) -#include "bindings/V8Storage.cpp" -#include "bindings/V8StorageEvent.cpp" +#if ENABLE(SHARED_WORKERS) +#include "bindings/V8SharedWorker.cpp" #endif #if ENABLE(SVG) @@ -251,7 +280,6 @@ #include "bindings/V8SVGClipPathElement.cpp" #include "bindings/V8SVGColor.cpp" #include "bindings/V8SVGCursorElement.cpp" -#include "bindings/V8SVGDefinitionSrcElement.cpp" #include "bindings/V8SVGDefsElement.cpp" #include "bindings/V8SVGDescElement.cpp" #include "bindings/V8SVGDocument.cpp" @@ -339,16 +367,6 @@ #include "bindings/V8SVGZoomEvent.cpp" #endif -#if ENABLE(WORKERS) -#include "bindings/V8AbstractWorker.cpp" -#include "bindings/V8DedicatedWorkerContext.cpp" -#include "bindings/V8SharedWorker.cpp" -#include "bindings/V8Worker.cpp" -#include "bindings/V8WorkerContext.cpp" -#include "bindings/V8WorkerLocation.cpp" -#include "bindings/V8WorkerNavigator.cpp" -#endif - #if ENABLE(XPATH) #include "bindings/V8XPathEvaluator.cpp" #include "bindings/V8XPathException.cpp" @@ -360,3 +378,15 @@ #if ENABLE(XSLT) #include "bindings/V8XSLTProcessor.cpp" #endif + +#if ENABLE(INSPECTOR) +#include "bindings/V8InspectorBackend.cpp" +#endif + +#if PLATFORM(ANDROID) +// TODO: Upstream NOTIFICATIONS guard. +#if ENABLE(NOTIFICATIONS) +#include "bindings/V8Notification.cpp" +#include "bindings/V8NotificationCenter.cpp" +#endif +#endif diff --git a/WebCore/bindings/v8/NPV8Object.cpp b/WebCore/bindings/v8/NPV8Object.cpp index cb2a6c1..13403ec 100644 --- a/WebCore/bindings/v8/NPV8Object.cpp +++ b/WebCore/bindings/v8/NPV8Object.cpp @@ -276,7 +276,7 @@ bool _NPN_EvaluateHelper(NPP npp, bool popupsAllowed, NPObject* npObject, NPStri filename = "npscript"; WebCore::String script = WebCore::String::fromUTF8(npScript->UTF8Characters, npScript->UTF8Length); - v8::Local<v8::Value> v8result = proxy->evaluate(WebCore::ScriptSourceCode(script, WebCore::KURL(filename)), 0); + v8::Local<v8::Value> v8result = proxy->evaluate(WebCore::ScriptSourceCode(script, WebCore::KURL(WebCore::ParsedURLString, filename)), 0); if (v8result.IsEmpty()) return false; @@ -413,8 +413,12 @@ bool _NPN_HasMethod(NPP npp, NPObject* npObject, NPIdentifier methodName) void _NPN_SetException(NPObject* npObject, const NPUTF8 *message) { - if (npObject->_class != npScriptObjectClass) + if (npObject->_class != npScriptObjectClass) { + // We won't be able to find a proper scope for this exception, so just throw it. + // This is consistent with JSC, which throws a global exception all the time. + V8Proxy::throwError(V8Proxy::GeneralError, message); return; + } v8::HandleScope handleScope; v8::Handle<v8::Context> context = toV8Context(0, npObject); if (context.IsEmpty()) diff --git a/WebCore/bindings/v8/OwnHandle.h b/WebCore/bindings/v8/OwnHandle.h index 6580674..17c551c 100644 --- a/WebCore/bindings/v8/OwnHandle.h +++ b/WebCore/bindings/v8/OwnHandle.h @@ -45,15 +45,13 @@ namespace WebCore { v8::Handle<T> get() const { return m_handle; } void set(v8::Handle<T> handle) { clear(); m_handle = v8::Persistent<T>::New(handle); } - // FIXME: What if we release a weak handle? Won't the callback do the wrong thing? - v8::Persistent<T> release() { v8::Persistent<T> result = m_handle; m_handle.Clear(); return result; } - void adopt(v8::Persistent<T> handle) { clear(); m_handle = handle; } - // Note: This is clear in the OwnPtr sense, not the v8::Handle sense. void clear() { if (m_handle.IsEmpty()) return; + if (m_handle.IsWeak()) + m_handle.ClearWeak(); m_handle.Dispose(); m_handle.Clear(); } diff --git a/WebCore/bindings/v8/ScheduledAction.cpp b/WebCore/bindings/v8/ScheduledAction.cpp index 44e8a37..268e177 100644 --- a/WebCore/bindings/v8/ScheduledAction.cpp +++ b/WebCore/bindings/v8/ScheduledAction.cpp @@ -44,8 +44,9 @@ namespace WebCore { -ScheduledAction::ScheduledAction(v8::Handle<v8::Function> func, int argc, v8::Handle<v8::Value> argv[]) - : m_code(String(), KURL(), 0) +ScheduledAction::ScheduledAction(v8::Handle<v8::Context> context, v8::Handle<v8::Function> func, int argc, v8::Handle<v8::Value> argv[]) + : m_context(context) + , m_code(String(), KURL(), 0) { m_function = v8::Persistent<v8::Function>::New(func); @@ -107,7 +108,7 @@ void ScheduledAction::execute(V8Proxy* proxy) LOCK_V8; v8::HandleScope handleScope; - v8::Local<v8::Context> v8Context = proxy->context(); + v8::Handle<v8::Context> v8Context = v8::Local<v8::Context>::New(m_context.get()); if (v8Context.IsEmpty()) return; // JS may not be enabled. @@ -136,7 +137,7 @@ void ScheduledAction::execute(WorkerContext* workerContext) if (!m_function.IsEmpty() && m_function->IsFunction()) { LOCK_V8; v8::HandleScope handleScope; - v8::Local<v8::Context> v8Context = scriptController->proxy()->context(); + v8::Handle<v8::Context> v8Context = v8::Local<v8::Context>::New(m_context.get()); ASSERT(!v8Context.IsEmpty()); v8::Context::Scope scope(v8Context); m_function->Call(v8Context->Global(), m_argc, m_argv); diff --git a/WebCore/bindings/v8/ScheduledAction.h b/WebCore/bindings/v8/ScheduledAction.h index 53694c7..003885f 100644 --- a/WebCore/bindings/v8/ScheduledAction.h +++ b/WebCore/bindings/v8/ScheduledAction.h @@ -31,7 +31,9 @@ #ifndef ScheduledAction_h #define ScheduledAction_h +#include "OwnHandle.h" #include "ScriptSourceCode.h" +#include "V8GCController.h" #include <v8.h> @@ -44,9 +46,10 @@ namespace WebCore { class ScheduledAction { public: - ScheduledAction(v8::Handle<v8::Function>, int argc, v8::Handle<v8::Value> argv[]); - explicit ScheduledAction(const WebCore::String& code, const KURL& url = KURL()) - : m_argc(0) + ScheduledAction(v8::Handle<v8::Context>, v8::Handle<v8::Function>, int argc, v8::Handle<v8::Value> argv[]); + explicit ScheduledAction(v8::Handle<v8::Context> context, const WebCore::String& code, const KURL& url = KURL()) + : m_context(context) + , m_argc(0) , m_argv(0) , m_code(code, url) { @@ -61,6 +64,7 @@ namespace WebCore { void execute(WorkerContext*); #endif + OwnHandle<v8::Context> m_context; v8::Persistent<v8::Function> m_function; int m_argc; v8::Persistent<v8::Value>* m_argv; diff --git a/WebCore/bindings/v8/ScriptCallFrame.cpp b/WebCore/bindings/v8/ScriptCallFrame.cpp index ab30862..4c29814 100644 --- a/WebCore/bindings/v8/ScriptCallFrame.cpp +++ b/WebCore/bindings/v8/ScriptCallFrame.cpp @@ -42,7 +42,7 @@ namespace WebCore { ScriptCallFrame::ScriptCallFrame(const String& functionName, const String& urlString, int lineNumber, const v8::Arguments& arguments, unsigned skipArgumentCount) : m_functionName(functionName) - , m_sourceURL(urlString) + , m_sourceURL(ParsedURLString, urlString) , m_lineNumber(lineNumber) { for (int i = 0; i < arguments.Length(); ++i) diff --git a/WebCore/bindings/v8/ScriptController.cpp b/WebCore/bindings/v8/ScriptController.cpp index 48c5115..85af072 100644 --- a/WebCore/bindings/v8/ScriptController.cpp +++ b/WebCore/bindings/v8/ScriptController.cpp @@ -51,7 +51,6 @@ #include "npruntime_priv.h" #include "NPV8Object.h" #include "ScriptSourceCode.h" -#include "ScriptState.h" #include "Widget.h" #include "XSSAuditor.h" @@ -61,6 +60,15 @@ namespace WebCore { +void ScriptController::initializeThreading() +{ + static bool initializedThreading = false; + if (!initializedThreading) { + WTF::initializeThreading(); + initializedThreading = true; + } +} + void ScriptController::setFlags(const char* string, int length) { v8::V8::SetFlagsFromString(string, length); @@ -96,7 +104,6 @@ ScriptController::ScriptController(Frame* frame) , m_sourceURL(0) , m_processingTimerCallback(false) , m_paused(false) - , m_scriptState(new ScriptState(frame)) , m_proxy(new V8Proxy(frame)) #if ENABLE(NETSCAPE_PLUGIN_API) , m_windowScriptNPObject(0) @@ -186,9 +193,14 @@ bool ScriptController::processingUserGesture() const return false; } -void ScriptController::evaluateInNewWorld(const Vector<ScriptSourceCode>& sources, int extensionGroup) +void ScriptController::evaluateInIsolatedWorld(unsigned worldID, const Vector<ScriptSourceCode>& sources) +{ + m_proxy->evaluateInIsolatedWorld(worldID, sources, 0); +} + +void ScriptController::evaluateInIsolatedWorld(unsigned worldID, const Vector<ScriptSourceCode>& sources, int extensionGroup) { - m_proxy->evaluateInNewWorld(sources, extensionGroup); + m_proxy->evaluateInIsolatedWorld(worldID, sources, extensionGroup); } void ScriptController::evaluateInNewContext(const Vector<ScriptSourceCode>& sources, int extensionGroup) @@ -202,12 +214,7 @@ ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode) LOCK_V8; String sourceURL = sourceCode.url(); - if (sourceURL.isNull() && !m_XSSAuditor->canEvaluateJavaScriptURL(sourceCode.source())) { - // This JavaScript URL is not safe to be evaluated. - return ScriptValue(); - } - - if (!sourceURL.isNull() && !m_XSSAuditor->canEvaluate(sourceCode.source())) { + if (!m_XSSAuditor->canEvaluate(sourceCode.source())) { // This script is not safe to be evaluated. return ScriptValue(); } @@ -343,7 +350,7 @@ PassScriptInstance ScriptController::createScriptInstanceForWidget(Widget* widge return V8ScriptInstance::create(wrapper); } -void ScriptController::cleanupScriptObjectsForPlugin(void* nativeHandle) +void ScriptController::cleanupScriptObjectsForPlugin(Widget* nativeHandle) { PluginObjectMap::iterator it = m_pluginObjects.find(nativeHandle); if (it == m_pluginObjects.end()) diff --git a/WebCore/bindings/v8/ScriptController.h b/WebCore/bindings/v8/ScriptController.h index d614619..ec15103 100644 --- a/WebCore/bindings/v8/ScriptController.h +++ b/WebCore/bindings/v8/ScriptController.h @@ -46,7 +46,6 @@ namespace WebCore { class Frame; class HTMLPlugInElement; class ScriptSourceCode; - class ScriptState; class String; class Widget; class XSSAuditor; @@ -60,16 +59,27 @@ namespace WebCore { // or this accessor should be made JSProxy* V8Proxy* proxy() { return m_proxy.get(); } + // This function must be called from the main thread. It is safe to call it repeatedly. + static void initializeThreading(); + // Evaluate a script file in the environment of this proxy. // If succeeded, 'succ' is set to true and result is returned // as a string. ScriptValue evaluate(const ScriptSourceCode&); - // Executes JavaScript in a new world associated with the web frame. The - // script gets its own global scope, its own prototypes for intrinsic - // JavaScript objects (String, Array, and so-on), and its own wrappers for - // all DOM nodes and DOM constructors. - void evaluateInNewWorld(const Vector<ScriptSourceCode>&, int extensionGroup); + void evaluateInIsolatedWorld(unsigned worldID, const Vector<ScriptSourceCode>&); + + // Executes JavaScript in an isolated world. The script gets its own global scope, + // its own prototypes for intrinsic JavaScript objects (String, Array, and so-on), + // and its own wrappers for all DOM nodes and DOM constructors. + // + // If an isolated world with the specified ID already exists, it is reused. + // Otherwise, a new world is created. + // + // If the worldID is 0, a new world is always created. + // + // FIXME: Get rid of extensionGroup here. + void evaluateInIsolatedWorld(unsigned worldID, const Vector<ScriptSourceCode>&, int extensionGroup); // Executes JavaScript in a new context associated with the web frame. The // script gets its own global scope and its own prototypes for intrinsic @@ -86,8 +96,6 @@ namespace WebCore { // with what JSC does as well. ScriptController* windowShell() { return this; } - ScriptState* state() const { return m_scriptState.get(); } - XSSAuditor* xssAuditor() { return m_XSSAuditor.get(); } void collectGarbage(); @@ -146,7 +154,7 @@ namespace WebCore { void updateSecurityOrigin(); void clearScriptObjects(); void updatePlatformScriptObjects(); - void cleanupScriptObjectsForPlugin(void*); + void cleanupScriptObjectsForPlugin(Widget*); #if ENABLE(NETSCAPE_PLUGIN_API) NPObject* createScriptObjectForPluginElement(HTMLPlugInElement*); @@ -160,9 +168,8 @@ namespace WebCore { bool m_processingTimerCallback; bool m_paused; - OwnPtr<ScriptState> m_scriptState; OwnPtr<V8Proxy> m_proxy; - typedef HashMap<void*, NPObject*> PluginObjectMap; + typedef HashMap<Widget*, NPObject*> PluginObjectMap; // A mapping between Widgets and their corresponding script object. // This list is used so that when the plugin dies, we can immediately diff --git a/WebCore/bindings/v8/ScriptEventListener.cpp b/WebCore/bindings/v8/ScriptEventListener.cpp index 7a8aa64..16ca70f 100644 --- a/WebCore/bindings/v8/ScriptEventListener.cpp +++ b/WebCore/bindings/v8/ScriptEventListener.cpp @@ -33,7 +33,11 @@ #include "Attribute.h" #include "Document.h" +#include "EventListener.h" #include "Frame.h" +#include "ScriptScope.h" +#include "V8AbstractEventListener.h" +#include "V8Binding.h" #include "XSSAuditor.h" namespace WebCore { @@ -68,4 +72,18 @@ PassRefPtr<V8LazyEventListener> createAttributeEventListener(Frame* frame, Attri return V8LazyEventListener::create(frame, attr->value(), attr->localName().string(), frame->document()->isSVGDocument()); } +String getEventListenerHandlerBody(ScriptExecutionContext*, ScriptState* scriptState, EventListener* listener) +{ + if (listener->type() != EventListener::JSEventListenerType) + return ""; + + ScriptScope scope(scriptState); + V8AbstractEventListener* v8Listener = static_cast<V8AbstractEventListener*>(listener); + v8::Handle<v8::Object> function = v8Listener->getListenerObject(); + if (function.IsEmpty()) + return ""; + + return toWebCoreStringWithNullCheck(function); +} + } // namespace WebCore diff --git a/WebCore/bindings/v8/ScriptEventListener.h b/WebCore/bindings/v8/ScriptEventListener.h index 0171120..ce12a53 100644 --- a/WebCore/bindings/v8/ScriptEventListener.h +++ b/WebCore/bindings/v8/ScriptEventListener.h @@ -38,11 +38,14 @@ namespace WebCore { class Attribute; + class EventListener; class Frame; class Node; + class ScriptState; PassRefPtr<V8LazyEventListener> createAttributeEventListener(Node*, Attribute*); PassRefPtr<V8LazyEventListener> createAttributeEventListener(Frame*, Attribute*); + String getEventListenerHandlerBody(ScriptExecutionContext*, ScriptState*, EventListener*); } // namespace WebCore diff --git a/WebCore/bindings/v8/ScriptFunctionCall.cpp b/WebCore/bindings/v8/ScriptFunctionCall.cpp index 2fa43d5..9ff6b8c 100644 --- a/WebCore/bindings/v8/ScriptFunctionCall.cpp +++ b/WebCore/bindings/v8/ScriptFunctionCall.cpp @@ -31,8 +31,6 @@ #include "config.h" #include "ScriptFunctionCall.h" -#include "Document.h" -#include "Frame.h" #include "ScriptScope.h" #include "ScriptState.h" #include "ScriptString.h" @@ -40,19 +38,13 @@ #include "V8Binding.h" #include "V8Proxy.h" +#include "V8Utilities.h" #include <v8.h> #include <wtf/OwnArrayPtr.h> namespace WebCore { -static void reportException(ScriptState* scriptState, v8::TryCatch &exceptionCatcher) -{ - v8::Local<v8::Message> message = exceptionCatcher.Message(); - scriptState->frame()->document()->reportException(toWebCoreString(message->Get()), message->GetLineNumber(), toWebCoreString(message->GetScriptResourceName())); - exceptionCatcher.Reset(); -} - ScriptFunctionCall::ScriptFunctionCall(ScriptState* scriptState, const ScriptObject& thisObject, const String& name) : m_scriptState(scriptState) , m_thisObject(thisObject) diff --git a/WebCore/bindings/v8/ScriptObject.cpp b/WebCore/bindings/v8/ScriptObject.cpp index b6943bd..ac8051d 100644 --- a/WebCore/bindings/v8/ScriptObject.cpp +++ b/WebCore/bindings/v8/ScriptObject.cpp @@ -97,6 +97,13 @@ bool ScriptObject::set(const char* name, int value) return scope.success(); } +bool ScriptObject::set(const char* name, unsigned value) +{ + ScriptScope scope(m_scriptState); + v8Object()->Set(v8::String::New(name), v8::Number::New(value)); + return scope.success(); +} + bool ScriptObject::set(const char* name, bool value) { ScriptScope scope(m_scriptState); diff --git a/WebCore/bindings/v8/ScriptObject.h b/WebCore/bindings/v8/ScriptObject.h index dcee3a5..f741f89 100644 --- a/WebCore/bindings/v8/ScriptObject.h +++ b/WebCore/bindings/v8/ScriptObject.h @@ -53,6 +53,7 @@ namespace WebCore { bool set(const char* name, double); bool set(const char* name, long long); bool set(const char* name, int); + bool set(const char* name, unsigned); bool set(const char* name, bool); static ScriptObject createNew(ScriptState*); diff --git a/WebCore/bindings/v8/ScriptObjectQuarantine.cpp b/WebCore/bindings/v8/ScriptObjectQuarantine.cpp index 053cf68..5dd0dc5 100644 --- a/WebCore/bindings/v8/ScriptObjectQuarantine.cpp +++ b/WebCore/bindings/v8/ScriptObjectQuarantine.cpp @@ -35,9 +35,11 @@ #include "Document.h" #include "DOMWindow.h" #include "Frame.h" +#include "InspectorController.h" #include "Page.h" #include "ScriptObject.h" #include "ScriptValue.h" +#include "Storage.h" #include "V8Binding.h" #include "V8Proxy.h" @@ -61,10 +63,11 @@ bool getQuarantinedScriptObject(Database* database, ScriptObject& quarantinedObj return false; } -bool getQuarantinedScriptObject(Frame* frame, Storage* storage, ScriptObject& quarantinedObject) +bool getQuarantinedScriptObject(Storage* storage, ScriptObject& quarantinedObject) { - ASSERT(frame); ASSERT(storage); + Frame* frame = storage->frame(); + ASSERT(frame); #if ENABLE(DOM_STORAGE) v8::HandleScope handleScope; @@ -73,7 +76,8 @@ bool getQuarantinedScriptObject(Frame* frame, Storage* storage, ScriptObject& qu v8::Context::Scope scope(context); v8::Handle<v8::Value> v8Storage = V8DOMWrapper::convertToV8Object(V8ClassIndex::STORAGE, storage); - quarantinedObject = ScriptObject(frame->script()->state(), v8::Local<v8::Object>(v8::Object::Cast(*v8Storage))); + ScriptState* scriptState = frame->page()->inspectorController()->frontendScriptState(); + quarantinedObject = ScriptObject(scriptState, v8::Local<v8::Object>(v8::Object::Cast(*v8Storage))); #else ASSERT_NOT_REACHED(); quarantinedObject = ScriptObject(); @@ -94,7 +98,8 @@ bool getQuarantinedScriptObject(Node* node, ScriptObject& quarantinedObject) v8::Context::Scope scope(context); v8::Handle<v8::Value> v8Node = V8DOMWrapper::convertNodeToV8Object(node); - quarantinedObject = ScriptObject(frame->script()->state(), v8::Local<v8::Object>(v8::Object::Cast(*v8Node))); + ScriptState* scriptState = frame->page()->inspectorController()->frontendScriptState(); + quarantinedObject = ScriptObject(scriptState, v8::Local<v8::Object>(v8::Object::Cast(*v8Node))); return true; } @@ -111,7 +116,8 @@ bool getQuarantinedScriptObject(DOMWindow* domWindow, ScriptObject& quarantinedO v8::Context::Scope scope(context); v8::Handle<v8::Value> v8DomWindow = V8DOMWrapper::convertToV8Object(V8ClassIndex::DOMWINDOW, domWindow); - quarantinedObject = ScriptObject(frame->script()->state(), v8::Local<v8::Object>(v8::Object::Cast(*v8DomWindow))); + ScriptState* scriptState = frame->page()->inspectorController()->frontendScriptState(); + quarantinedObject = ScriptObject(scriptState, v8::Local<v8::Object>(v8::Object::Cast(*v8DomWindow))); return true; } diff --git a/WebCore/bindings/v8/ScriptObjectQuarantine.h b/WebCore/bindings/v8/ScriptObjectQuarantine.h index 3b7ccff..712dd9b 100644 --- a/WebCore/bindings/v8/ScriptObjectQuarantine.h +++ b/WebCore/bindings/v8/ScriptObjectQuarantine.h @@ -42,7 +42,6 @@ namespace WebCore { class Database; class DOMWindow; - class Frame; class Node; class ScriptObject; class ScriptValue; @@ -51,7 +50,7 @@ namespace WebCore { ScriptValue quarantineValue(ScriptState*, const ScriptValue&); bool getQuarantinedScriptObject(Database* database, ScriptObject& quarantinedObject); - bool getQuarantinedScriptObject(Frame* frame, Storage* storage, ScriptObject& quarantinedObject); + bool getQuarantinedScriptObject(Storage* storage, ScriptObject& quarantinedObject); bool getQuarantinedScriptObject(Node* node, ScriptObject& quarantinedObject); bool getQuarantinedScriptObject(DOMWindow* domWindow, ScriptObject& quarantinedObject); diff --git a/WebCore/bindings/v8/ScriptScope.cpp b/WebCore/bindings/v8/ScriptScope.cpp index 52cab10..727ab25 100644 --- a/WebCore/bindings/v8/ScriptScope.cpp +++ b/WebCore/bindings/v8/ScriptScope.cpp @@ -36,14 +36,13 @@ #include "Document.h" #include "Frame.h" #include "V8Binding.h" -#include "V8Proxy.h" #include <v8.h> namespace WebCore { ScriptScope::ScriptScope(ScriptState* scriptState, bool reportExceptions) - : m_context(V8Proxy::context(scriptState->frame())) + : m_context(scriptState->context()) , m_scope(m_context) , m_scriptState(scriptState) , m_reportExceptions(reportExceptions) diff --git a/WebCore/bindings/v8/ScriptSourceCode.h b/WebCore/bindings/v8/ScriptSourceCode.h index fea387a..5c16168 100644 --- a/WebCore/bindings/v8/ScriptSourceCode.h +++ b/WebCore/bindings/v8/ScriptSourceCode.h @@ -50,7 +50,7 @@ public: // Not sure if that matters. ScriptSourceCode(CachedScript* cs) : m_source(cs->script()) - , m_url(cs->url()) + , m_url(ParsedURLString, cs->url()) , m_startLine(1) { } diff --git a/WebCore/bindings/v8/ScriptState.cpp b/WebCore/bindings/v8/ScriptState.cpp index b9e240c..99557b5 100644 --- a/WebCore/bindings/v8/ScriptState.cpp +++ b/WebCore/bindings/v8/ScriptState.cpp @@ -42,9 +42,22 @@ namespace WebCore { ScriptState::ScriptState(Frame* frame) : m_frame(frame) + , m_context(v8::Persistent<v8::Context>::New(V8Proxy::mainWorldContext(frame))) { } +ScriptState::ScriptState(Frame* frame, v8::Handle<v8::Context> context) + : m_frame(frame) + , m_context(v8::Persistent<v8::Context>::New(context)) +{ +} + +ScriptState::~ScriptState() +{ + m_context.Dispose(); + m_context.Clear(); +} + ScriptState* scriptStateFromNode(Node* node) { // This should be never reached with V8 bindings (WebKit only uses it @@ -55,7 +68,9 @@ ScriptState* scriptStateFromNode(Node* node) ScriptState* scriptStateFromPage(Page* page) { - return page->mainFrame()->script()->state(); + // This should be never reached with V8 bindings. + ASSERT_NOT_REACHED(); + return 0; } } diff --git a/WebCore/bindings/v8/ScriptState.h b/WebCore/bindings/v8/ScriptState.h index 8fbcfa3..e44e914 100644 --- a/WebCore/bindings/v8/ScriptState.h +++ b/WebCore/bindings/v8/ScriptState.h @@ -32,16 +32,19 @@ #define ScriptState_h #include <v8.h> +#include <wtf/Noncopyable.h> namespace WebCore { class Node; class Page; class Frame; - class ScriptState { + class ScriptState : public Noncopyable { public: ScriptState() { } ScriptState(Frame* frame); + ScriptState(Frame* frame, v8::Handle<v8::Context> context); + ~ScriptState(); bool hadException() { return !m_exception.IsEmpty(); } void setException(v8::Local<v8::Value> exception) @@ -51,10 +54,15 @@ namespace WebCore { v8::Local<v8::Value> exception() { return m_exception; } Frame* frame() const { return m_frame; } + v8::Local<v8::Context> context() const + { + return v8::Local<v8::Context>::New(m_context); + } private: v8::Local<v8::Value> m_exception; Frame* m_frame; + v8::Persistent<v8::Context> m_context; }; ScriptState* scriptStateFromNode(Node*); diff --git a/WebCore/bindings/v8/ScriptValue.h b/WebCore/bindings/v8/ScriptValue.h index 004851b..a429593 100644 --- a/WebCore/bindings/v8/ScriptValue.h +++ b/WebCore/bindings/v8/ScriptValue.h @@ -110,7 +110,12 @@ public: { return m_value->IsUndefined(); } - + + bool isObject() const + { + return m_value->IsObject(); + } + bool hasNoValue() const { return m_value.IsEmpty(); @@ -128,7 +133,7 @@ public: m_value.Clear(); } - ~ScriptValue() + virtual ~ScriptValue() { clear(); } diff --git a/WebCore/bindings/v8/SerializedScriptValue.h b/WebCore/bindings/v8/SerializedScriptValue.h new file mode 100644 index 0000000..26a4199 --- /dev/null +++ b/WebCore/bindings/v8/SerializedScriptValue.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SerializedScriptValue_h +#define SerializedScriptValue_h + +#include "ScriptValue.h" +#include "V8Binding.h" +#include <v8.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class SerializedScriptValue : public RefCounted<SerializedScriptValue> { +public: + static PassRefPtr<SerializedScriptValue> create(String string) + { + return adoptRef(new SerializedScriptValue(string)); + } + + static PassRefPtr<SerializedScriptValue> create() + { + return adoptRef(new SerializedScriptValue()); + } + + PassRefPtr<SerializedScriptValue> release() + { + RefPtr<SerializedScriptValue> result = adoptRef(new SerializedScriptValue(m_data)); + m_data = String(); + return result.release(); + } + + String toString() + { + return m_data; + } + +private: + SerializedScriptValue(String string) + : m_data(string) + { + } + + SerializedScriptValue() { } + String m_data; +}; + +} // namespace WebCore + +#endif // SerializedScriptValue_h diff --git a/WebCore/bindings/v8/SharedPersistent.h b/WebCore/bindings/v8/SharedPersistent.h new file mode 100644 index 0000000..c1232ae --- /dev/null +++ b/WebCore/bindings/v8/SharedPersistent.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SharedPersistent_h +#define SharedPersistent_h + +#include <v8.h> + +namespace WebCore { + + // A shareable reference to a v8 persistent handle. Using a shared + // persistent any number of objects can share a reference to a v8 + // object and when it should no longer be accessible the object's + // owner can clear it. + template <typename T> + class SharedPersistent : public WTF::RefCounted<SharedPersistent<T> > { + public: + void set(v8::Persistent<T> value) + { + m_value = value; + } + v8::Persistent<T> get() + { + return m_value; + } + void disposeHandle() + { + if (!m_value.IsEmpty()) { + m_value.Dispose(); + m_value.Clear(); + } + } + static PassRefPtr<SharedPersistent<T> > create(v8::Persistent<T> value) + { + return adoptRef(new SharedPersistent<T>(value)); + } + static PassRefPtr<SharedPersistent<T> > create() + { + return create(v8::Persistent<T>()); + } + private: + explicit SharedPersistent(v8::Persistent<T> value) : m_value(value) { } + v8::Persistent<T> m_value; + }; + +} // namespace WebCore + +#endif // SharedPersistent_h diff --git a/WebCore/bindings/v8/V8AbstractEventListener.cpp b/WebCore/bindings/v8/V8AbstractEventListener.cpp index 0c81846..032b6b9 100644 --- a/WebCore/bindings/v8/V8AbstractEventListener.cpp +++ b/WebCore/bindings/v8/V8AbstractEventListener.cpp @@ -31,17 +31,30 @@ #include "config.h" #include "V8AbstractEventListener.h" +#include "DateExtension.h" #include "Document.h" #include "Event.h" #include "Frame.h" #include "Tokenizer.h" #include "V8Binding.h" +#include "V8EventListenerList.h" +#include "V8Proxy.h" +#include "V8Utilities.h" namespace WebCore { -V8AbstractEventListener::V8AbstractEventListener(Frame* frame, bool isAttribute) - : m_isAttribute(isAttribute) +static void weakEventListenerCallback(v8::Persistent<v8::Value>, void* parameter) +{ + V8AbstractEventListener* listener = static_cast<V8AbstractEventListener*>(parameter); + listener->disposeListenerObject(); +} + +V8AbstractEventListener::V8AbstractEventListener(Frame* frame, PassRefPtr<V8ListenerGuard> guard, bool isAttribute) + : EventListener(JSEventListenerType) + , m_isWeak(true) + , m_isAttribute(isAttribute) , m_frame(frame) + , m_guard(guard) , m_lineNumber(0) , m_columnNumber(0) { @@ -51,8 +64,7 @@ V8AbstractEventListener::V8AbstractEventListener(Frame* frame, bool isAttribute) // We might be called directly from the parser. v8::HandleScope handleScope; - m_context.set(V8Proxy::context(m_frame)); - m_context.makeWeak(); + m_context = V8Proxy::shared_context(m_frame); // Get the position in the source if any. if (m_isAttribute && m_frame->document()->tokenizer()) { @@ -61,52 +73,17 @@ V8AbstractEventListener::V8AbstractEventListener(Frame* frame, bool isAttribute) } } -void V8AbstractEventListener::invokeEventHandler(v8::Handle<v8::Context> v8Context, Event* event, v8::Handle<v8::Value> jsEvent, bool isWindowEvent) +V8AbstractEventListener::~V8AbstractEventListener() { - // We push the event being processed into the global object, so that it can be exposed by DOMWindow's bindings. - v8::Local<v8::String> eventSymbol = v8::String::NewSymbol("event"); - v8::Local<v8::Value> returnValue; - - { - // Catch exceptions thrown in the event handler so they do not propagate to javascript code that caused the event to fire. - v8::TryCatch tryCatch; - tryCatch.SetVerbose(true); - - // Save the old 'event' property so we can restore it later. - v8::Local<v8::Value> savedEvent = v8Context->Global()->GetHiddenValue(eventSymbol); - tryCatch.Reset(); - - // Make the event available in the global object, so DOMWindow can expose it. - v8Context->Global()->SetHiddenValue(eventSymbol, jsEvent); - tryCatch.Reset(); - - // Call the event handler. - returnValue = callListenerFunction(jsEvent, event, isWindowEvent); - tryCatch.Reset(); - - // Restore the old event. This must be done for all exit paths through this method. - if (savedEvent.IsEmpty()) - v8Context->Global()->SetHiddenValue(eventSymbol, v8::Undefined()); - else - v8Context->Global()->SetHiddenValue(eventSymbol, savedEvent); - tryCatch.Reset(); + if (!m_listener.IsEmpty()) { + v8::HandleScope scope; + v8::Local<v8::Object> listener = v8::Local<v8::Object>::New(m_listener); + V8EventListenerList::clearWrapper(listener, m_isAttribute); } - - ASSERT(!V8Proxy::handleOutOfMemory() || returnValue.IsEmpty()); - - if (returnValue.IsEmpty()) - return; - - if (!returnValue->IsNull() && !returnValue->IsUndefined() && event->storesResultAsString()) - event->storeResult(toWebCoreString(returnValue)); - - // Prevent default action if the return value is false; - // FIXME: Add example, and reference to bug entry. - if (m_isAttribute && returnValue->IsBoolean() && !returnValue->BooleanValue()) - event->preventDefault(); + disposeListenerObject(); } -void V8AbstractEventListener::handleEvent(Event* event, bool isWindowEvent) +void V8AbstractEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) { // EventListener could be disconnected from the frame. if (disconnected()) @@ -119,7 +96,12 @@ void V8AbstractEventListener::handleEvent(Event* event, bool isWindowEvent) LOCK_V8; v8::HandleScope handleScope; - v8::Handle<v8::Context> v8Context = m_context.get(); + if (!m_context) + return; + + // Create a new local handle since the persistent handle stored in + // m_context may be disposed before we're done. + v8::Handle<v8::Context> v8Context = v8::Local<v8::Context>::New(m_context->get()); if (v8Context.IsEmpty()) return; @@ -132,7 +114,7 @@ void V8AbstractEventListener::handleEvent(Event* event, bool isWindowEvent) // Get the V8 wrapper for the event object. v8::Handle<v8::Value> jsEvent = V8DOMWrapper::convertEventToV8Object(event); - invokeEventHandler(v8Context, event, jsEvent, isWindowEvent); + invokeEventHandler(v8Context, event, jsEvent); Document::updateStyleForAllDocuments(); } @@ -148,14 +130,83 @@ void V8AbstractEventListener::disposeListenerObject() } } -v8::Local<v8::Object> V8AbstractEventListener::getReceiverObject(Event* event, bool isWindowEvent) +void V8AbstractEventListener::setListenerObject(v8::Handle<v8::Object> listener) +{ + disposeListenerObject(); + m_listener = v8::Persistent<v8::Object>::New(listener); +#ifndef NDEBUG + V8GCController::registerGlobalHandle(EVENT_LISTENER, this, m_listener); +#endif + if (m_isWeak) + m_listener.MakeWeak(this, &weakEventListenerCallback); +} + +void V8AbstractEventListener::invokeEventHandler(v8::Handle<v8::Context> v8Context, Event* event, v8::Handle<v8::Value> jsEvent) +{ + // We push the event being processed into the global object, so that it can be exposed by DOMWindow's bindings. + v8::Local<v8::String> eventSymbol = v8::String::NewSymbol("event"); + v8::Local<v8::Value> returnValue; + + // In beforeunload/unload handlers, we want to avoid sleeps which do tight loops of calling Date.getTime(). + if (event->type() == "beforeunload" || event->type() == "unload") + DateExtension::get()->setAllowSleep(false); + + { + // Catch exceptions thrown in the event handler so they do not propagate to javascript code that caused the event to fire. + v8::TryCatch tryCatch; + tryCatch.SetVerbose(true); + + // Save the old 'event' property so we can restore it later. + v8::Local<v8::Value> savedEvent = v8Context->Global()->GetHiddenValue(eventSymbol); + tryCatch.Reset(); + + // Make the event available in the global object, so DOMWindow can expose it. + v8Context->Global()->SetHiddenValue(eventSymbol, jsEvent); + tryCatch.Reset(); + + // Call the event handler. + tryCatch.SetVerbose(false); // We do not want to report the exception to the inspector console. + returnValue = callListenerFunction(jsEvent, event); + if (!tryCatch.CanContinue()) + return; + + // If an error occurs while handling the event, it should be reported. + if (tryCatch.HasCaught()) { + reportException(0, tryCatch); + tryCatch.Reset(); + } + + // Restore the old event. This must be done for all exit paths through this method. + tryCatch.SetVerbose(true); + if (savedEvent.IsEmpty()) + v8Context->Global()->SetHiddenValue(eventSymbol, v8::Undefined()); + else + v8Context->Global()->SetHiddenValue(eventSymbol, savedEvent); + tryCatch.Reset(); + } + + if (event->type() == "beforeunload" || event->type() == "unload") + DateExtension::get()->setAllowSleep(true); + + ASSERT(!V8Proxy::handleOutOfMemory() || returnValue.IsEmpty()); + + if (returnValue.IsEmpty()) + return; + + if (!returnValue->IsNull() && !returnValue->IsUndefined() && event->storesResultAsString()) + event->storeResult(toWebCoreString(returnValue)); + + // Prevent default action if the return value is false; + // FIXME: Add example, and reference to bug entry. + if (m_isAttribute && returnValue->IsBoolean() && !returnValue->BooleanValue()) + event->preventDefault(); +} + +v8::Local<v8::Object> V8AbstractEventListener::getReceiverObject(Event* event) { if (!m_listener.IsEmpty() && !m_listener->IsFunction()) return v8::Local<v8::Object>::New(m_listener); - if (isWindowEvent) - return v8::Context::GetCurrent()->Global(); - EventTarget* target = event->currentTarget(); v8::Handle<v8::Value> value = V8DOMWrapper::convertEventTargetToV8Object(target); if (value.IsEmpty()) diff --git a/WebCore/bindings/v8/V8AbstractEventListener.h b/WebCore/bindings/v8/V8AbstractEventListener.h index 1521941..c7736be 100644 --- a/WebCore/bindings/v8/V8AbstractEventListener.h +++ b/WebCore/bindings/v8/V8AbstractEventListener.h @@ -33,12 +33,39 @@ #include "EventListener.h" #include "OwnHandle.h" +#include "SharedPersistent.h" #include <v8.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> namespace WebCore { class Event; class Frame; + class V8Proxy; + + // Shared by listener objects and V8Proxy so that V8Proxy can + // silence listeners when needed. + class V8ListenerGuard : public RefCounted<V8ListenerGuard> { + public: + static PassRefPtr<V8ListenerGuard> create() + { + return adoptRef(new V8ListenerGuard); + } + + bool isDisconnected() const { return m_disconnected; } + + void disconnectListeners() + { + m_disconnected = true; + } + + private: + V8ListenerGuard() + : m_disconnected(false) { } + + bool m_disconnected; + }; // There are two kinds of event listeners: HTML or non-HMTL. onload, // onfocus, etc (attributes) are always HTML event handler type; Event @@ -50,54 +77,94 @@ namespace WebCore { // but ALLOWs duplicated non-HTML event handlers. class V8AbstractEventListener : public EventListener { public: - virtual ~V8AbstractEventListener() { } + virtual ~V8AbstractEventListener(); + + static const V8AbstractEventListener* cast(const EventListener* listener) + { + return listener->type() == JSEventListenerType + ? static_cast<const V8AbstractEventListener*>(listener) + : 0; + } + + static V8AbstractEventListener* cast(EventListener* listener) + { + return const_cast<V8AbstractEventListener*>(cast(const_cast<const EventListener*>(listener))); + } + + // Implementation of EventListener interface. + + virtual bool operator==(const EventListener& other) { return this == &other; } + + virtual void handleEvent(ScriptExecutionContext*, Event*); // Returns the owner frame of the listener. Frame* frame() { return m_frame; } - virtual void handleEvent(Event*, bool isWindowEvent); - void invokeEventHandler(v8::Handle<v8::Context>, Event*, v8::Handle<v8::Value> jsEvent, bool isWindowEvent); + virtual bool isLazy() const { return false; } // Returns the listener object, either a function or an object. - virtual v8::Local<v8::Object> getListenerObject() + v8::Local<v8::Object> getListenerObject() { + prepareListenerObject(); return v8::Local<v8::Object>::New(m_listener); } + v8::Local<v8::Object> getExistingListenerObject() + { + return v8::Local<v8::Object>::New(m_listener); + } + + bool hasExistingListenerObject() + { + return !m_listener.IsEmpty(); + } + // Dispose listener object and clear the handle. void disposeListenerObject(); - virtual bool disconnected() const { return !m_frame; } + // Detach the listener from its owner frame. + void disconnectFrame() { m_frame = 0; } - virtual bool isObjectListener() const { return false; } + virtual bool disconnected() const { return m_guard && m_guard->isDisconnected(); } protected: - v8::Persistent<v8::Object> m_listener; + V8AbstractEventListener(Frame*, PassRefPtr<V8ListenerGuard>, bool isAttribute); - // Indicates if this is an HTML type listener. - bool m_isAttribute; + virtual void prepareListenerObject() { } - private: - V8AbstractEventListener(Frame*, bool isInline); + void setListenerObject(v8::Handle<v8::Object> listener); - virtual v8::Local<v8::Value> callListenerFunction(v8::Handle<v8::Value> jsevent, Event*, bool isWindowEvent) = 0; + void invokeEventHandler(v8::Handle<v8::Context>, Event*, v8::Handle<v8::Value> jsEvent); // Get the receiver object to use for event listener call. - v8::Local<v8::Object> getReceiverObject(Event*, bool isWindowEvent); + v8::Local<v8::Object> getReceiverObject(Event*); + + int lineNumber() const { return m_lineNumber; } + + private: + // Implementation of EventListener function. + virtual bool virtualisAttribute() const { return m_isAttribute; } + + virtual v8::Local<v8::Value> callListenerFunction(v8::Handle<v8::Value> jsevent, Event*) = 0; + + v8::Persistent<v8::Object> m_listener; + + // Indicates if the above handle is weak. + bool m_isWeak; + + // Indicates if this is an HTML type listener. + bool m_isAttribute; // Frame to which the event listener is attached to. An event listener must be destroyed before its owner frame is // deleted. See fast/dom/replaceChild.html // FIXME: this could hold m_frame live until the event listener is deleted. Frame* m_frame; - OwnHandle<v8::Context> m_context; + RefPtr<SharedPersistent<v8::Context> > m_context; + RefPtr<V8ListenerGuard> m_guard; // Position in the HTML source for HTML event listeners. int m_lineNumber; int m_columnNumber; - - friend class V8EventListener; - friend class V8ObjectEventListener; - friend class V8LazyEventListener; }; } // namespace WebCore diff --git a/WebCore/bindings/v8/V8Binding.cpp b/WebCore/bindings/v8/V8Binding.cpp index 0da910b..9ac7eae 100644 --- a/WebCore/bindings/v8/V8Binding.cpp +++ b/WebCore/bindings/v8/V8Binding.cpp @@ -55,7 +55,8 @@ public: #ifndef NDEBUG m_threadId = WTF::currentThread(); #endif - v8::V8::AdjustAmountOfExternalAllocatedMemory(2 * length()); + ASSERT(!string.isNull()); + v8::V8::AdjustAmountOfExternalAllocatedMemory(2 * string.length()); } explicit WebCoreStringResource(const AtomicString& string) @@ -65,7 +66,8 @@ public: #ifndef NDEBUG m_threadId = WTF::currentThread(); #endif - v8::V8::AdjustAmountOfExternalAllocatedMemory(2 * length()); + ASSERT(!string.isNull()); + v8::V8::AdjustAmountOfExternalAllocatedMemory(2 * string.length()); } virtual ~WebCoreStringResource() @@ -73,18 +75,18 @@ public: #ifndef NDEBUG ASSERT(m_threadId == WTF::currentThread()); #endif - int reducedExternalMemory = -2 * length(); - if (!m_plainString.impl()->inTable()) + int reducedExternalMemory = -2 * m_plainString.length(); + if (m_plainString.impl() != m_atomicString.impl() && !m_atomicString.isNull()) reducedExternalMemory *= 2; v8::V8::AdjustAmountOfExternalAllocatedMemory(reducedExternalMemory); } - const uint16_t* data() const + virtual const uint16_t* data() const { - return reinterpret_cast<const uint16_t*>(m_plainString.characters()); + return reinterpret_cast<const uint16_t*>(m_plainString.impl()->characters()); } - size_t length() const { return m_plainString.length(); } + virtual size_t length() const { return m_plainString.impl()->length(); } String webcoreString() { return m_plainString; } @@ -95,12 +97,17 @@ public: #endif if (m_atomicString.isNull()) { m_atomicString = AtomicString(m_plainString); - if (!m_plainString.impl()->inTable()) - v8::V8::AdjustAmountOfExternalAllocatedMemory(2 * length()); + ASSERT(!m_atomicString.isNull()); + if (m_plainString.impl() != m_atomicString.impl()) + v8::V8::AdjustAmountOfExternalAllocatedMemory(2 * m_atomicString.length()); } return m_atomicString; } + // Returns right string type based on a dummy parameter. + String string(String) { return webcoreString(); } + AtomicString string(AtomicString) { return atomicString(); } + static WebCoreStringResource* toStringResource(v8::Handle<v8::String> v8String) { return static_cast<WebCoreStringResource*>(v8String->GetExternalStringResource()); @@ -121,12 +128,17 @@ private: #endif }; -String v8StringToWebCoreString(v8::Handle<v8::String> v8String, ExternalMode external, - StringType type) +enum ExternalMode { + Externalize, + DoNotExternalize +}; + +template <typename StringType> +static StringType v8StringToWebCoreString(v8::Handle<v8::String> v8String, ExternalMode external) { WebCoreStringResource* stringResource = WebCoreStringResource::toStringResource(v8String); if (stringResource) - return stringResource->webcoreString(); + return stringResource->string(StringType()); int length = v8String->Length(); if (!length) { @@ -134,44 +146,42 @@ String v8StringToWebCoreString(v8::Handle<v8::String> v8String, ExternalMode ext return StringImpl::empty(); } - UChar* buffer; - String result = String::createUninitialized(length, buffer); - v8String->Write(reinterpret_cast<uint16_t*>(buffer), 0, length); - - if (type == AtomicStringType) - result = AtomicString(result); + StringType result; + static const int inlineBufferSize = 16; + if (length <= inlineBufferSize) { + UChar inlineBuffer[inlineBufferSize]; + v8String->Write(reinterpret_cast<uint16_t*>(inlineBuffer), 0, length); + result = StringType(inlineBuffer, length); + } else { + UChar* buffer; + String tmp = String::createUninitialized(length, buffer); + v8String->Write(reinterpret_cast<uint16_t*>(buffer), 0, length); + result = StringType(tmp); + } - if (external == Externalize) { - WebCoreStringResource* resource = new WebCoreStringResource(result); - if (!v8String->MakeExternal(resource)) { + if (external == Externalize && v8String->CanMakeExternal()) { + stringResource = new WebCoreStringResource(result); + if (!v8String->MakeExternal(stringResource)) { // In case of a failure delete the external resource as it was not used. - delete resource; + delete stringResource; } } return result; } -AtomicString v8StringToAtomicWebCoreString(v8::Handle<v8::String> v8String) +String v8StringToWebCoreString(v8::Handle<v8::String> v8String) { - WebCoreStringResource* stringResource = WebCoreStringResource::toStringResource(v8String); - if (!stringResource) { - // If this string hasn't been externalized, we force it now. - String plain = v8StringToWebCoreString(v8String, Externalize, AtomicStringType); - // If the string is empty there's no room to cache an atomic - // string so we bail out. - if (plain.isEmpty()) - return plain; - stringResource = WebCoreStringResource::toStringResource(v8String); - ASSERT(stringResource != NULL); - } - return stringResource->atomicString(); + return v8StringToWebCoreString<String>(v8String, Externalize); } -String v8ValueToWebCoreString(v8::Handle<v8::Value> object) +AtomicString v8StringToAtomicWebCoreString(v8::Handle<v8::String> v8String) { - if (object->IsString()) - return v8StringToWebCoreString(v8::Handle<v8::String>::Cast(object), Externalize, PlainStringType); + return v8StringToWebCoreString<AtomicString>(v8String, Externalize); +} +String v8NonStringValueToWebCoreString(v8::Handle<v8::Value> object) +{ + ASSERT(!object->IsString()); if (object->IsInt32()) { int value = object->Int32Value(); // Most numbers used are <= 100. Even if they aren't used there's very little in using the space. @@ -197,20 +207,13 @@ String v8ValueToWebCoreString(v8::Handle<v8::Value> object) throwError(block.Exception()); return StringImpl::empty(); } - return v8StringToWebCoreString(v8String, DoNotExternalize, PlainStringType); -} - -AtomicString v8ValueToAtomicWebCoreString(v8::Handle<v8::Value> v8Value) -{ - if (v8Value->IsString()) - return v8StringToAtomicWebCoreString(v8::Handle<v8::String>::Cast(v8Value)); - String string = v8ValueToWebCoreString(v8Value); - return AtomicString(string); + return v8StringToWebCoreString<String>(v8String, DoNotExternalize); } -v8::Handle<v8::String> v8String(const String& string) +AtomicString v8NonStringValueToAtomicWebCoreString(v8::Handle<v8::Value> object) { - return v8ExternalString(string); + ASSERT(!object->IsString()); + return AtomicString(v8NonStringValueToWebCoreString(object)); } static bool stringImplCacheEnabled = false; @@ -261,7 +264,7 @@ v8::Local<v8::String> v8ExternalString(const String& string) StringCache& stringCache = getStringCache(); v8::String* cachedV8String = stringCache.get(stringImpl); if (cachedV8String) - return v8::Local<v8::String>(cachedV8String); + return v8::Local<v8::String>::New(v8::Handle<v8::String>(cachedV8String)); v8::Local<v8::String> newString = makeExternalString(string); if (newString.IsEmpty()) diff --git a/WebCore/bindings/v8/V8Binding.h b/WebCore/bindings/v8/V8Binding.h index 4f36f00..a09102d 100644 --- a/WebCore/bindings/v8/V8Binding.h +++ b/WebCore/bindings/v8/V8Binding.h @@ -31,6 +31,7 @@ #ifndef V8Binding_h #define V8Binding_h +#include "AtomicString.h" #include "MathExtras.h" #include "PlatformString.h" @@ -38,32 +39,31 @@ namespace WebCore { - enum ExternalMode { - Externalize, - DoNotExternalize - }; - - enum StringType { - PlainStringType, - AtomicStringType - }; - // Convert v8 types to a WebCore::String. If the V8 string is not already // an external string then it is transformed into an external string at this // point to avoid repeated conversions. - String v8StringToWebCoreString(v8::Handle<v8::String>, ExternalMode mode, StringType type); - String v8ValueToWebCoreString(v8::Handle<v8::Value>); + String v8StringToWebCoreString(v8::Handle<v8::String>); + String v8NonStringValueToWebCoreString(v8::Handle<v8::Value>); + inline String v8ValueToWebCoreString(v8::Handle<v8::Value> value) + { + if (value->IsString()) + return v8StringToWebCoreString(v8::Handle<v8::String>::Cast(value)); + return v8NonStringValueToWebCoreString(value); + } // Convert v8 types to a WebCore::AtomicString. AtomicString v8StringToAtomicWebCoreString(v8::Handle<v8::String>); - AtomicString v8ValueToAtomicWebCoreString(v8::Handle<v8::Value>); - - // Convert a string to a V8 string. - v8::Handle<v8::String> v8String(const String&); + AtomicString v8NonStringValueToAtomicWebCoreString(v8::Handle<v8::Value>); + inline AtomicString v8ValueToAtomicWebCoreString(v8::Handle<v8::Value> value) + { + if (value->IsString()) + return v8StringToAtomicWebCoreString(v8::Handle<v8::String>::Cast(value)); + return v8NonStringValueToAtomicWebCoreString(value); + } - inline String toString(const String& string)
- {
- return string;
+ inline String toString(const String& string) + { + return string; } // Return a V8 external string that shares the underlying buffer with the given @@ -71,6 +71,12 @@ namespace WebCore { // underlying buffer alive while the string is still live in the V8 engine. v8::Local<v8::String> v8ExternalString(const String&); + // Convert a string to a V8 string. + inline v8::Handle<v8::String> v8String(const String& string) + { + return v8ExternalString(string); + } + // Enables caching v8 wrappers created for WebCore::StringImpl. Currently this cache requires // all the calls (both to convert WebCore::String to v8::String and to GC the handle) // to be performed on the main thread. @@ -145,7 +151,7 @@ namespace WebCore { { return value ? v8::True() : v8::False(); } - + inline String toWebCoreStringWithNullCheck(v8::Handle<v8::Value> value) { if (value->IsNull()) @@ -153,6 +159,13 @@ namespace WebCore { return v8ValueToWebCoreString(value); } + inline AtomicString v8ValueToAtomicWebCoreStringWithNullCheck(v8::Handle<v8::Value> value) + { + if (value->IsNull()) + return AtomicString(); + return v8ValueToAtomicWebCoreString(value); + } + inline String toWebCoreStringWithNullOrUndefinedCheck(v8::Handle<v8::Value> value) { if (value->IsNull() || value->IsUndefined()) diff --git a/WebCore/bindings/v8/V8DOMWrapper.cpp b/WebCore/bindings/v8/V8DOMWrapper.cpp index 8a9741a..5a6b901 100644 --- a/WebCore/bindings/v8/V8DOMWrapper.cpp +++ b/WebCore/bindings/v8/V8DOMWrapper.cpp @@ -31,21 +31,32 @@ #include "config.h" #include "V8DOMWrapper.h" +#include "CSSMutableStyleDeclaration.h" #if PLATFORM(CHROMIUM) #include "ChromiumBridge.h" #endif -#include "CSSMutableStyleDeclaration.h" #include "DOMObjectsInclude.h" #include "DocumentLoader.h" #include "FrameLoaderClient.h" +#include "Notification.h" +#if PLATFORM(ANDROID) +// TODO: Upstream SVG guard. +#if ENABLE(SVG) +#include "SVGElementInstance.h" +#endif +#endif #include "ScriptController.h" +#include "V8AbstractEventListener.h" #include "V8Binding.h" #include "V8Collection.h" #include "V8CustomBinding.h" +#include "V8CustomEventListener.h" #include "V8DOMMap.h" #include "V8DOMWindow.h" +#include "V8EventListenerList.h" #include "V8Index.h" #include "V8IsolatedWorld.h" +#include "V8Proxy.h" #include "WorkerContextExecutionProxy.h" #include <algorithm> @@ -337,6 +348,7 @@ v8::Persistent<v8::FunctionTemplate> V8DOMWrapper::getTemplate(V8ClassIndex::V8W descriptor->PrototypeTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(DOMWindow)); descriptor->PrototypeTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(DOMWindow)); + descriptor->PrototypeTemplate()->SetInternalFieldCount(V8Custom::kDOMWindowInternalFieldCount); descriptor->SetHiddenPrototype(true); @@ -381,6 +393,24 @@ v8::Persistent<v8::FunctionTemplate> V8DOMWrapper::getTemplate(V8ClassIndex::V8W break; } +#if ENABLE(NOTIFICATIONS) + case V8ClassIndex::NOTIFICATION: { + // Reserve one more internal field for keeping event listeners. + v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate(); + instanceTemplate->SetInternalFieldCount(V8Custom::kNotificationInternalFieldCount); + break; + } +#endif // NOTIFICATIONS + +#if ENABLE(SVG) + case V8ClassIndex::SVGELEMENTINSTANCE: { + // Reserve one more internal field for keeping event listeners. + v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate(); + instanceTemplate->SetInternalFieldCount(V8Custom::kSVGElementInstanceInternalFieldCount); + break; + } +#endif + #if ENABLE(WORKERS) case V8ClassIndex::ABSTRACTWORKER: { // Reserve one more internal field for keeping event listeners. @@ -424,20 +454,42 @@ v8::Persistent<v8::FunctionTemplate> V8DOMWrapper::getTemplate(V8ClassIndex::V8W } #endif +#if ENABLE(3D_CANVAS) // The following objects are created from JavaScript. - case V8ClassIndex::DOMPARSER: - descriptor->SetCallHandler(USE_CALLBACK(DOMParserConstructor)); + case V8ClassIndex::CANVASARRAYBUFFER: + descriptor->SetCallHandler(USE_CALLBACK(CanvasArrayBufferConstructor)); break; -#if ENABLE(VIDEO) - case V8ClassIndex::HTMLAUDIOELEMENT: - descriptor->SetCallHandler(USE_CALLBACK(HTMLAudioElementConstructor)); + case V8ClassIndex::CANVASBYTEARRAY: + descriptor->SetCallHandler(USE_CALLBACK(CanvasByteArrayConstructor)); + descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(CanvasByteArray), USE_INDEXED_PROPERTY_SETTER(CanvasByteArray)); break; -#endif - case V8ClassIndex::HTMLIMAGEELEMENT: - descriptor->SetCallHandler(USE_CALLBACK(HTMLImageElementConstructor)); + case V8ClassIndex::CANVASFLOATARRAY: + descriptor->SetCallHandler(USE_CALLBACK(CanvasFloatArrayConstructor)); + descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(CanvasFloatArray), USE_INDEXED_PROPERTY_SETTER(CanvasFloatArray)); break; - case V8ClassIndex::HTMLOPTIONELEMENT: - descriptor->SetCallHandler(USE_CALLBACK(HTMLOptionElementConstructor)); + case V8ClassIndex::CANVASINTARRAY: + descriptor->SetCallHandler(USE_CALLBACK(CanvasIntArrayConstructor)); + descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(CanvasIntArray), USE_INDEXED_PROPERTY_SETTER(CanvasIntArray)); + break; + case V8ClassIndex::CANVASSHORTARRAY: + descriptor->SetCallHandler(USE_CALLBACK(CanvasShortArrayConstructor)); + descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(CanvasShortArray), USE_INDEXED_PROPERTY_SETTER(CanvasShortArray)); + break; + case V8ClassIndex::CANVASUNSIGNEDBYTEARRAY: + descriptor->SetCallHandler(USE_CALLBACK(CanvasUnsignedByteArrayConstructor)); + descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(CanvasUnsignedByteArray), USE_INDEXED_PROPERTY_SETTER(CanvasUnsignedByteArray)); + break; + case V8ClassIndex::CANVASUNSIGNEDINTARRAY: + descriptor->SetCallHandler(USE_CALLBACK(CanvasUnsignedIntArrayConstructor)); + descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(CanvasUnsignedIntArray), USE_INDEXED_PROPERTY_SETTER(CanvasUnsignedIntArray)); + break; + case V8ClassIndex::CANVASUNSIGNEDSHORTARRAY: + descriptor->SetCallHandler(USE_CALLBACK(CanvasUnsignedShortArrayConstructor)); + descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(CanvasUnsignedShortArray), USE_INDEXED_PROPERTY_SETTER(CanvasUnsignedShortArray)); + break; +#endif + case V8ClassIndex::DOMPARSER: + descriptor->SetCallHandler(USE_CALLBACK(DOMParserConstructor)); break; case V8ClassIndex::WEBKITCSSMATRIX: descriptor->SetCallHandler(USE_CALLBACK(WebKitCSSMatrixConstructor)); @@ -445,6 +497,15 @@ v8::Persistent<v8::FunctionTemplate> V8DOMWrapper::getTemplate(V8ClassIndex::V8W case V8ClassIndex::WEBKITPOINT: descriptor->SetCallHandler(USE_CALLBACK(WebKitPointConstructor)); break; +#if ENABLE(WEB_SOCKETS) + case V8ClassIndex::WEBSOCKET: { + // Reserve one more internal field for keeping event listeners. + v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate(); + instanceTemplate->SetInternalFieldCount(V8Custom::kWebSocketInternalFieldCount); + descriptor->SetCallHandler(USE_CALLBACK(WebSocketConstructor)); + break; + } +#endif case V8ClassIndex::XMLSERIALIZER: descriptor->SetCallHandler(USE_CALLBACK(XMLSerializerConstructor)); break; @@ -482,6 +543,9 @@ v8::Persistent<v8::FunctionTemplate> V8DOMWrapper::getTemplate(V8ClassIndex::V8W case V8ClassIndex::CLIENTRECTLIST: descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(ClientRectList)); break; + case V8ClassIndex::FILELIST: + descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(FileList)); + break; #if ENABLE(DATAGRID) case V8ClassIndex::DATAGRIDCOLUMNLIST: descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(DataGridColumnList)); @@ -534,6 +598,16 @@ v8::Local<v8::Function> V8DOMWrapper::getConstructor(V8ClassIndex::V8WrapperType if (!frame) return v8::Local<v8::Function>(); +#if ENABLE(WEB_SOCKETS) + // Make typeof(window.WebSocket) == 'undefined' when + // experimentalWebSocketEnabled is false. + if (type == V8ClassIndex::WEBSOCKET) { + Settings* settings = frame->settings(); + if (!settings || !settings->experimentalWebSocketsEnabled()) + return v8::Local<v8::Function>(); + } +#endif + v8::Handle<v8::Context> context = V8Proxy::context(frame); if (context.IsEmpty()) return v8::Local<v8::Function>(); @@ -562,6 +636,7 @@ v8::Handle<v8::Value> V8DOMWrapper::convertToV8Object(V8ClassIndex::V8WrapperTyp // These objects can be constructed under WorkerContextExecutionProxy. They need special // handling, since if we proceed below V8Proxy::retrieve() will get called and will crash. + // TODO(ukai): websocket? if ((type == V8ClassIndex::DOMCOREEXCEPTION || type == V8ClassIndex::RANGEEXCEPTION || type == V8ClassIndex::EVENTEXCEPTION @@ -982,7 +1057,6 @@ V8ClassIndex::V8WrapperType V8DOMWrapper::htmlElementType(HTMLElement* element) #if ENABLE(SVG_FONTS) #define FOR_EACH_FONTS_TAG(macro) \ - macro(definition-src, DEFINITIONSRC) \ macro(font-face, FONTFACE) \ macro(font-face-format, FONTFACEFORMAT) \ macro(font-face-name, FONTFACENAME) \ @@ -1105,6 +1179,8 @@ v8::Handle<v8::Value> V8DOMWrapper::convertEventToV8Object(Event* event) type = V8ClassIndex::OVERFLOWEVENT; else if (event->isMessageEvent()) type = V8ClassIndex::MESSAGEEVENT; + else if (event->isPageTransitionEvent()) + type = V8ClassIndex::PAGETRANSITIONEVENT; else if (event->isProgressEvent()) { if (event->isXMLHttpRequestProgressEvent()) type = V8ClassIndex::XMLHTTPREQUESTPROGRESSEVENT; @@ -1155,30 +1231,30 @@ static const V8ClassIndex::V8WrapperType mapping[] = { V8ClassIndex::NODE, // XPATH_NAMESPACE_NODE }; -// Caller checks node is not null. -v8::Handle<v8::Value> V8DOMWrapper::convertNodeToV8Object(Node* node) +v8::Handle<v8::Value> V8DOMWrapper::convertDocumentToV8Object(Document* document) { - if (!node) - return v8::Null(); - // Find a proxy for this node. // // Note that if proxy is found, we might initialize the context which can // instantiate a document wrapper. Therefore, we get the proxy before // checking if the node already has a wrapper. - V8Proxy* proxy = 0; - Document* document = node->document(); - if (document) { - Frame* frame = document->frame(); - proxy = V8Proxy::retrieve(frame); - if (proxy) - proxy->initContextIfNeeded(); - } + V8Proxy* proxy = V8Proxy::retrieve(document->frame()); + if (proxy) + proxy->initContextIfNeeded(); DOMWrapperMap<Node>& domNodeMap = getDOMNodeMap(); - v8::Handle<v8::Object> wrapper = domNodeMap.get(node); - if (!wrapper.IsEmpty()) - return wrapper; + v8::Handle<v8::Object> wrapper = domNodeMap.get(document); + if (wrapper.IsEmpty()) + return convertNewNodeToV8Object(document, proxy, domNodeMap); + + return wrapper; +} + +// Caller checks node is not null. +v8::Handle<v8::Value> V8DOMWrapper::convertNewNodeToV8Object(Node* node, V8Proxy* proxy, DOMWrapperMap<Node>& domNodeMap) +{ + if (!proxy && node->document()) + proxy = V8Proxy::retrieve(node->document()->frame()); bool isDocument = false; // document type node has special handling V8ClassIndex::V8WrapperType type; @@ -1272,6 +1348,18 @@ v8::Handle<v8::Value> V8DOMWrapper::convertEventTargetToV8Object(EventTarget* ta return convertToV8Object(V8ClassIndex::WORKER, worker); #endif // WORKERS +#if ENABLE(NOTIFICATIONS) + Notification* notification = target->toNotification(); + if (notification) + return convertToV8Object(V8ClassIndex::NOTIFICATION, notification); +#endif + +#if ENABLE(WEB_SOCKETS) + WebSocket* webSocket = target->toWebSocket(); + if (webSocket) + return convertToV8Object(V8ClassIndex::WEBSOCKET, webSocket); +#endif + Node* node = target->toNode(); if (node) return convertNodeToV8Object(node); @@ -1322,6 +1410,102 @@ v8::Handle<v8::Value> V8DOMWrapper::convertEventListenerToV8Object(EventListener return v8listener->getListenerObject(); } +PassRefPtr<EventListener> V8DOMWrapper::getEventListener(Node* node, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) +{ + ScriptExecutionContext* context = node->scriptExecutionContext(); + if (!context) + return 0; + + V8Proxy* proxy = V8Proxy::retrieve(context); + // The document might be created using createDocument, which does + // not have a frame, use the active frame. + if (!proxy) + proxy = V8Proxy::retrieve(V8Proxy::retrieveFrameForEnteredContext()); + + if (proxy) + return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(proxy->frame(), proxy->listenerGuard(), value, isAttribute); + + return 0; +} + +#if PLATFORM(ANDROID) +#if ENABLE(SVG) +PassRefPtr<EventListener> V8DOMWrapper::getEventListener(SVGElementInstance* element, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) +{ + return getEventListener(element->correspondingElement(), value, isAttribute, lookup); +} +#endif +#endif + +PassRefPtr<EventListener> V8DOMWrapper::getEventListener(AbstractWorker* worker, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) +{ + if (worker->scriptExecutionContext()->isWorkerContext()) { + WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); + ASSERT(workerContextProxy); + return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); + } + + V8Proxy* proxy = V8Proxy::retrieve(worker->scriptExecutionContext()); + if (proxy) + return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(proxy->frame(), proxy->listenerGuard(), value, isAttribute); + + return 0; +} + +#if ENABLE(NOTIFICATIONS) +PassRefPtr<EventListener> V8DOMWrapper::getEventListener(Notification* notification, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) +{ + if (notification->scriptExecutionContext()->isWorkerContext()) { + WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); + ASSERT(workerContextProxy); + return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); + } + + V8Proxy* proxy = V8Proxy::retrieve(notification->scriptExecutionContext()); + if (proxy) + return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(proxy->frame(), proxy->listenerGuard(), value, isAttribute); + + return 0; +} +#endif + +PassRefPtr<EventListener> V8DOMWrapper::getEventListener(WorkerContext* workerContext, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) +{ + WorkerContextExecutionProxy* workerContextProxy = workerContext->script()->proxy(); + if (workerContextProxy) + return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); + + return 0; +} + +PassRefPtr<EventListener> V8DOMWrapper::getEventListener(XMLHttpRequestUpload* upload, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) +{ + return getEventListener(upload->associatedXMLHttpRequest(), value, isAttribute, lookup); +} + +PassRefPtr<EventListener> V8DOMWrapper::getEventListener(EventTarget* eventTarget, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) +{ + V8Proxy* proxy = V8Proxy::retrieve(eventTarget->scriptExecutionContext()); + if (proxy) + return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(proxy->frame(), proxy->listenerGuard(), value, isAttribute); + +#if ENABLE(WORKERS) + WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); + if (workerContextProxy) + return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); +#endif + + return 0; +} + +PassRefPtr<EventListener> V8DOMWrapper::getEventListener(V8Proxy* proxy, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) +{ + if (proxy) + return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(proxy->frame(), proxy->listenerGuard(), value, isAttribute); + + return 0; +} + v8::Handle<v8::Value> V8DOMWrapper::convertDOMImplementationToV8Object(DOMImplementation* impl) { v8::Handle<v8::Object> result = instantiateV8Object(V8ClassIndex::DOMIMPLEMENTATION, V8ClassIndex::DOMIMPLEMENTATION, impl); diff --git a/WebCore/bindings/v8/V8DOMWrapper.h b/WebCore/bindings/v8/V8DOMWrapper.h index 57b3a69..b5587d5 100644 --- a/WebCore/bindings/v8/V8DOMWrapper.h +++ b/WebCore/bindings/v8/V8DOMWrapper.h @@ -31,13 +31,18 @@ #ifndef V8DOMWrapper_h #define V8DOMWrapper_h +#include "Document.h" #include "Event.h" #include "Node.h" #include "NodeFilter.h" #include "PlatformString.h" // for WebCore::String #include "V8CustomBinding.h" +#include "V8CustomXPathNSResolver.h" +#include "V8DOMMap.h" #include "V8Index.h" #include "V8Utilities.h" +#include "V8XPathNSResolver.h" +#include "XPathNSResolver.h" #include <v8.h> namespace WebCore { @@ -86,8 +91,16 @@ namespace WebCore { class StyleSheetList; class V8EventListener; class V8ObjectEventListener; +#if ENABLE(WEB_SOCKETS) + class WebSocket; +#endif class WorkerContext; + enum ListenerLookupType { + ListenerFindOnly, + ListenerFindOrCreate, + }; + class V8DOMWrapper { public: #ifndef NDEBUG @@ -134,7 +147,26 @@ namespace WebCore { return convertNodeToV8Object(node.get()); } - static v8::Handle<v8::Value> convertNodeToV8Object(Node*); + static v8::Handle<v8::Value> convertNodeToV8Object(Node* node) + { + if (!node) + return v8::Null(); + + Document* document = node->document(); + if (node == document) + return convertDocumentToV8Object(document); + + DOMWrapperMap<Node>& domNodeMap = getDOMNodeMap(); + v8::Handle<v8::Object> wrapper = domNodeMap.get(node); + if (wrapper.IsEmpty()) + return convertNewNodeToV8Object(node, 0, domNodeMap); + + return wrapper; + } + + static v8::Handle<v8::Value> convertDocumentToV8Object(Document*); + + static v8::Handle<v8::Value> convertNewNodeToV8Object(Node*, V8Proxy*, DOMWrapperMap<Node>&); template <class C> static C* convertToNativeObject(V8ClassIndex::V8WrapperType type, v8::Handle<v8::Object> object) @@ -184,13 +216,48 @@ namespace WebCore { static v8::Handle<v8::Value> convertEventTargetToV8Object(EventTarget*); // Wrap and unwrap JS event listeners. - static v8::Handle<v8::Value> convertEventListenerToV8Object(PassRefPtr<Event> eventListener) + static v8::Handle<v8::Value> convertEventListenerToV8Object(PassRefPtr<EventListener> eventListener) { return convertEventListenerToV8Object(eventListener.get()); } static v8::Handle<v8::Value> convertEventListenerToV8Object(EventListener*); + static PassRefPtr<EventListener> getEventListener(Node* node, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup); + + static PassRefPtr<EventListener> getEventListener(SVGElementInstance* element, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup); + + static PassRefPtr<EventListener> getEventListener(AbstractWorker* worker, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup); + +#if ENABLE(NOTIFICATIONS) + static PassRefPtr<EventListener> getEventListener(Notification* notification, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup); +#endif + + static PassRefPtr<EventListener> getEventListener(WorkerContext* workerContext, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup); + + static PassRefPtr<EventListener> getEventListener(XMLHttpRequestUpload* upload, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup); + + static PassRefPtr<EventListener> getEventListener(EventTarget* eventTarget, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup); + + static PassRefPtr<EventListener> getEventListener(V8Proxy* proxy, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup); + + +#if PLATFORM(ANDROID) +// TODO: upstream XPATH guard. +#if ENABLE(XPATH) + // XPath-related utilities + static RefPtr<XPathNSResolver> getXPathNSResolver(v8::Handle<v8::Value> value) + { + RefPtr<XPathNSResolver> resolver; + if (V8XPathNSResolver::HasInstance(value)) + resolver = convertToNativeObject<XPathNSResolver>(V8ClassIndex::XPATHNSRESOLVER, v8::Handle<v8::Object>::Cast(value)); + else if (value->IsObject()) + resolver = V8CustomXPathNSResolver::create(value->ToObject()); + return resolver; + } +#endif +#endif + // DOMImplementation is a singleton and it is handled in a special // way. A wrapper is generated per document and stored in an // internal field of the document. diff --git a/WebCore/bindings/v8/V8EventListenerList.cpp b/WebCore/bindings/v8/V8EventListenerList.cpp index c9aaa12..e37d630 100644 --- a/WebCore/bindings/v8/V8EventListenerList.cpp +++ b/WebCore/bindings/v8/V8EventListenerList.cpp @@ -31,165 +31,6 @@ #include "config.h" #include "V8EventListenerList.h" -#include "V8CustomEventListener.h" - namespace WebCore { -V8EventListenerListIterator::V8EventListenerListIterator(V8EventListenerList* list) - : m_list(list) - , m_vectorIndex(0) - , m_iter(list->m_table.begin()) -{ -} - -V8EventListenerListIterator::V8EventListenerListIterator(V8EventListenerList* list, bool shouldSeekToEnd) - : m_list(list) - , m_vectorIndex(0) - , m_iter(list->m_table.begin()) -{ - if (shouldSeekToEnd) - seekToEnd(); -} - -V8EventListenerListIterator::~V8EventListenerListIterator() { } - -void V8EventListenerListIterator::operator++() -{ - if (m_iter != m_list->m_table.end()) { - Vector<V8EventListener*>* vector = m_iter->second; - if (m_vectorIndex + 1 < vector->size()) { - m_vectorIndex++; - return; - } - m_vectorIndex = 0; - ++m_iter; - } -} - -bool V8EventListenerListIterator::operator==(const V8EventListenerListIterator& other) -{ - return other.m_iter == m_iter && other.m_vectorIndex == m_vectorIndex && other.m_list == m_list; -} - -bool V8EventListenerListIterator::operator!=(const V8EventListenerListIterator& other) -{ - return !operator==(other); -} - -V8EventListener* V8EventListenerListIterator::operator*() -{ - if (m_iter != m_list->m_table.end()) { - Vector<V8EventListener*>* vector = m_iter->second; - if (m_vectorIndex < vector->size()) - return vector->at(m_vectorIndex); - } - return 0; -} - -void V8EventListenerListIterator::seekToEnd() -{ - m_iter = m_list->m_table.end(); - m_vectorIndex = 0; -} - - -V8EventListenerList::V8EventListenerList() -{ -} - -V8EventListenerList::~V8EventListenerList() -{ -} - -V8EventListenerListIterator V8EventListenerList::begin() -{ - return iterator(this); -} - -V8EventListenerListIterator V8EventListenerList::end() -{ - return iterator(this, true); -} - - -static int getKey(v8::Local<v8::Object> object) -{ - // 0 is a sentinel value for the HashMap key, so we map it to 1. - int hash = object->GetIdentityHash(); - if (!hash) - return 1; - return hash; -} - -void V8EventListenerList::add(V8EventListener* listener) -{ - ASSERT(v8::Context::InContext()); - v8::HandleScope handleScope; - - v8::Local<v8::Object> object = listener->getListenerObject(); - int key = getKey(object); - Vector<V8EventListener*>* vector = m_table.get(key); - if (!vector) { - vector = new Vector<V8EventListener*>(); - m_table.set(key, vector); - } - vector->append(listener); - m_reverseTable.set(listener, key); -} - -void V8EventListenerList::remove(V8EventListener* listener) -{ - if (m_reverseTable.contains(listener)) { - int key = m_reverseTable.get(listener); - Vector<V8EventListener*>* vector = m_table.get(key); - if (!vector) - return; - for (size_t j = 0; j < vector->size(); j++) { - if (vector->at(j) == listener) { - vector->remove(j); - if (!vector->size()) { - m_table.remove(key); - delete vector; - vector = 0; - } - m_reverseTable.remove(listener); - return; - } - } - } -} - -void V8EventListenerList::clear() -{ - m_table.clear(); - m_reverseTable.clear(); -} - -V8EventListener* V8EventListenerList::find(v8::Local<v8::Object> object, bool isAttribute) -{ - ASSERT(v8::Context::InContext()); - int key = getKey(object); - - Vector<V8EventListener*>* vector = m_table.get(key); - if (!vector) - return 0; - - for (size_t i = 0; i < vector->size(); i++) { - V8EventListener* element = vector->at(i); - if (isAttribute == element->isAttribute() && object == element->getListenerObject()) - return element; - } - return 0; -} - -PassRefPtr<V8EventListener> V8EventListenerList::findWrapper(v8::Local<v8::Value> object, bool isAttribute) -{ - ASSERT(v8::Context::InContext()); - if (!object->IsObject()) - return 0; - - // FIXME: Should this be v8::Local<v8::Object>::Cast instead? - return find(object->ToObject(), isAttribute); -} - } // namespace WebCore diff --git a/WebCore/bindings/v8/V8EventListenerList.h b/WebCore/bindings/v8/V8EventListenerList.h index 4255050..506e5dc 100644 --- a/WebCore/bindings/v8/V8EventListenerList.h +++ b/WebCore/bindings/v8/V8EventListenerList.h @@ -32,92 +32,74 @@ #define V8EventListenerList_h #include <v8.h> -#include <wtf/Vector.h> -#include <wtf/HashMap.h> #include "PassRefPtr.h" +#include "V8CustomEventListener.h" +#include "V8HiddenPropertyName.h" namespace WebCore { class Frame; class V8EventListener; - class V8EventListenerListIterator; - // This is a container for V8EventListener objects that uses the identity hash of the v8::Object to - // speed up lookups + // This is a container for V8EventListener objects that uses hidden properties of v8::Object to speed up lookups. class V8EventListenerList { public: - // Because v8::Object identity hashes are not guaranteed to be unique, we unfortunately can't just map - // an int to V8EventListener. Instead we define a HashMap of int to Vector of V8EventListener - // called a ListenerMultiMap. - typedef Vector<V8EventListener*>* Values; - struct ValuesTraits : HashTraits<Values> { - static const bool needsDestruction = true; - }; - typedef HashMap<int, Values, DefaultHash<int>::Hash, HashTraits<int>, ValuesTraits> ListenerMultiMap; - - V8EventListenerList(); - ~V8EventListenerList(); - - friend class V8EventListenerListIterator; - typedef V8EventListenerListIterator iterator; - - iterator begin(); - iterator end(); - - void add(V8EventListener*); - void remove(V8EventListener*); - V8EventListener* find(v8::Local<v8::Object>, bool isAttribute); - void clear(); - size_t size() { return m_table.size(); } - - PassRefPtr<V8EventListener> findWrapper(v8::Local<v8::Value>, bool isAttribute); - template<typename WrapperType> - PassRefPtr<V8EventListener> findOrCreateWrapper(Frame*, v8::Local<v8::Value>, bool isAttribute); + static PassRefPtr<V8EventListener> findWrapper(v8::Local<v8::Value> value, bool isAttribute) + { + ASSERT(v8::Context::InContext()); + if (!value->IsObject()) + return 0; - private: - ListenerMultiMap m_table; + v8::Handle<v8::String> wrapperProperty = getHiddenProperty(isAttribute); + return doFindWrapper(v8::Local<v8::Object>::Cast(value), wrapperProperty); + } - // we also keep a reverse mapping of V8EventListener to v8::Object identity hash, - // in order to speed up removal by V8EventListener - HashMap<V8EventListener*, int> m_reverseTable; - }; + template<typename WrapperType, typename ContextType> + static PassRefPtr<V8EventListener> findOrCreateWrapper(ContextType*, PassRefPtr<V8ListenerGuard>, v8::Local<v8::Value>, bool isAttribute); + + static void clearWrapper(v8::Handle<v8::Object> listenerObject, bool isAttribute) + { + v8::Handle<v8::String> wrapperProperty = getHiddenProperty(isAttribute); + listenerObject->DeleteHiddenValue(wrapperProperty); + } - class V8EventListenerListIterator { - public: - ~V8EventListenerListIterator(); - void operator++(); - bool operator==(const V8EventListenerListIterator&); - bool operator!=(const V8EventListenerListIterator&); - V8EventListener* operator*(); private: - friend class V8EventListenerList; - explicit V8EventListenerListIterator(V8EventListenerList*); - V8EventListenerListIterator(V8EventListenerList*, bool shouldSeekToEnd); - void seekToEnd(); - - V8EventListenerList* m_list; - V8EventListenerList::ListenerMultiMap::iterator m_iter; - size_t m_vectorIndex; + static V8EventListener* doFindWrapper(v8::Local<v8::Object> object, v8::Handle<v8::String> wrapperProperty) + { + ASSERT(v8::Context::InContext()); + v8::HandleScope scope; + v8::Local<v8::Value> listener = object->GetHiddenValue(wrapperProperty); + if (listener.IsEmpty()) + return 0; + return static_cast<V8EventListener*>(v8::External::Unwrap(listener)); + } + + static inline v8::Handle<v8::String> getHiddenProperty(bool isAttribute) + { + return isAttribute ? V8HiddenPropertyName::attributeListener() : V8HiddenPropertyName::listener(); + } }; - template<typename WrapperType> - PassRefPtr<V8EventListener> V8EventListenerList::findOrCreateWrapper(Frame* frame, v8::Local<v8::Value> object, bool isAttribute) + template<typename WrapperType, typename ContextType> + PassRefPtr<V8EventListener> V8EventListenerList::findOrCreateWrapper(ContextType* context, PassRefPtr<V8ListenerGuard> guard, v8::Local<v8::Value> value, bool isAttribute) { ASSERT(v8::Context::InContext()); - if (!object->IsObject()) + if (!value->IsObject()) return 0; - // FIXME: Should this be v8::Local<v8::Object>::Cast instead? - V8EventListener* wrapper = find(object->ToObject(), isAttribute); + v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(value); + v8::Handle<v8::String> wrapperProperty = getHiddenProperty(isAttribute); + + V8EventListener* wrapper = doFindWrapper(object, wrapperProperty); if (wrapper) return wrapper; - // Create a new one, and add to cache. - RefPtr<WrapperType> newListener = WrapperType::create(frame, v8::Local<v8::Object>::Cast(object), isAttribute); - add(newListener.get()); + PassRefPtr<V8EventListener> wrapperPtr = WrapperType::create(context, guard, object, isAttribute); + if (wrapperPtr) + object->SetHiddenValue(wrapperProperty, v8::External::Wrap(wrapperPtr.get())); - return newListener; - }; + return wrapperPtr; + } } // namespace WebCore diff --git a/WebCore/bindings/v8/V8HiddenPropertyName.cpp b/WebCore/bindings/v8/V8HiddenPropertyName.cpp index 16ac232..d83573f 100644 --- a/WebCore/bindings/v8/V8HiddenPropertyName.cpp +++ b/WebCore/bindings/v8/V8HiddenPropertyName.cpp @@ -33,22 +33,21 @@ namespace WebCore { -v8::Handle<v8::String> V8HiddenPropertyName::objectPrototype() -{ - static v8::Persistent<v8::String>* string = createString("WebCore::V8HiddenPropertyName::objectPrototype"); - - return *string; +#define V8_AS_STRING(x) V8_AS_STRING_IMPL(x) +#define V8_AS_STRING_IMPL(x) #x + +#define V8_DEFINE_PROPERTY(name) \ +v8::Handle<v8::String> V8HiddenPropertyName::name() \ +{ \ + static v8::Persistent<v8::String>* string = createString("WebCore::V8HiddenPropertyName::" V8_AS_STRING(name)); \ + return *string; \ } -v8::Handle<v8::String> V8HiddenPropertyName::isolatedWorld() -{ - static v8::Persistent<v8::String>* string = createString("WebCore::V8HiddenPropertyName::isolatedWorld"); - - return *string; -} +V8_HIDDEN_PROPERTIES(V8_DEFINE_PROPERTY); v8::Persistent<v8::String>* V8HiddenPropertyName::createString(const char* key) { + v8::HandleScope scope; return new v8::Persistent<v8::String>(v8::Persistent<v8::String>::New(v8::String::NewSymbol(key))); } diff --git a/WebCore/bindings/v8/V8HiddenPropertyName.h b/WebCore/bindings/v8/V8HiddenPropertyName.h index 874b525..5ef89cb 100644 --- a/WebCore/bindings/v8/V8HiddenPropertyName.h +++ b/WebCore/bindings/v8/V8HiddenPropertyName.h @@ -35,10 +35,19 @@ namespace WebCore { +#define V8_HIDDEN_PROPERTIES(V) \ + V(objectPrototype) \ + V(isolatedWorld) \ + V(listener) \ + V(attributeListener) \ + V(sleepFunction) \ + V(toStringString) + class V8HiddenPropertyName { public: - static v8::Handle<v8::String> objectPrototype(); - static v8::Handle<v8::String> isolatedWorld(); +#define V8_DECLARE_PROPERTY(name) static v8::Handle<v8::String> name(); + V8_HIDDEN_PROPERTIES(V8_DECLARE_PROPERTY); +#undef V8_DECLARE_PROPERTY private: static v8::Persistent<v8::String>* createString(const char* key); diff --git a/WebCore/bindings/v8/V8Index.cpp b/WebCore/bindings/v8/V8Index.cpp index 9efbc3d..2cbd16d 100644 --- a/WebCore/bindings/v8/V8Index.cpp +++ b/WebCore/bindings/v8/V8Index.cpp @@ -33,6 +33,8 @@ #include "V8Attr.h" #include "V8BarInfo.h" +#include "V8BeforeLoadEvent.h" +#include "V8CanvasRenderingContext.h" #include "V8CanvasRenderingContext2D.h" #include "V8CanvasGradient.h" #include "V8CanvasPattern.h" @@ -107,6 +109,7 @@ #include "V8HTMLHtmlElement.h" #include "V8HTMLIFrameElement.h" #include "V8HTMLImageElement.h" +#include "V8HTMLImageElementConstructor.h" #include "V8HTMLInputElement.h" #include "V8HTMLIsIndexElement.h" #include "V8HTMLLabelElement.h" @@ -121,6 +124,7 @@ #include "V8HTMLOListElement.h" #include "V8HTMLOptGroupElement.h" #include "V8HTMLOptionElement.h" +#include "V8HTMLOptionElementConstructor.h" #include "V8HTMLParagraphElement.h" #include "V8HTMLParamElement.h" #include "V8HTMLPreElement.h" @@ -179,6 +183,7 @@ #include "V8Navigator.h" #include "V8MimeType.h" #include "V8MimeTypeArray.h" +#include "V8PageTransitionEvent.h" #include "V8Plugin.h" #include "V8PluginArray.h" #include "V8Range.h" @@ -195,24 +200,11 @@ #include "V8XMLHttpRequestUpload.h" #include "V8XMLSerializer.h" #include "V8RGBColor.h" -#include "V8VoidCallback.h" - -#if !PLATFORM(ANDROID) -#include "V8InspectorBackend.h" -#endif #if ENABLE(OFFLINE_WEB_APPLICATIONS) #include "V8DOMApplicationCache.h" #endif -#if ENABLE(DATABASE) -#include "V8Database.h" -#include "V8SQLError.h" -#include "V8SQLResultSet.h" -#include "V8SQLResultSetRowList.h" -#include "V8SQLTransaction.h" -#endif - #if ENABLE(DOM_STORAGE) #include "V8Storage.h" #include "V8StorageEvent.h" @@ -254,7 +246,6 @@ #endif #if ENABLE(SVG_FONTS) -#include "V8SVGDefinitionSrcElement.h" #include "V8SVGFontFaceElement.h" #include "V8SVGFontFaceFormatElement.h" #include "V8SVGFontFaceNameElement.h" @@ -370,6 +361,7 @@ #if ENABLE(VIDEO) #include "V8HTMLAudioElement.h" +#include "V8HTMLAudioElementConstructor.h" #include "V8HTMLMediaElement.h" #include "V8HTMLSourceElement.h" #include "V8HTMLVideoElement.h" @@ -377,6 +369,10 @@ #include "V8TimeRanges.h" #endif +#if ENABLE(WEB_SOCKETS) +#include "V8WebSocket.h" +#endif + #if ENABLE(WORKERS) #include "V8AbstractWorker.h" #include "V8DedicatedWorkerContext.h" @@ -386,35 +382,76 @@ #include "V8WorkerNavigator.h" #endif +#if ENABLE(NOTIFICATIONS) +#include "V8Notification.h" +#include "V8NotificationCenter.h" +#endif + #if ENABLE(SHARED_WORKERS) #include "V8SharedWorker.h" #endif -#if ENABLE(GEOLOCATION) -#include "V8Coordinates.h" -#include "V8Geolocation.h" -#include "V8Geoposition.h" -#include "V8PositionError.h" +#if ENABLE(3D_CANVAS) +#include "V8CanvasRenderingContext3D.h" +#include "V8CanvasArrayBuffer.h" +#include "V8CanvasArray.h" +#include "V8CanvasByteArray.h" +#include "V8CanvasBuffer.h" +#include "V8CanvasFloatArray.h" +#include "V8CanvasFramebuffer.h" +#include "V8CanvasIntArray.h" +#include "V8CanvasProgram.h" +#include "V8CanvasRenderbuffer.h" +#include "V8CanvasShader.h" +#include "V8CanvasShortArray.h" +#include "V8CanvasTexture.h" +#include "V8CanvasUnsignedByteArray.h" +#include "V8CanvasUnsignedIntArray.h" +#include "V8CanvasUnsignedShortArray.h" #endif -#if ENABLE(TOUCH_EVENTS) -#include "V8Touch.h" -#include "V8TouchList.h" -#include "V8TouchEvent.h" +#if ENABLE(DATABASE) +#include "V8Database.h" +#include "V8SQLError.h" +#include "V8SQLResultSet.h" +#include "V8SQLResultSetRowList.h" +#include "V8SQLTransaction.h" #endif #if ENABLE(XPATH) #include "V8XPathResult.h" #include "V8XPathException.h" #include "V8XPathExpression.h" -#include "V8XPathEvaluator.h" #include "V8XPathNSResolver.h" +#include "V8XPathEvaluator.h" #endif #if ENABLE(XSLT) #include "V8XSLTProcessor.h" #endif +#if ENABLE(INSPECTOR) +#include "V8InspectorBackend.h" +#endif + +#if PLATFORM(ANDROID) +// TODO: Upstream these guards to webkit.org +#if ENABLE(GEOLOCATION) +#include "V8Coordinates.h" +#include "V8Geolocation.h" +#include "V8Geoposition.h" +#include "V8PositionError.h" +#endif + +#if ENABLE(TOUCH_EVENTS) +#include "V8Touch.h" +#include "V8TouchList.h" +#include "V8TouchEvent.h" +#endif + +#include "V8VoidCallback.h" +#endif // PLATFORM(ANDROID) + namespace WebCore { FunctionTemplateFactory V8ClassIndex::GetFactory(V8WrapperType type) diff --git a/WebCore/bindings/v8/V8Index.h b/WebCore/bindings/v8/V8Index.h index d6db4c6..179b963 100644 --- a/WebCore/bindings/v8/V8Index.h +++ b/WebCore/bindings/v8/V8Index.h @@ -54,6 +54,7 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); #if ENABLE(VIDEO) #define VIDEO_HTMLELEMENT_TYPES(V) \ + V(AUDIO, HTMLAudioElementConstructor) \ V(HTMLAUDIOELEMENT, HTMLAudioElement) \ V(HTMLMEDIAELEMENT, HTMLMediaElement) \ V(HTMLSOURCEELEMENT, HTMLSourceElement) \ @@ -82,16 +83,26 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); #endif #if ENABLE(OFFLINE_WEB_APPLICATIONS) -#define APPLICATIONCACHE_NONNODE_WRAPPER_TYPES(V) \ +#define APPLICATIONCACHE_NONNODE_WRAPPER_TYPES(V) \ V(DOMAPPLICATIONCACHE, DOMApplicationCache) #else #define APPLICATIONCACHE_NONNODE_WRAPPER_TYPES(V) #endif +#if ENABLE(NOTIFICATIONS) +#define NOTIFICATIONS_NONNODE_WRAPPER_TYPES(V) \ + V(NOTIFICATION, Notification) \ + V(NOTIFICATIONCENTER, NotificationCenter) +#else +#define NOTIFICATIONS_NONNODE_WRAPPER_TYPES(V) +#endif + #if ENABLE(SHARED_WORKERS) #define SHARED_WORKER_ACTIVE_OBJECT_WRAPPER_TYPES(V) \ V(SHAREDWORKER, SharedWorker) -#define SHARED_WORKER_NONNODE_WRAPPER_TYPES(V) + +#define SHARED_WORKER_NONNODE_WRAPPER_TYPES(V) \ + V(SHAREDWORKERCONTEXT, SharedWorkerContext) #else #define SHARED_WORKER_ACTIVE_OBJECT_WRAPPER_TYPES(V) #define SHARED_WORKER_NONNODE_WRAPPER_TYPES(V) @@ -109,7 +120,9 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); V(ENTITY, Entity) \ V(ENTITYREFERENCE, EntityReference) \ V(HTMLDOCUMENT, HTMLDocument) \ + V(IMAGE, HTMLImageElementConstructor) \ V(NODE, Node) \ + V(OPTION, HTMLOptionElementConstructor) \ V(NOTATION, Notation) \ V(PROCESSINGINSTRUCTION, ProcessingInstruction) \ V(TEXT, Text) \ @@ -216,7 +229,6 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); #if ENABLE(SVG_FONTS) #define SVG_FONTS_ELEMENT_TYPES(V) \ - V(SVGDEFINITIONSRCELEMENT, SVGDefinitionSrcElement) \ V(SVGFONTFACEELEMENT, SVGFontFaceElement) \ V(SVGFONTFACEFORMATELEMENT, SVGFontFaceFormatElement) \ V(SVGFONTFACENAMEELEMENT, SVGFontFaceNameElement) \ @@ -289,13 +301,21 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); #endif // SVG +#if ENABLE(WEB_SOCKETS) +#define WEBSOCKET_ACTIVE_OBJECT_WRAPPER_TYPES(V) \ + V(WEBSOCKET, WebSocket) +#else +#define WEBSOCKET_ACTIVE_OBJECT_WRAPPER_TYPES(V) +#endif + // ACTIVE_DOM_OBJECT_TYPES are DOM_OBJECT_TYPES that need special treatement // during GC. #define ACTIVE_DOM_OBJECT_TYPES(V) \ V(MESSAGEPORT, MessagePort) \ V(XMLHTTPREQUEST, XMLHttpRequest) \ WORKER_ACTIVE_OBJECT_WRAPPER_TYPES(V) \ - SHARED_WORKER_ACTIVE_OBJECT_WRAPPER_TYPES(V) + SHARED_WORKER_ACTIVE_OBJECT_WRAPPER_TYPES(V) \ + WEBSOCKET_ACTIVE_OBJECT_WRAPPER_TYPES(V) // NOTE: DOM_OBJECT_TYPES is split into two halves because // Visual Studio's Intellinonsense crashes when macros get @@ -303,8 +323,10 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); // DOM_OBJECT_TYPES are non-node DOM types. #define DOM_OBJECT_TYPES_1(V) \ V(BARINFO, BarInfo) \ + V(BEFORELOADEVENT, BeforeLoadEvent) \ V(CANVASGRADIENT, CanvasGradient) \ V(CANVASPATTERN, CanvasPattern) \ + V(CANVASRENDERINGCONTEXT, CanvasRenderingContext) \ V(CANVASRENDERINGCONTEXT2D, CanvasRenderingContext2D) \ V(CLIENTRECT, ClientRect) \ V(CLIENTRECTLIST, ClientRectList) \ @@ -359,6 +381,7 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); V(NODEITERATOR, NodeIterator) \ V(NODELIST, NodeList) \ V(OVERFLOWEVENT, OverflowEvent) \ + V(PAGETRANSITIONEVENT, PageTransitionEvent) \ V(PLUGIN, Plugin) \ V(PLUGINARRAY, PluginArray) \ V(PROGRESSEVENT, ProgressEvent) \ @@ -374,7 +397,6 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); V(TREEWALKER, TreeWalker) \ V(UIEVENT, UIEvent) \ V(VALIDITYSTATE, ValidityState) \ - V(VOIDCALLBACK, VoidCallback) \ V(WEBKITANIMATIONEVENT, WebKitAnimationEvent) \ V(WEBKITCSSKEYFRAMERULE, WebKitCSSKeyframeRule) \ V(WEBKITCSSKEYFRAMESRULE, WebKitCSSKeyframesRule) \ @@ -391,27 +413,10 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); APPLICATIONCACHE_NONNODE_WRAPPER_TYPES(V) \ DATAGRID_NONNODE_TYPES(V) \ VIDEO_NONNODE_TYPES(V) \ + NOTIFICATIONS_NONNODE_WRAPPER_TYPES(V) \ SHARED_WORKER_NONNODE_WRAPPER_TYPES(V) \ WORKER_NONNODE_WRAPPER_TYPES(V) -#if ENABLE(XPATH) -#define DOM_OBJECT_XPATH_TYPES(V) \ - V(XPATHEVALUATOR, XPathEvaluator) \ - V(XPATHEXCEPTION, XPathException) \ - V(XPATHEXPRESSION, XPathExpression) \ - V(XPATHNSRESOLVER, XPathNSResolver) \ - V(XPATHRESULT, XPathResult) -#else -#define DOM_OBJECT_XPATH_TYPES(V) -#endif - -#if ENABLE(XSLT) -#define DOM_OBJECT_XSLT_TYPES(V) \ - V(XSLTPROCESSOR, XSLTProcessor) -#else -#define DOM_OBJECT_XSLT_TYPES(V) -#endif - #if ENABLE(DATABASE) #define DOM_OBJECT_DATABASE_TYPES(V) \ V(DATABASE, Database) \ @@ -438,6 +443,53 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); #define DOM_OBJECT_WORKERS_TYPES(V) #endif +#if ENABLE(3D_CANVAS) +#define DOM_OBJECT_3D_CANVAS_TYPES(V) \ + V(CANVASARRAY, CanvasArray) \ + V(CANVASARRAYBUFFER, CanvasArrayBuffer) \ + V(CANVASBUFFER, CanvasBuffer) \ + V(CANVASBYTEARRAY, CanvasByteArray) \ + V(CANVASFLOATARRAY, CanvasFloatArray) \ + V(CANVASFRAMEBUFFER, CanvasFramebuffer) \ + V(CANVASINTARRAY, CanvasIntArray) \ + V(CANVASPROGRAM, CanvasProgram) \ + V(CANVASRENDERBUFFER, CanvasRenderbuffer) \ + V(CANVASRENDERINGCONTEXT3D, CanvasRenderingContext3D) \ + V(CANVASSHADER, CanvasShader) \ + V(CANVASSHORTARRAY, CanvasShortArray) \ + V(CANVASTEXTURE, CanvasTexture) \ + V(CANVASUNSIGNEDBYTEARRAY, CanvasUnsignedByteArray) \ + V(CANVASUNSIGNEDINTARRAY, CanvasUnsignedIntArray) \ + V(CANVASUNSIGNEDSHORTARRAY, CanvasUnsignedShortArray) +#else +#define DOM_OBJECT_3D_CANVAS_TYPES(V) +#endif + +#if ENABLE(XPATH) +#define DOM_OBJECT_XPATH_TYPES(V) \ + V(XPATHEVALUATOR, XPathEvaluator) \ + V(XPATHEXCEPTION, XPathException) \ + V(XPATHEXPRESSION, XPathExpression) \ + V(XPATHNSRESOLVER, XPathNSResolver) \ + V(XPATHRESULT, XPathResult) +#else +#define DOM_OBJECT_XPATH_TYPES(V) +#endif + +#if ENABLE(XSLT) +#define DOM_OBJECT_XSLT_TYPES(V) \ + V(XSLTPROCESSOR, XSLTProcessor) +#else +#define DOM_OBJECT_XSLT_TYPES(V) +#endif + +#if ENABLE(INSPECTOR) +#define DOM_OBJECT_INSPECTOR_TYPES(V) \ + V(INSPECTORBACKEND, InspectorBackend) +#else +#define DOM_OBJECT_INSPECTOR_TYPES(V) +#endif + #if ENABLE(GEOLOCATION) #define DOM_OBJECT_GEOLOCATION_TYPES(V) \ V(COORDINATES, Coordinates) \ @@ -448,6 +500,8 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); #define DOM_OBJECT_GEOLOCATION_TYPES(V) #endif +#if PLATFORM(ANDROID) +// TODO: Upstream this guard. #if ENABLE(TOUCH_EVENTS) #define DOM_OBJECT_TOUCH_EVENT_TYPES(V) \ V(TOUCHLIST, TouchList) \ @@ -456,26 +510,30 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); #else #define DOM_OBJECT_TOUCH_EVENT_TYPES(V) #endif +#endif -#if PLATFORM(CHROMIUM) +#if PLATFORM(ANDROID) +#define DOM_OBJECT_VOIDCALLBACK_TYPES(V) \ + V(VOIDCALLBACK, VoidCallback) +#else +#define DOM_OBJECT_VOIDCALLBACK_TYPES(V) +#endif + +#if PLATFORM(ANDROID) +// This block is modified, but is not Android-specific. #define DOM_OBJECT_TYPES(V) \ DOM_OBJECT_TYPES_1(V) \ DOM_OBJECT_TYPES_2(V) \ DOM_OBJECT_DATABASE_TYPES(V) \ DOM_OBJECT_STORAGE_TYPES(V) \ DOM_OBJECT_WORKERS_TYPES(V) \ + DOM_OBJECT_3D_CANVAS_TYPES(V) \ DOM_OBJECT_XPATH_TYPES(V) \ DOM_OBJECT_XSLT_TYPES(V) \ - V(INSPECTORBACKEND, InspectorBackend) -#elif PLATFORM(ANDROID) -#define DOM_OBJECT_TYPES(V) \ - DOM_OBJECT_TYPES_1(V) \ - DOM_OBJECT_TYPES_2(V) \ - DOM_OBJECT_DATABASE_TYPES(V) \ DOM_OBJECT_GEOLOCATION_TYPES(V) \ - DOM_OBJECT_STORAGE_TYPES(V) \ DOM_OBJECT_TOUCH_EVENT_TYPES(V) \ - DOM_OBJECT_WORKERS_TYPES(V) + DOM_OBJECT_VOIDCALLBACK_TYPES(V) \ + DOM_OBJECT_INSPECTOR_TYPES(V) #endif #if ENABLE(SVG) diff --git a/WebCore/bindings/v8/V8IsolatedWorld.cpp b/WebCore/bindings/v8/V8IsolatedWorld.cpp index 1457545..d4e4f52 100644 --- a/WebCore/bindings/v8/V8IsolatedWorld.cpp +++ b/WebCore/bindings/v8/V8IsolatedWorld.cpp @@ -43,34 +43,29 @@ namespace WebCore { -static int isolatedWorldCount = 0; +int V8IsolatedWorld::isolatedWorldCount = 0; -static void contextWeakReferenceCallback(v8::Persistent<v8::Value> object, void* isolated_world) +void V8IsolatedWorld::contextWeakReferenceCallback(v8::Persistent<v8::Value> object, void* isolated_world) { // Our context is going away. Time to clean up the world. V8IsolatedWorld* world = static_cast<V8IsolatedWorld*>(isolated_world); delete world; } -void V8IsolatedWorld::evaluate(const Vector<ScriptSourceCode>& sources, V8Proxy* proxy, int extensionGroup) +V8IsolatedWorld::V8IsolatedWorld(V8Proxy* proxy, int extensionGroup) { + ++isolatedWorldCount; + v8::HandleScope scope; - v8::Persistent<v8::Context> context = proxy->createNewContext(v8::Handle<v8::Object>(), extensionGroup); + m_context = SharedPersistent<v8::Context>::create(proxy->createNewContext(v8::Handle<v8::Object>(), extensionGroup)); // Run code in the new context. - v8::Context::Scope context_scope(context); - - // The lifetime of this object is controlled by the V8 GC. - // We need to create the world before touching DOM wrappers. - V8IsolatedWorld* world = new V8IsolatedWorld(context); + v8::Context::Scope context_scope(m_context->get()); - V8Proxy::installHiddenObjectPrototype(context); - proxy->installDOMWindow(context, proxy->frame()->domWindow()); - - proxy->frame()->loader()->client()->didCreateIsolatedScriptContext(); + m_context->get()->Global()->SetHiddenValue(V8HiddenPropertyName::isolatedWorld(), v8::External::Wrap(this)); - for (size_t i = 0; i < sources.size(); ++i) - proxy->evaluate(sources[i], 0); + V8Proxy::installHiddenObjectPrototype(m_context->get()); + proxy->installDOMWindow(m_context->get(), proxy->frame()->domWindow()); // Using the default security token means that the canAccess is always // called, which is slow. @@ -78,40 +73,24 @@ void V8IsolatedWorld::evaluate(const Vector<ScriptSourceCode>& sources, V8Proxy* // created contexts so that they can all be updated when the // document domain // changes. - // FIXME: Move this statement above proxy->evaluate? It seems like we - // should set up the token before running the script. - context->UseDefaultSecurityToken(); + m_context->get()->UseDefaultSecurityToken(); - context.Dispose(); - // WARNING! This might well delete |world|. + proxy->frame()->loader()->client()->didCreateIsolatedScriptContext(); } -V8IsolatedWorld::V8IsolatedWorld(v8::Handle<v8::Context> context) - : m_context(v8::Persistent<v8::Context>::New(context)) +void V8IsolatedWorld::destroy() { - ++isolatedWorldCount; - m_context.MakeWeak(this, &contextWeakReferenceCallback); - m_context->Global()->SetHiddenValue(V8HiddenPropertyName::isolatedWorld(), v8::External::Wrap(this)); + m_context->get().MakeWeak(this, &contextWeakReferenceCallback); } V8IsolatedWorld::~V8IsolatedWorld() { --isolatedWorldCount; - m_context.Dispose(); - m_context.Clear(); + m_context->disposeHandle(); } -V8IsolatedWorld* V8IsolatedWorld::getEntered() +V8IsolatedWorld* V8IsolatedWorld::getEnteredImpl() { - if (isolatedWorldCount == 0) { - // This is a temporary performance optimization. Essentially, - // GetHiddenValue is too slow for this code path. We need to get the - // V8 team to add a real property to v8::Context for isolated worlds. - // Until then, we optimize the common case of not having any isolated - // worlds at all. - return 0; - } - if (!v8::Context::InContext()) return 0; v8::HandleScope scope; diff --git a/WebCore/bindings/v8/V8IsolatedWorld.h b/WebCore/bindings/v8/V8IsolatedWorld.h index 2036e65..15d8711 100644 --- a/WebCore/bindings/v8/V8IsolatedWorld.h +++ b/WebCore/bindings/v8/V8IsolatedWorld.h @@ -35,6 +35,7 @@ #include "V8DOMMap.h" #include "V8Index.h" +#include "V8Proxy.h" #include "V8Utilities.h" #include "ScriptSourceCode.h" // for WebCore::ScriptSourceCode @@ -57,11 +58,14 @@ namespace WebCore { // class V8IsolatedWorld { public: - ~V8IsolatedWorld(); + // Creates an isolated world. To destroy it, call destroy(). + // This will delete the isolated world when the context it owns is GC'd. + V8IsolatedWorld(V8Proxy* proxy, int extensionGroup); - // Evaluate JavaScript in a new isolated world. The script has access - // to the DOM of the document associated with |proxy|. - static void evaluate(const Vector<ScriptSourceCode>& sources, V8Proxy* proxy, int extensionGroup); + // Call this to destroy the isolated world. It will be deleted sometime + // after this call, once all script references to the world's context + // have been dropped. + void destroy(); // Returns the isolated world associated with // v8::Context::GetEntered(). Because worlds are isolated, the entire @@ -71,26 +75,42 @@ namespace WebCore { // FIXME: Consider edge cases with DOM mutation events that might // violate this invariant. // - static V8IsolatedWorld* getEntered(); + static V8IsolatedWorld* getEntered() + { + // This is a temporary performance optimization. Essentially, + // GetHiddenValue is too slow for this code path. We need to get the + // V8 team to add a real property to v8::Context for isolated worlds. + // Until then, we optimize the common case of not having any isolated + // worlds at all. + if (!isolatedWorldCount) + return 0; + return getEnteredImpl(); + } - v8::Handle<v8::Context> context() { return m_context; } + v8::Handle<v8::Context> context() { return m_context->get(); } + PassRefPtr<SharedPersistent<v8::Context> > shared_context() { return m_context; } DOMDataStore* getDOMDataStore() const { return m_domDataStore.getStore(); } private: - // The lifetime of an isolated world is managed by the V8 garbage - // collector. In particular, the object created by this constructor is - // freed when |context| is garbage collected. - explicit V8IsolatedWorld(v8::Handle<v8::Context> context); + ~V8IsolatedWorld(); + + static V8IsolatedWorld* getEnteredImpl(); + + // Called by the garbage collector when our JavaScript context is about + // to be destroyed. + static void contextWeakReferenceCallback(v8::Persistent<v8::Value> object, void* isolated_world); // The v8::Context for the isolated world. This object is keep on the // heap as long as |m_context| has not been garbage collected. - v8::Persistent<v8::Context> m_context; + RefPtr<SharedPersistent<v8::Context> > m_context; // The backing store for the isolated world's DOM wrappers. This class // doesn't have visibility into the wrappers. This handle simply helps // manage their lifetime. DOMDataStoreHandle m_domDataStore; + + static int isolatedWorldCount; }; } // namespace WebCore diff --git a/WebCore/bindings/v8/V8LazyEventListener.cpp b/WebCore/bindings/v8/V8LazyEventListener.cpp index 59fa7be..9b58571 100644 --- a/WebCore/bindings/v8/V8LazyEventListener.cpp +++ b/WebCore/bindings/v8/V8LazyEventListener.cpp @@ -33,199 +33,115 @@ #include "Frame.h" #include "V8Binding.h" +#include "V8HiddenPropertyName.h" #include "V8Proxy.h" +#include <wtf/StdLibExtras.h> + namespace WebCore { -V8LazyEventListener::V8LazyEventListener(Frame *frame, const String& code, const String& functionName, bool isSVGEvent) - : V8AbstractEventListener(frame, true) +V8LazyEventListener::V8LazyEventListener(Frame* frame, const String& code, const String& functionName, bool isSVGEvent) + : V8AbstractEventListener(frame, 0, true) , m_code(code) , m_functionName(functionName) , m_isSVGEvent(isSVGEvent) - , m_compiled(false) - , m_wrappedFunctionCompiled(false) -{ -} - -V8LazyEventListener::~V8LazyEventListener() { - disposeListenerObject(); - - // Dispose wrapped function - if (!m_wrappedFunction.IsEmpty()) { -#ifndef NDEBUG - V8GCController::unregisterGlobalHandle(this, m_wrappedFunction); -#endif - m_wrappedFunction.Dispose(); - m_wrappedFunction.Clear(); - } } -v8::Local<v8::Function> V8LazyEventListener::getListenerFunction() +v8::Local<v8::Value> V8LazyEventListener::callListenerFunction(v8::Handle<v8::Value> jsEvent, Event* event) { - if (m_compiled) { - ASSERT(m_listener.IsEmpty() || m_listener->IsFunction()); - return m_listener.IsEmpty() ? v8::Local<v8::Function>() : v8::Local<v8::Function>::New(v8::Persistent<v8::Function>::Cast(m_listener)); - } - - m_compiled = true; - - ASSERT(m_frame); - - { - // Switch to the context of m_frame. - v8::HandleScope handleScope; - - // Use the outer scope to hold context. - v8::Handle<v8::Context> v8Context = V8Proxy::mainWorldContext(m_frame); - // Bail out if we could not get the context. - if (v8Context.IsEmpty()) - return v8::Local<v8::Function>(); - - v8::Context::Scope scope(v8Context); - - // Wrap function around the event code. The parenthesis around the function are needed so that evaluating the code yields - // the function value. Without the parenthesis the function value is thrown away. - - // Make it an anonymous function to avoid name conflict for cases like - // <body onload='onload()'> - // <script> function onload() { alert('hi'); } </script>. - // Set function name to function object instead. - // See issue 944690. - // - // The ECMAScript spec says (very obliquely) that the parameter to an event handler is named "evt". - // - // Don't use new lines so that lines in the modified handler - // have the same numbers as in the original code. - String code = "(function (evt) {"; - code.append(m_code); - code.append("\n})"); - - v8::Handle<v8::String> codeExternalString = v8ExternalString(code); - v8::Handle<v8::Script> script = V8Proxy::compileScript(codeExternalString, m_frame->document()->url(), m_lineNumber - 1); - if (!script.IsEmpty()) { - V8Proxy* proxy = V8Proxy::retrieve(m_frame); - ASSERT(proxy); - v8::Local<v8::Value> value = proxy->runScript(script, false); - if (!value.IsEmpty()) { - ASSERT(value->IsFunction()); - v8::Local<v8::Function> listenerFunction = v8::Local<v8::Function>::Cast(value); - listenerFunction->SetName(v8::String::New(fromWebCoreString(m_functionName), m_functionName.length())); - - m_listener = v8::Persistent<v8::Function>::New(listenerFunction); -#ifndef NDEBUG - V8GCController::registerGlobalHandle(EVENT_LISTENER, this, m_listener); -#endif - } - } - } - - ASSERT(m_listener.IsEmpty() || m_listener->IsFunction()); - return m_listener.IsEmpty() ? v8::Local<v8::Function>() : v8::Local<v8::Function>::New(v8::Persistent<v8::Function>::Cast(m_listener)); -} - -v8::Local<v8::Value> V8LazyEventListener::callListenerFunction(v8::Handle<v8::Value> jsEvent, Event* event, bool isWindowEvent) -{ - v8::Local<v8::Function> handlerFunction = getWrappedListenerFunction(); - v8::Local<v8::Object> receiver = getReceiverObject(event, isWindowEvent); + v8::Local<v8::Function> handlerFunction = v8::Local<v8::Function>::Cast(getListenerObject()); + v8::Local<v8::Object> receiver = getReceiverObject(event); if (handlerFunction.IsEmpty() || receiver.IsEmpty()) return v8::Local<v8::Value>(); v8::Handle<v8::Value> parameters[1] = { jsEvent }; - V8Proxy* proxy = V8Proxy::retrieve(m_frame); + V8Proxy* proxy = V8Proxy::retrieve(frame()); return proxy->callFunction(handlerFunction, receiver, 1, parameters); } - static v8::Handle<v8::Value> V8LazyEventListenerToString(const v8::Arguments& args) { - return args.Callee()->GetHiddenValue(v8::String::New("toStringString")); + return args.Holder()->GetHiddenValue(V8HiddenPropertyName::toStringString()); } - -v8::Local<v8::Function> V8LazyEventListener::getWrappedListenerFunction() +void V8LazyEventListener::prepareListenerObject() { - if (m_wrappedFunctionCompiled) { - ASSERT(m_wrappedFunction.IsEmpty() || m_wrappedFunction->IsFunction()); - return m_wrappedFunction.IsEmpty() ? v8::Local<v8::Function>() : v8::Local<v8::Function>::New(m_wrappedFunction); - } - - m_wrappedFunctionCompiled = true; - - { - // Switch to the context of m_frame. - v8::HandleScope handleScope; - - // Use the outer scope to hold context. - v8::Handle<v8::Context> v8Context = V8Proxy::mainWorldContext(m_frame); - // Bail out if we cannot get the context. - if (v8Context.IsEmpty()) - return v8::Local<v8::Function>(); - - v8::Context::Scope scope(v8Context); - - // FIXME: cache the wrapper function. - - // Nodes other than the document object, when executing inline event handlers push document, form, and the target node on the scope chain. - // We do this by using 'with' statement. - // See chrome/fast/forms/form-action.html - // chrome/fast/forms/selected-index-value.html - // base/fast/overflow/onscroll-layer-self-destruct.html - // - // Don't use new lines so that lines in the modified handler - // have the same numbers as in the original code. - String code = "(function (evt) {" \ - "with (this.ownerDocument ? this.ownerDocument : {}) {" \ - "with (this.form ? this.form : {}) {" \ - "with (this) {" \ - "return (function(evt){"; - code.append(m_code); - // Insert '\n' otherwise //-style comments could break the handler. - code.append( "\n}).call(this, evt);}}}})"); - v8::Handle<v8::String> codeExternalString = v8ExternalString(code); - v8::Handle<v8::Script> script = V8Proxy::compileScript(codeExternalString, m_frame->document()->url(), m_lineNumber); - if (!script.IsEmpty()) { - V8Proxy* proxy = V8Proxy::retrieve(m_frame); - ASSERT(proxy); - v8::Local<v8::Value> value = proxy->runScript(script, false); - if (!value.IsEmpty()) { - ASSERT(value->IsFunction()); - - m_wrappedFunction = v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(value)); - - // Change the toString function on the wrapper function to avoid it returning the source for the actual wrapper function. Instead - // it returns source for a clean wrapper function with the event argument wrapping the event source code. The reason for this - // is that some web sites uses toString on event functions and the evals the source returned (some times a RegExp is applied as - // well) for some other use. That fails miserably if the actual wrapper source is returned. - v8::Local<v8::FunctionTemplate> toStringTemplate = v8::FunctionTemplate::New(V8LazyEventListenerToString); - v8::Local<v8::Function> toStringFunction; - if (!toStringTemplate.IsEmpty()) - toStringFunction = toStringTemplate->GetFunction(); - if (!toStringFunction.IsEmpty()) { - String toStringResult = "function "; - toStringResult.append(m_functionName); - toStringResult.append("("); - if (m_isSVGEvent) - toStringResult.append("evt"); - else - toStringResult.append("event"); - toStringResult.append(") {\n "); - toStringResult.append(m_code); - toStringResult.append("\n}"); - toStringFunction->SetHiddenValue(v8::String::New("toStringString"), v8ExternalString(toStringResult)); - m_wrappedFunction->Set(v8::String::New("toString"), toStringFunction); - } - -#ifndef NDEBUG - V8GCController::registerGlobalHandle(EVENT_LISTENER, this, m_wrappedFunction); -#endif - m_wrappedFunction->SetName(v8::String::New(fromWebCoreString(m_functionName), m_functionName.length())); + if (hasExistingListenerObject()) + return; + + // Switch to the context of m_frame. + v8::HandleScope handleScope; + + // Use the outer scope to hold context. + v8::Handle<v8::Context> v8Context = V8Proxy::mainWorldContext(frame()); + // Bail out if we cannot get the context. + if (v8Context.IsEmpty()) + return; + + v8::Context::Scope scope(v8Context); + + // FIXME: cache the wrapper function. + + // Nodes other than the document object, when executing inline event handlers push document, form, and the target node on the scope chain. + // We do this by using 'with' statement. + // See chrome/fast/forms/form-action.html + // chrome/fast/forms/selected-index-value.html + // base/fast/overflow/onscroll-layer-self-destruct.html + // + // Don't use new lines so that lines in the modified handler + // have the same numbers as in the original code. + String code = "(function (evt) {" \ + "with (this.ownerDocument ? this.ownerDocument : {}) {" \ + "with (this.form ? this.form : {}) {" \ + "with (this) {" \ + "return (function(evt){"; + code.append(m_code); + // Insert '\n' otherwise //-style comments could break the handler. + code.append( "\n}).call(this, evt);}}}})"); + v8::Handle<v8::String> codeExternalString = v8ExternalString(code); + v8::Handle<v8::Script> script = V8Proxy::compileScript(codeExternalString, frame()->document()->url(), lineNumber()); + if (!script.IsEmpty()) { + V8Proxy* proxy = V8Proxy::retrieve(frame()); + ASSERT(proxy); + v8::Local<v8::Value> value = proxy->runScript(script, false); + if (!value.IsEmpty()) { + ASSERT(value->IsFunction()); + + v8::Local<v8::Function> wrappedFunction = v8::Local<v8::Function>::Cast(value); + + // Change the toString function on the wrapper function to avoid it + // returning the source for the actual wrapper function. Instead it + // returns source for a clean wrapper function with the event + // argument wrapping the event source code. The reason for this is + // that some web sites use toString on event functions and eval the + // source returned (sometimes a RegExp is applied as well) for some + // other use. That fails miserably if the actual wrapper source is + // returned. + DEFINE_STATIC_LOCAL(v8::Persistent<v8::FunctionTemplate>, toStringTemplate, ()); + if (toStringTemplate.IsEmpty()) + toStringTemplate = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(V8LazyEventListenerToString)); + v8::Local<v8::Function> toStringFunction; + if (!toStringTemplate.IsEmpty()) + toStringFunction = toStringTemplate->GetFunction(); + if (!toStringFunction.IsEmpty()) { + String toStringResult = "function "; + toStringResult.append(m_functionName); + toStringResult.append("("); + toStringResult.append(m_isSVGEvent ? "evt" : "event"); + toStringResult.append(") {\n "); + toStringResult.append(m_code); + toStringResult.append("\n}"); + wrappedFunction->SetHiddenValue(V8HiddenPropertyName::toStringString(), v8ExternalString(toStringResult)); + wrappedFunction->Set(v8::String::New("toString"), toStringFunction); } + + wrappedFunction->SetName(v8::String::New(fromWebCoreString(m_functionName), m_functionName.length())); + + setListenerObject(wrappedFunction); } } - - return v8::Local<v8::Function>::New(m_wrappedFunction); } } // namespace WebCore diff --git a/WebCore/bindings/v8/V8LazyEventListener.h b/WebCore/bindings/v8/V8LazyEventListener.h index 62d9342..ba460e6 100644 --- a/WebCore/bindings/v8/V8LazyEventListener.h +++ b/WebCore/bindings/v8/V8LazyEventListener.h @@ -50,30 +50,19 @@ namespace WebCore { return adoptRef(new V8LazyEventListener(frame, code, functionName, isSVGEvent)); } - // For lazy event listener, the listener object is the same as its listener - // function without additional scope chains. - virtual v8::Local<v8::Object> getListenerObject() { return getWrappedListenerFunction(); } + virtual bool isLazy() const { return true; } + + protected: + virtual void prepareListenerObject(); private: V8LazyEventListener(Frame*, const String& code, const String& functionName, bool isSVGEvent); - virtual ~V8LazyEventListener(); - virtual bool virtualisAttribute() const { return true; } + virtual v8::Local<v8::Value> callListenerFunction(v8::Handle<v8::Value> jsEvent, Event*); String m_code; String m_functionName; bool m_isSVGEvent; - bool m_compiled; - - // If the event listener is on a non-document dom node, we compile the function with some implicit scope chains before it. - bool m_wrappedFunctionCompiled; - v8::Persistent<v8::Function> m_wrappedFunction; - - v8::Local<v8::Function> getWrappedListenerFunction(); - - virtual v8::Local<v8::Value> callListenerFunction(v8::Handle<v8::Value> jsEvent, Event*, bool isWindowEvent); - - v8::Local<v8::Function> getListenerFunction(); }; } // namespace WebCore diff --git a/WebCore/bindings/v8/V8ObjectEventListener.cpp b/WebCore/bindings/v8/V8ObjectEventListener.cpp deleted file mode 100644 index f10766c..0000000 --- a/WebCore/bindings/v8/V8ObjectEventListener.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2006, 2007, 2008, 2009 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 THE COPYRIGHT - * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "V8ObjectEventListener.h" - -#include "Frame.h" -#include "V8Proxy.h" - -namespace WebCore { - -static void weakObjectEventListenerCallback(v8::Persistent<v8::Value>, void* parameter) -{ - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(parameter); - - // Remove the wrapper - Frame* frame = listener->frame(); - if (frame) { - V8Proxy* proxy = V8Proxy::retrieve(frame); - if (proxy) - proxy->objectListeners()->remove(listener); - - // Because the listener is no longer in the list, it must be disconnected from the frame to avoid dangling frame pointer - // in the destructor. - listener->disconnectFrame(); - } - listener->disposeListenerObject(); -} - -// An object event listener wrapper only holds a weak reference to the -// JS function. A strong reference can create a cycle. -// -// The lifetime of these objects is bounded by the life time of the JS -// wrapper of XHR or Node. So we can create a hidden reference from -// the JS wrapper to to its JS function. -// -// (map) -// XHR or Node <---------- JS_wrapper -// | (hidden) : ^ -// V V : (may be reachable by closure) -// V8_listener --------> JS_function -// (weak) <-- may create a cycle if it is strong -// -// The persistent reference is made weak in the constructor of -// V8ObjectEventListener. - -V8ObjectEventListener::V8ObjectEventListener(Frame* frame, v8::Local<v8::Object> listener, bool isInline) - : V8EventListener(frame, listener, isInline) -{ - m_listener.MakeWeak(this, weakObjectEventListenerCallback); -} - -V8ObjectEventListener::~V8ObjectEventListener() -{ - if (m_frame) { - ASSERT(!m_listener.IsEmpty()); - V8Proxy* proxy = V8Proxy::retrieve(m_frame); - if (proxy) - proxy->objectListeners()->remove(this); - } - - disposeListenerObject(); -} - -} // namespace WebCore diff --git a/WebCore/bindings/v8/V8Proxy.cpp b/WebCore/bindings/v8/V8Proxy.cpp index 1cfafb8..dd3c218 100644 --- a/WebCore/bindings/v8/V8Proxy.cpp +++ b/WebCore/bindings/v8/V8Proxy.cpp @@ -32,11 +32,14 @@ #include "V8Proxy.h" #include "CSSMutableStyleDeclaration.h" -#include "CString.h" +#include "DateExtension.h" #include "DOMObjectsInclude.h" #include "DocumentLoader.h" #include "FrameLoaderClient.h" +#include "Page.h" +#include "PageGroup.h" #include "ScriptController.h" +#include "StorageNamespace.h" #include "V8Binding.h" #include "V8Collection.h" #include "V8ConsoleMessage.h" @@ -47,6 +50,8 @@ #include "V8Index.h" #include "V8IsolatedWorld.h" +#include <algorithm> +#include <utility> #include <v8.h> #include <v8-debug.h> #include <wtf/Assertions.h> @@ -62,12 +67,16 @@ #include "TimeCounter.h" #endif +#if PLATFORM(ANDROID) +#include "CString.h" +#endif + namespace WebCore { v8::Persistent<v8::Context> V8Proxy::m_utilityContext; // Static list of registered extensions -V8ExtensionList V8Proxy::m_extensions; +V8Extensions V8Proxy::m_extensions; const char* V8Proxy::kContextDebugDataType = "type"; const char* V8Proxy::kContextDebugDataValue = "value"; @@ -213,6 +222,14 @@ static void reportFatalErrorInV8(const char* location, const char* message) handleFatalErrorInV8(); } +V8Proxy::V8Proxy(Frame* frame) + : m_frame(frame), + m_context(SharedPersistent<v8::Context>::create()), + m_listenerGuard(V8ListenerGuard::create()), + m_inlineCode(false), + m_timerCallback(false), + m_recursion(0) { } + V8Proxy::~V8Proxy() { clearForClose(); @@ -230,22 +247,6 @@ void V8Proxy::destroyGlobal() } } -static void disconnectEventListenersInList(V8EventListenerList& list) -{ - V8EventListenerList::iterator it = list.begin(); - while (it != list.end()) { - (*it)->disconnectFrame(); - ++it; - } - list.clear(); -} - -void V8Proxy::disconnectEventListeners() -{ - disconnectEventListenersInList(m_eventListeners); - disconnectEventListenersInList(m_objectListeners); -} - v8::Handle<v8::Script> V8Proxy::compileScript(v8::Handle<v8::String> code, const String& fileName, int baseLine) #ifdef ANDROID_INSTRUMENT { @@ -296,10 +297,32 @@ bool V8Proxy::handleOutOfMemory() return true; } -void V8Proxy::evaluateInNewWorld(const Vector<ScriptSourceCode>& sources, int extensionGroup) +void V8Proxy::evaluateInIsolatedWorld(int worldID, const Vector<ScriptSourceCode>& sources, int extensionGroup) { initContextIfNeeded(); - V8IsolatedWorld::evaluate(sources, this, extensionGroup); + + v8::HandleScope handleScope; + V8IsolatedWorld* world = 0; + + if (worldID > 0) { + IsolatedWorldMap::iterator iter = m_isolatedWorlds.find(worldID); + if (iter != m_isolatedWorlds.end()) { + world = iter->second; + } else { + world = new V8IsolatedWorld(this, extensionGroup); + m_isolatedWorlds.set(worldID, world); + } + } else { + world = new V8IsolatedWorld(this, extensionGroup); + } + + v8::Local<v8::Context> context = v8::Local<v8::Context>::New(world->context()); + v8::Context::Scope context_scope(context); + for (size_t i = 0; i < sources.size(); ++i) + evaluate(sources[i], 0); + + if (worldID == 0) + world->destroy(); } void V8Proxy::evaluateInNewContext(const Vector<ScriptSourceCode>& sources, int extensionGroup) @@ -309,7 +332,7 @@ void V8Proxy::evaluateInNewContext(const Vector<ScriptSourceCode>& sources, int v8::HandleScope handleScope; // Set up the DOM window as the prototype of the new global object. - v8::Handle<v8::Context> windowContext = m_context; + v8::Handle<v8::Context> windowContext = context(); v8::Handle<v8::Object> windowGlobal = windowContext->Global(); v8::Handle<v8::Object> windowWrapper = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, windowGlobal); @@ -357,29 +380,31 @@ v8::Local<v8::Value> V8Proxy::evaluate(const ScriptSourceCode& source, Node* nod ASSERT(v8::Context::InContext()); LOCK_V8; - // Compile the script. - v8::Local<v8::String> code = v8ExternalString(source.source()); -#if PLATFORM(CHROMIUM) - // TODO(andreip): ChromeBridge->BrowserBridge? - ChromiumBridge::traceEventBegin("v8.compile", node, ""); -#endif - - // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at - // 1, whereas v8 starts at 0. - v8::Handle<v8::Script> script = compileScript(code, source.url(), source.startLine() - 1); -#if PLATFORM(CHROMIUM) - // TODO(andreip): ChromeBridge->BrowserBridge? - ChromiumBridge::traceEventEnd("v8.compile", node, ""); - ChromiumBridge::traceEventBegin("v8.run", node, ""); -#endif v8::Local<v8::Value> result; { - // Isolate exceptions that occur when executing the code. These - // exceptions should not interfere with javascript code we might - // evaluate from C++ when returning from here. + // Isolate exceptions that occur when compiling and executing + // the code. These exceptions should not interfere with + // javascript code we might evaluate from C++ when returning + // from here. v8::TryCatch tryCatch; tryCatch.SetVerbose(true); + // Compile the script. + v8::Local<v8::String> code = v8ExternalString(source.source()); +#if PLATFORM(CHROMIUM) + // TODO(andreip): ChromeBridge->BrowserBridge? + ChromiumBridge::traceEventBegin("v8.compile", node, ""); +#endif + + // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at + // 1, whereas v8 starts at 0. + v8::Handle<v8::Script> script = compileScript(code, source.url(), source.startLine() - 1); +#if PLATFORM(CHROMIUM) + // TODO(andreip): ChromeBridge->BrowserBridge? + ChromiumBridge::traceEventEnd("v8.compile", node, ""); + + ChromiumBridge::traceEventBegin("v8.run", node, ""); +#endif // Set inlineCode to true for <a href="javascript:doSomething()"> // and false for <script>doSomething</script>. We make a rough guess at // this based on whether the script source has a URL. @@ -431,15 +456,18 @@ v8::Local<v8::Value> V8Proxy::runScriptInternal(v8::Handle<v8::Script> script, b v8::Local<v8::Value> result; { V8ConsoleMessage::Scope scope; - m_recursion++; // See comment in V8Proxy::callFunction. m_frame->keepAlive(); + m_recursion++; result = script->Run(); m_recursion--; } + // Release the storage mutex if applicable. + releaseStorageMutex(); + if (handleOutOfMemory()) ASSERT(result.IsEmpty()); @@ -461,14 +489,21 @@ v8::Local<v8::Value> V8Proxy::callFunction(v8::Handle<v8::Function> function, v8 #ifdef ANDROID_INSTRUMENT android::TimeCounter::start(android::TimeCounter::JavaScriptExecuteTimeCounter); #endif - - // For now, we don't put any artificial limitations on the depth - // of recursion that stems from calling functions. This is in - // contrast to the script evaluations. v8::Local<v8::Value> result; { V8ConsoleMessage::Scope scope; + if (m_recursion >= kMaxRecursionDepth) { + v8::Local<v8::String> code = v8::String::New("throw new RangeError('Maximum call stack size exceeded.')"); + if (code.IsEmpty()) + return result; + v8::Local<v8::Script> script = v8::Script::Compile(code); + if (script.IsEmpty()) + return result; + script->Run(); + return result; + } + // Evaluating the JavaScript could cause the frame to be deallocated, // so we start the keep alive timer here. // Frame::keepAlive method adds the ref count of the frame and sets a @@ -476,9 +511,14 @@ v8::Local<v8::Value> V8Proxy::callFunction(v8::Handle<v8::Function> function, v8 // execution finishs before firing the timer. m_frame->keepAlive(); + m_recursion++; result = function->Call(receiver, argc, args); + m_recursion--; } + // Release the storage mutex if applicable. + releaseStorageMutex(); + if (v8::V8::IsDead()) handleFatalErrorInV8(); @@ -508,17 +548,13 @@ v8::Local<v8::Value> V8Proxy::newInstance(v8::Handle<v8::Function> constructor, return result; } -v8::Local<v8::Object> V8Proxy::createWrapperFromCache(V8ClassIndex::V8WrapperType type) +v8::Local<v8::Object> V8Proxy::createWrapperFromCacheSlowCase(V8ClassIndex::V8WrapperType type) { - int classIndex = V8ClassIndex::ToInt(type); - v8::Local<v8::Object> clone(m_wrapperBoilerplates->CloneElementAt(classIndex)); - if (!clone.IsEmpty()) - return clone; - // Not in cache. + int classIndex = V8ClassIndex::ToInt(type); initContextIfNeeded(); - v8::Context::Scope scope(m_context); - v8::Local<v8::Function> function = V8DOMWrapper::getConstructor(type, getHiddenObjectPrototype(m_context)); + v8::Context::Scope scope(context()); + v8::Local<v8::Function> function = V8DOMWrapper::getConstructor(type, getHiddenObjectPrototype(context())); v8::Local<v8::Object> instance = SafeAllocation::newInstance(function); if (!instance.IsEmpty()) { m_wrapperBoilerplates->Set(v8::Integer::New(classIndex), instance); @@ -531,9 +567,9 @@ bool V8Proxy::isContextInitialized() { // m_context, m_global, and m_wrapperBoilerplates should // all be non-empty if if m_context is non-empty. - ASSERT(m_context.IsEmpty() || !m_global.IsEmpty()); - ASSERT(m_context.IsEmpty() || !m_wrapperBoilerplates.IsEmpty()); - return !m_context.IsEmpty(); + ASSERT(context().IsEmpty() || !m_global.IsEmpty()); + ASSERT(context().IsEmpty() || !m_wrapperBoilerplates.IsEmpty()); + return !context().IsEmpty(); } DOMWindow* V8Proxy::retrieveWindow(v8::Handle<v8::Context> context) @@ -547,7 +583,14 @@ DOMWindow* V8Proxy::retrieveWindow(v8::Handle<v8::Context> context) Frame* V8Proxy::retrieveFrame(v8::Handle<v8::Context> context) { - return retrieveWindow(context)->frame(); + DOMWindow* window = retrieveWindow(context); + Frame* frame = window->frame(); + if (frame && frame->domWindow() == window) + return frame; + // We return 0 here because |context| is detached from the Frame. If we + // did return |frame| we could get in trouble because the frame could be + // navigated to another security origin. + return 0; } Frame* V8Proxy::retrieveFrameForEnteredContext() @@ -701,21 +744,20 @@ void V8Proxy::updateDocumentWrapperCache() clearDocumentWrapperCache(); return; } - m_context->Global()->ForceSet(v8::String::New("document"), documentWrapper, static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete)); + context()->Global()->ForceSet(v8::String::New("document"), documentWrapper, static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete)); } void V8Proxy::clearDocumentWrapperCache() { - ASSERT(!m_context.IsEmpty()); - m_context->Global()->ForceDelete(v8::String::New("document")); + ASSERT(!context().IsEmpty()); + context()->Global()->ForceDelete(v8::String::New("document")); } void V8Proxy::disposeContextHandles() { - if (!m_context.IsEmpty()) { + if (!context().IsEmpty()) { m_frame->loader()->client()->didDestroyScriptContextForFrame(); - m_context.Dispose(); - m_context.Clear(); + shared_context()->disposeHandle(); } if (!m_wrapperBoilerplates.IsEmpty()) { @@ -727,9 +769,40 @@ void V8Proxy::disposeContextHandles() } } +void V8Proxy::releaseStorageMutex() +{ + // If we've just left a top level script context and local storage has been + // instantiated, we must ensure that any storage locks have been freed. + // Per http://dev.w3.org/html5/spec/Overview.html#storage-mutex + if (m_recursion != 0) + return; + Page* page = m_frame->page(); + if (!page) + return; + if (page->group().hasLocalStorage()) + page->group().localStorage()->unlock(); +} + +void V8Proxy::disconnectEventListeners() +{ + m_listenerGuard->disconnectListeners(); + m_listenerGuard = V8ListenerGuard::create(); +} + +void V8Proxy::resetIsolatedWorlds() +{ + for (IsolatedWorldMap::iterator iter = m_isolatedWorlds.begin(); + iter != m_isolatedWorlds.end(); ++iter) { + iter->second->destroy(); + } + m_isolatedWorlds.clear(); +} + void V8Proxy::clearForClose() { - if (!m_context.IsEmpty()) { + resetIsolatedWorlds(); + + if (!context().IsEmpty()) { LOCK_V8; v8::HandleScope handleScope; @@ -741,13 +814,14 @@ void V8Proxy::clearForClose() void V8Proxy::clearForNavigation() { disconnectEventListeners(); + resetIsolatedWorlds(); - if (!m_context.IsEmpty()) { + if (!context().IsEmpty()) { LOCK_V8; v8::HandleScope handle; clearDocumentWrapper(); - v8::Context::Scope contextScope(m_context); + v8::Context::Scope contextScope(context()); // Clear the document wrapper cache before turning on access checks on // the old DOMWindow wrapper. This way, access to the document wrapper @@ -760,7 +834,7 @@ void V8Proxy::clearForNavigation() wrapper->TurnOnAccessCheck(); // Separate the context from its global object. - m_context->DetachGlobal(); + context()->DetachGlobal(); disposeContextHandles(); } @@ -771,7 +845,7 @@ void V8Proxy::setSecurityToken() Document* document = m_frame->document(); // Setup security origin and security token. if (!document) { - m_context->UseDefaultSecurityToken(); + context()->UseDefaultSecurityToken(); return; } @@ -791,14 +865,14 @@ void V8Proxy::setSecurityToken() // case, we use the global object as the security token to avoid // calling canAccess when a script accesses its own objects. if (token.isEmpty() || token == "null") { - m_context->UseDefaultSecurityToken(); + context()->UseDefaultSecurityToken(); return; } CString utf8Token = token.utf8(); // NOTE: V8 does identity comparison in fast path, must use a symbol // as the security token. - m_context->SetSecurityToken(v8::String::NewSymbol(utf8Token.data(), utf8Token.length())); + context()->SetSecurityToken(v8::String::NewSymbol(utf8Token.data(), utf8Token.length())); } void V8Proxy::updateDocument() @@ -816,6 +890,10 @@ void V8Proxy::updateDocument() // global object wrapper succeed. initContextIfNeeded(); + // Bail out if context initialization failed. + if (context().IsEmpty()) + return; + // We have a new document and we need to update the cache. updateDocumentWrapperCache(); @@ -930,21 +1008,26 @@ v8::Persistent<v8::Context> V8Proxy::createNewContext(v8::Handle<v8::Object> glo // Install a security handler with V8. globalTemplate->SetAccessCheckCallbacks(V8Custom::v8DOMWindowNamedSecurityCheck, V8Custom::v8DOMWindowIndexedSecurityCheck, v8::Integer::New(V8ClassIndex::DOMWINDOW)); + globalTemplate->SetInternalFieldCount(V8Custom::kDOMWindowInternalFieldCount); + + // Used to avoid sleep calls in unload handlers. + if (!registeredExtensionWithV8(DateExtension::get())) + registerExtension(DateExtension::get(), String()); // Dynamically tell v8 about our extensions now. OwnArrayPtr<const char*> extensionNames(new const char*[m_extensions.size()]); int index = 0; - for (V8ExtensionList::iterator it = m_extensions.begin(); it != m_extensions.end(); ++it) { - if (it->group && it->group != extensionGroup) + for (size_t i = 0; i < m_extensions.size(); ++i) { + if (m_extensions[i].group && m_extensions[i].group != extensionGroup) continue; // Note: we check the loader URL here instead of the document URL // because we might be currently loading an URL into a blank page. // See http://code.google.com/p/chromium/issues/detail?id=10924 - if (it->scheme.length() > 0 && (it->scheme != m_frame->loader()->activeDocumentLoader()->url().protocol() || it->scheme != m_frame->page()->mainFrame()->loader()->activeDocumentLoader()->url().protocol())) + if (m_extensions[i].scheme.length() > 0 && (m_extensions[i].scheme != m_frame->loader()->activeDocumentLoader()->url().protocol() || m_extensions[i].scheme != m_frame->page()->mainFrame()->loader()->activeDocumentLoader()->url().protocol())) continue; - extensionNames[index++] = it->extension->name(); + extensionNames[index++] = m_extensions[i].extension->name(); } v8::ExtensionConfiguration extensions(index, extensionNames.get()); result = v8::Context::New(&extensions, globalTemplate, global); @@ -967,12 +1050,14 @@ bool V8Proxy::installDOMWindow(v8::Handle<v8::Context> context, DOMWindow* windo // Wrap the window. V8DOMWrapper::setDOMWrapper(jsWindow, V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW), window); + V8DOMWrapper::setDOMWrapper(v8::Handle<v8::Object>::Cast(jsWindow->GetPrototype()), V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW), window); window->ref(); V8DOMWrapper::setJSWrapperForDOMObject(window, v8::Persistent<v8::Object>::New(jsWindow)); // Insert the window instance as the prototype of the shadow object. v8::Handle<v8::Object> v8Global = context->Global(); + V8DOMWrapper::setDOMWrapper(v8::Handle<v8::Object>::Cast(v8Global->GetPrototype()), V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW), window); v8Global->Set(implicitProtoString, jsWindow); return true; } @@ -1015,7 +1100,7 @@ bool V8Proxy::installDOMWindow(v8::Handle<v8::Context> context, DOMWindow* windo void V8Proxy::initContextIfNeeded() { // Bail out if the context has already been initialized. - if (!m_context.IsEmpty()) + if (!context().IsEmpty()) return; #ifdef ANDROID_INSTRUMENT @@ -1044,17 +1129,18 @@ void V8Proxy::initContextIfNeeded() isV8Initialized = true; } - m_context = createNewContext(m_global, 0); - if (m_context.IsEmpty()) + + v8::Persistent<v8::Context> context = createNewContext(m_global, 0); + if (context.IsEmpty()) return; + m_context->set(context); + - // Starting from now, use local context only. - v8::Local<v8::Context> v8Context = context(); - v8::Context::Scope contextScope(v8Context); + v8::Context::Scope contextScope(context); // Store the first global object created so we can reuse it. if (m_global.IsEmpty()) { - m_global = v8::Persistent<v8::Object>::New(v8Context->Global()); + m_global = v8::Persistent<v8::Object>::New(context->Global()); // Bail out if allocation of the first global objects fails. if (m_global.IsEmpty()) { disposeContextHandles(); @@ -1065,7 +1151,7 @@ void V8Proxy::initContextIfNeeded() #endif } - installHiddenObjectPrototype(m_context); + installHiddenObjectPrototype(context); m_wrapperBoilerplates = v8::Persistent<v8::Array>::New(v8::Array::New(V8ClassIndex::WRAPPER_TYPE_COUNT)); // Bail out if allocation failed. if (m_wrapperBoilerplates.IsEmpty()) { @@ -1076,7 +1162,7 @@ void V8Proxy::initContextIfNeeded() V8GCController::registerGlobalHandle(PROXY, this, m_wrapperBoilerplates); #endif - if (!installDOMWindow(v8Context, m_frame->domWindow())) + if (!installDOMWindow(context, m_frame->domWindow())) disposeContextHandles(); updateDocument(); @@ -1162,6 +1248,23 @@ v8::Local<v8::Context> V8Proxy::context(Frame* frame) return context; } +PassRefPtr<SharedPersistent<v8::Context> > V8Proxy::shared_context(Frame* frame) +{ + V8Proxy *proxy = V8Proxy::retrieve(frame); + if (!proxy) + return 0; + + proxy->initContextIfNeeded(); + RefPtr<SharedPersistent<v8::Context> > context = proxy->shared_context(); + if (V8IsolatedWorld* world = V8IsolatedWorld::getEntered()) { + context = world->shared_context(); + if (frame != V8Proxy::retrieveFrame(context->get())) + return 0; + } + + return context; +} + v8::Local<v8::Context> V8Proxy::mainWorldContext(Frame* frame) { V8Proxy* proxy = retrieve(frame); @@ -1169,7 +1272,7 @@ v8::Local<v8::Context> V8Proxy::mainWorldContext(Frame* frame) return v8::Local<v8::Context>(); proxy->initContextIfNeeded(); - return proxy->context(); + return v8::Local<v8::Context>::New(proxy->context()); } v8::Local<v8::Context> V8Proxy::currentContext() @@ -1279,14 +1382,21 @@ String V8Proxy::sourceName() #endif } -void V8Proxy::registerExtensionWithV8(v8::Extension* extension) { +void V8Proxy::registerExtensionWithV8(v8::Extension* extension) +{ // If the extension exists in our list, it was already registered with V8. - for (V8ExtensionList::iterator it = m_extensions.begin(); it != m_extensions.end(); ++it) { - if (it->extension == extension) - return; + if (!registeredExtensionWithV8(extension)) + v8::RegisterExtension(extension); +} + +bool V8Proxy::registeredExtensionWithV8(v8::Extension* extension) +{ + for (size_t i = 0; i < m_extensions.size(); ++i) { + if (m_extensions[i].extension == extension) + return true; } - v8::RegisterExtension(extension); + return false; } void V8Proxy::registerExtension(v8::Extension* extension, const String& schemeRestriction) @@ -1306,17 +1416,17 @@ void V8Proxy::registerExtension(v8::Extension* extension, int extensionGroup) bool V8Proxy::setContextDebugId(int debugId) { ASSERT(debugId > 0); - if (m_context.IsEmpty()) + if (context().IsEmpty()) return false; v8::HandleScope scope; - if (!m_context->GetData()->IsUndefined()) + if (!context()->GetData()->IsUndefined()) return false; - v8::Context::Scope contextScope(m_context); + v8::Context::Scope contextScope(context()); v8::Handle<v8::Object> contextData = v8::Object::New(); contextData->Set(v8::String::New(kContextDebugDataType), v8::String::New("page")); contextData->Set(v8::String::New(kContextDebugDataValue), v8::Integer::New(debugId)); - m_context->SetData(contextData); + context()->SetData(contextData); return true; } diff --git a/WebCore/bindings/v8/V8Proxy.h b/WebCore/bindings/v8/V8Proxy.h index d8f546c..30f682d 100644 --- a/WebCore/bindings/v8/V8Proxy.h +++ b/WebCore/bindings/v8/V8Proxy.h @@ -31,20 +31,14 @@ #ifndef V8Proxy_h #define V8Proxy_h -#include "Node.h" -#include "NodeFilter.h" -#include "PlatformString.h" // for WebCore::String #include "ScriptSourceCode.h" // for WebCore::ScriptSourceCode #include "SecurityOrigin.h" // for WebCore::SecurityOrigin -#include "V8CustomBinding.h" -#include "V8DOMMap.h" +#include "SharedPersistent.h" +#include "V8AbstractEventListener.h" #include "V8DOMWrapper.h" -#include "V8EventListenerList.h" #include "V8GCController.h" #include "V8Index.h" -#include "V8Utilities.h" #include <v8.h> -#include <wtf/Assertions.h> #include <wtf/PassRefPtr.h> // so generated bindings don't have to #include <wtf/Vector.h> @@ -57,49 +51,14 @@ namespace WebCore { - class CSSRule; - class CSSRuleList; - class CSSStyleDeclaration; - class CSSValue; - class CSSValueList; - class ClientRectList; - class DOMImplementation; class DOMWindow; - class Document; - class Element; - class Event; - class EventListener; - class EventTarget; class Frame; - class HTMLCollection; - class HTMLDocument; - class HTMLElement; - class HTMLOptionsCollection; - class MediaList; - class MimeType; - class MimeTypeArray; - class NamedNodeMap; - class Navigator; class Node; - class NodeFilter; - class NodeList; - class Plugin; - class PluginArray; class SVGElement; -#if ENABLE(SVG) - class SVGElementInstance; -#endif - class Screen; class ScriptExecutionContext; -#if ENABLE(DOM_STORAGE) - class Storage; - class StorageEvent; -#endif class String; - class StyleSheet; - class StyleSheetList; class V8EventListener; - class V8ObjectEventListener; + class V8IsolatedWorld; // FIXME: use standard logging facilities in WebCore. void logInfo(Frame*, const String& message, const String& url); @@ -145,7 +104,7 @@ namespace WebCore { int group; v8::Extension* extension; }; - typedef WTF::Vector<V8ExtensionInfo> V8ExtensionList; + typedef WTF::Vector<V8ExtensionInfo> V8Extensions; class V8Proxy { public: @@ -158,7 +117,7 @@ namespace WebCore { GeneralError }; - explicit V8Proxy(Frame* frame) : m_frame(frame), m_inlineCode(false), m_timerCallback(false), m_recursion(0) { } + explicit V8Proxy(Frame*); ~V8Proxy(); @@ -196,9 +155,6 @@ namespace WebCore { bool isEnabled(); - V8EventListenerList* eventListeners() { return &m_eventListeners; } - V8EventListenerList* objectListeners() { return &m_objectListeners; } - #if ENABLE(SVG) static void setSVGContext(void*, SVGElement*); static SVGElement* svgContext(void*); @@ -211,7 +167,7 @@ namespace WebCore { // global scope, its own prototypes for intrinsic JavaScript objects (String, // Array, and so-on), and its own wrappers for all DOM nodes and DOM // constructors. - void evaluateInNewWorld(const Vector<ScriptSourceCode>& sources, int extensionGroup); + void evaluateInIsolatedWorld(int worldId, const Vector<ScriptSourceCode>& sources, int extensionGroup); // Evaluate JavaScript in a new context. The script gets its own global scope // and its own prototypes for intrinsic JavaScript objects (String, Array, @@ -239,7 +195,12 @@ namespace WebCore { // To create JS Wrapper objects, we create a cache of a 'boiler plate' // object, and then simply Clone that object each time we need a new one. // This is faster than going through the full object creation process. - v8::Local<v8::Object> createWrapperFromCache(V8ClassIndex::V8WrapperType); + v8::Local<v8::Object> createWrapperFromCache(V8ClassIndex::V8WrapperType type) + { + int classIndex = V8ClassIndex::ToInt(type); + v8::Local<v8::Object> clone(m_wrapperBoilerplates->CloneElementAt(classIndex)); + return clone.IsEmpty() ? createWrapperFromCacheSlowCase(type) : clone; + } // Returns the window object associated with a context. static DOMWindow* retrieveWindow(v8::Handle<v8::Context>); @@ -290,6 +251,7 @@ namespace WebCore { // Returns V8 Context of a frame. If none exists, creates // a new context. It is potentially slow and consumes memory. static v8::Local<v8::Context> context(Frame*); + static PassRefPtr<SharedPersistent<v8::Context> > shared_context(Frame*); static v8::Local<v8::Context> mainWorldContext(Frame*); static v8::Local<v8::Context> currentContext(); @@ -334,10 +296,19 @@ namespace WebCore { static int sourceLineNumber(); static String sourceName(); - // Returns a local handle of the context. - v8::Local<v8::Context> context() + v8::Handle<v8::Context> context() + { + return m_context->get(); + } + + PassRefPtr<SharedPersistent<v8::Context> > shared_context() + { + return m_context; + } + + PassRefPtr<V8ListenerGuard> listenerGuard() { - return v8::Local<v8::Context>::New(m_context); + return m_listenerGuard; } bool setContextDebugId(int id); @@ -368,7 +339,6 @@ namespace WebCore { static const char* kContextDebugDataType; static const char* kContextDebugDataValue; - void disconnectEventListeners(); void setSecurityToken(); void clearDocumentWrapper(); @@ -382,6 +352,14 @@ namespace WebCore { // Dispose global handles of m_contexts and friends. void disposeContextHandles(); + // If m_recursionCount is 0, let LocalStorage know so we can release + // the storage mutex. + void releaseStorageMutex(); + + void disconnectEventListeners(); + + void resetIsolatedWorlds(); + static bool canAccessPrivate(DOMWindow*); static const char* rangeExceptionName(int exceptionCode); @@ -407,11 +385,17 @@ namespace WebCore { return v8::Local<v8::Context>::New(m_utilityContext); } + v8::Local<v8::Object> createWrapperFromCacheSlowCase(V8ClassIndex::V8WrapperType); + static void registerExtensionWithV8(v8::Extension*); + static bool registeredExtensionWithV8(v8::Extension*); Frame* m_frame; - v8::Persistent<v8::Context> m_context; + RefPtr<SharedPersistent<v8::Context> > m_context; + + RefPtr<V8ListenerGuard> m_listenerGuard; + // For each possible type of wrapper, we keep a boilerplate object. // The boilerplate is used to create additional wrappers of the same // type. We keep a single persistent handle to an array of the @@ -426,14 +410,6 @@ namespace WebCore { int m_handlerLineNumber; - // A list of event listeners created for this frame, - // the list gets cleared when removing all timeouts. - V8EventListenerList m_eventListeners; - - // A list of event listeners create for XMLHttpRequest object for this frame, - // the list gets cleared when removing all timeouts. - V8EventListenerList m_objectListeners; - // True for <a href="javascript:foo()"> and false for <script>foo()</script>. // Only valid during execution. bool m_inlineCode; @@ -447,8 +423,18 @@ namespace WebCore { // excessive recursion in the binding layer. int m_recursion; - // List of extensions registered with the context. - static V8ExtensionList m_extensions; + // All of the extensions registered with the context. + static V8Extensions m_extensions; + + // The isolated worlds we are tracking for this frame. We hold them alive + // here so that they can be used again by future calls to + // evaluateInIsolatedWorld(). + // + // Note: although the pointer is raw, the instance is kept alive by a strong + // reference to the v8 context it contains, which is not made weak until we + // call world->destroy(). + typedef HashMap<int, V8IsolatedWorld*> IsolatedWorldMap; + IsolatedWorldMap m_isolatedWorlds; }; template <int tag, typename T> diff --git a/WebCore/bindings/v8/V8Utilities.cpp b/WebCore/bindings/v8/V8Utilities.cpp index c1ac6d4..a66f435 100644 --- a/WebCore/bindings/v8/V8Utilities.cpp +++ b/WebCore/bindings/v8/V8Utilities.cpp @@ -33,8 +33,15 @@ #include <v8.h> +#include "Document.h" +#include "Frame.h" +#include "ScriptExecutionContext.h" +#include "ScriptState.h" #include "V8CustomBinding.h" +#include "V8Binding.h" #include "V8Proxy.h" +#include "WorkerContext.h" +#include "WorkerContextExecutionProxy.h" #include <wtf/Assertions.h> #include "Frame.h" @@ -43,7 +50,7 @@ namespace WebCore { // Use an array to hold dependents. It works like a ref-counted scheme. // A value can be added more than once to the DOM object. -void createHiddenDependency(v8::Local<v8::Object> object, v8::Local<v8::Value> value, int cacheIndex) +void createHiddenDependency(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int cacheIndex) { v8::Local<v8::Value> cache = object->GetInternalField(cacheIndex); if (cache->IsNull() || cache->IsUndefined()) { @@ -55,7 +62,7 @@ void createHiddenDependency(v8::Local<v8::Object> object, v8::Local<v8::Value> v cacheArray->Set(v8::Integer::New(cacheArray->Length()), value); } -void removeHiddenDependency(v8::Local<v8::Object> object, v8::Local<v8::Value> value, int cacheIndex) +void removeHiddenDependency(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int cacheIndex) { v8::Local<v8::Value> cache = object->GetInternalField(cacheIndex); if (!cache->IsArray()) @@ -98,7 +105,46 @@ void navigateIfAllowed(Frame* frame, const KURL& url, bool lockHistory, bool loc return; if (!protocolIsJavaScript(url) || ScriptController::isSafeScript(frame)) - frame->loader()->scheduleLocationChange(url.string(), callingFrame->loader()->outgoingReferrer(), lockHistory, lockBackForwardList, processingUserGesture()); + frame->redirectScheduler()->scheduleLocationChange(url.string(), callingFrame->loader()->outgoingReferrer(), lockHistory, lockBackForwardList, processingUserGesture()); +} + +ScriptExecutionContext* getScriptExecutionContext(ScriptState* scriptState) +{ +#if ENABLE(WORKERS) + WorkerContextExecutionProxy* proxy = WorkerContextExecutionProxy::retrieve(); + if (proxy) + return proxy->workerContext()->scriptExecutionContext(); +#endif + + if (scriptState) + return scriptState->frame()->document()->scriptExecutionContext(); + else { + Frame* frame = V8Proxy::retrieveFrameForCurrentContext(); + if (frame) + return frame->document()->scriptExecutionContext(); + } + + return 0; +} + +void reportException(ScriptState* scriptState, v8::TryCatch& exceptionCatcher) +{ + String errorMessage; + int lineNumber = 0; + String sourceURL; + + // There can be a situation that an exception is thrown without setting a message. + v8::Local<v8::Message> message = exceptionCatcher.Message(); + if (message.IsEmpty()) + errorMessage = toWebCoreString(exceptionCatcher.Exception()->ToString()); + else { + errorMessage = toWebCoreString(message->Get()); + lineNumber = message->GetLineNumber(); + sourceURL = toWebCoreString(message->GetScriptResourceName()); + } + + getScriptExecutionContext(scriptState)->reportException(errorMessage, lineNumber, sourceURL); + exceptionCatcher.Reset(); } } // namespace WebCore diff --git a/WebCore/bindings/v8/V8Utilities.h b/WebCore/bindings/v8/V8Utilities.h index 3e59d34..1a713c9 100644 --- a/WebCore/bindings/v8/V8Utilities.h +++ b/WebCore/bindings/v8/V8Utilities.h @@ -44,17 +44,26 @@ namespace WebCore { class Frame; class KURL; + class ScriptExecutionContext; + class ScriptState; class String; // Use an array to hold dependents. It works like a ref-counted scheme. A value can be added more than once to the DOM object. - void createHiddenDependency(v8::Local<v8::Object>, v8::Local<v8::Value>, int cacheIndex); - void removeHiddenDependency(v8::Local<v8::Object>, v8::Local<v8::Value>, int cacheIndex); + void createHiddenDependency(v8::Handle<v8::Object>, v8::Local<v8::Value>, int cacheIndex); + void removeHiddenDependency(v8::Handle<v8::Object>, v8::Local<v8::Value>, int cacheIndex); bool processingUserGesture(); bool shouldAllowNavigation(Frame*); KURL completeURL(const String& relativeURL); void navigateIfAllowed(Frame*, const KURL&, bool lockHistory, bool lockBackForwardList); + ScriptExecutionContext* getScriptExecutionContext(ScriptState*); + inline ScriptExecutionContext* getScriptExecutionContext() { + return getScriptExecutionContext(0); + } + + void reportException(ScriptState*, v8::TryCatch&); + class AllowAllocation { public: inline AllowAllocation() diff --git a/WebCore/bindings/v8/V8WorkerContextEventListener.cpp b/WebCore/bindings/v8/V8WorkerContextEventListener.cpp index 862cd2d..24e493c 100644 --- a/WebCore/bindings/v8/V8WorkerContextEventListener.cpp +++ b/WebCore/bindings/v8/V8WorkerContextEventListener.cpp @@ -41,20 +41,13 @@ namespace WebCore { -V8WorkerContextEventListener::V8WorkerContextEventListener(WorkerContextExecutionProxy* proxy, v8::Local<v8::Object> listener, bool isInline) - : V8EventListener(0, listener, isInline) +V8WorkerContextEventListener::V8WorkerContextEventListener(WorkerContextExecutionProxy* proxy, PassRefPtr<V8ListenerGuard> guard, v8::Local<v8::Object> listener, bool isInline) + : V8EventListener(0, guard, listener, isInline) , m_proxy(proxy) { } -V8WorkerContextEventListener::~V8WorkerContextEventListener() -{ - if (m_proxy) - m_proxy->removeEventListener(this); - disposeListenerObject(); -} - -void V8WorkerContextEventListener::handleEvent(Event* event, bool isWindowEvent) +void V8WorkerContextEventListener::handleEvent(ScriptExecutionContext*, Event* event) { // Is the EventListener disconnected? if (disconnected()) @@ -77,7 +70,7 @@ void V8WorkerContextEventListener::handleEvent(Event* event, bool isWindowEvent) // Get the V8 wrapper for the event object. v8::Handle<v8::Value> jsEvent = WorkerContextExecutionProxy::convertEventToV8Object(event); - invokeEventHandler(context, event, jsEvent, isWindowEvent); + invokeEventHandler(context, event, jsEvent); } bool V8WorkerContextEventListener::reportError(const String& message, const String& url, int lineNumber) @@ -98,6 +91,7 @@ bool V8WorkerContextEventListener::reportError(const String& message, const Stri // Enter the V8 context in which to perform the event handling. v8::Context::Scope scope(context); + v8::Local<v8::Object> listener = getListenerObject(); v8::Local<v8::Value> returnValue; { // Catch exceptions thrown in calling the function so they do not propagate to javascript code that caused the event to fire. @@ -105,8 +99,8 @@ bool V8WorkerContextEventListener::reportError(const String& message, const Stri tryCatch.SetVerbose(true); // Call the function. - if (!m_listener.IsEmpty() && m_listener->IsFunction()) { - v8::Local<v8::Function> callFunction = v8::Local<v8::Function>::New(v8::Persistent<v8::Function>::Cast(m_listener)); + if (!listener.IsEmpty() && listener->IsFunction()) { + v8::Local<v8::Function> callFunction = v8::Local<v8::Function>::Cast(listener); v8::Local<v8::Object> thisValue = v8::Context::GetCurrent()->Global(); v8::Handle<v8::Value> parameters[3] = { v8String(message), v8String(url), v8::Integer::New(lineNumber) }; @@ -126,10 +120,10 @@ bool V8WorkerContextEventListener::reportError(const String& message, const Stri return errorHandled; } -v8::Local<v8::Value> V8WorkerContextEventListener::callListenerFunction(v8::Handle<v8::Value> jsEvent, Event* event, bool isWindowEvent) +v8::Local<v8::Value> V8WorkerContextEventListener::callListenerFunction(v8::Handle<v8::Value> jsEvent, Event* event) { v8::Local<v8::Function> handlerFunction = getListenerFunction(); - v8::Local<v8::Object> receiver = getReceiverObject(event, isWindowEvent); + v8::Local<v8::Object> receiver = getReceiverObject(event); if (handlerFunction.IsEmpty() || receiver.IsEmpty()) return v8::Local<v8::Value>(); @@ -141,13 +135,12 @@ v8::Local<v8::Value> V8WorkerContextEventListener::callListenerFunction(v8::Hand return result; } -v8::Local<v8::Object> V8WorkerContextEventListener::getReceiverObject(Event* event, bool isWindowEvent) +v8::Local<v8::Object> V8WorkerContextEventListener::getReceiverObject(Event* event) { - if (!m_listener.IsEmpty() && !m_listener->IsFunction()) - return v8::Local<v8::Object>::New(m_listener); + v8::Local<v8::Object> listener = getListenerObject(); - if (isWindowEvent) - return v8::Context::GetCurrent()->Global(); + if (!listener.IsEmpty() && !listener->IsFunction()) + return listener; EventTarget* target = event->currentTarget(); v8::Handle<v8::Value> value = WorkerContextExecutionProxy::convertEventTargetToV8Object(target); diff --git a/WebCore/bindings/v8/V8WorkerContextEventListener.h b/WebCore/bindings/v8/V8WorkerContextEventListener.h index c901c51..3752533 100644 --- a/WebCore/bindings/v8/V8WorkerContextEventListener.h +++ b/WebCore/bindings/v8/V8WorkerContextEventListener.h @@ -44,23 +44,21 @@ namespace WebCore { class V8WorkerContextEventListener : public V8EventListener { public: - static PassRefPtr<V8WorkerContextEventListener> create(WorkerContextExecutionProxy* proxy, v8::Local<v8::Object> listener, bool isInline) + static PassRefPtr<V8WorkerContextEventListener> create(WorkerContextExecutionProxy* proxy, PassRefPtr<V8ListenerGuard> guard, v8::Local<v8::Object> listener, bool isInline) { - return adoptRef(new V8WorkerContextEventListener(proxy, listener, isInline)); + return adoptRef(new V8WorkerContextEventListener(proxy, guard, listener, isInline)); } - V8WorkerContextEventListener(WorkerContextExecutionProxy*, v8::Local<v8::Object> listener, bool isInline); - virtual ~V8WorkerContextEventListener(); - virtual void handleEvent(Event*, bool isWindowEvent); + virtual void handleEvent(ScriptExecutionContext*, Event*); virtual bool reportError(const String& message, const String& url, int lineNumber); - virtual bool disconnected() const { return !m_proxy; } WorkerContextExecutionProxy* proxy() const { return m_proxy; } - void disconnect() { m_proxy = 0; } private: - virtual v8::Local<v8::Value> callListenerFunction(v8::Handle<v8::Value> jsEvent, Event*, bool isWindowEvent); - v8::Local<v8::Object> getReceiverObject(Event*, bool isWindowEvent); + V8WorkerContextEventListener(WorkerContextExecutionProxy*, PassRefPtr<V8ListenerGuard>, v8::Local<v8::Object> listener, bool isInline); + + virtual v8::Local<v8::Value> callListenerFunction(v8::Handle<v8::Value> jsEvent, Event*); + v8::Local<v8::Object> getReceiverObject(Event*); WorkerContextExecutionProxy* m_proxy; }; diff --git a/WebCore/bindings/v8/WorkerContextExecutionProxy.cpp b/WebCore/bindings/v8/WorkerContextExecutionProxy.cpp index ba858cf..90c1f6f 100644 --- a/WebCore/bindings/v8/WorkerContextExecutionProxy.cpp +++ b/WebCore/bindings/v8/WorkerContextExecutionProxy.cpp @@ -38,6 +38,8 @@ #include "DOMCoreException.h" #include "DedicatedWorkerContext.h" #include "Event.h" +#include "Notification.h" +#include "NotificationCenter.h" #include "EventException.h" #include "MessagePort.h" #include "RangeException.h" @@ -46,7 +48,9 @@ #include "V8Index.h" #include "V8Proxy.h" #include "V8WorkerContextEventListener.h" -#include "V8WorkerContextObjectEventListener.h" +#if ENABLE(WEB_SOCKETS) +#include "WebSocket.h" +#endif #include "Worker.h" #include "WorkerContext.h" #include "WorkerLocation.h" @@ -66,6 +70,7 @@ static void reportFatalErrorInV8(const char* location, const char* message) WorkerContextExecutionProxy::WorkerContextExecutionProxy(WorkerContext* workerContext) : m_workerContext(workerContext) , m_recursion(0) + , m_listenerGuard(V8ListenerGuard::create()) { initV8IfNeeded(); } @@ -77,13 +82,7 @@ WorkerContextExecutionProxy::~WorkerContextExecutionProxy() void WorkerContextExecutionProxy::dispose() { - // Disconnect all event listeners. - if (m_listeners.get()) { - for (V8EventListenerList::iterator iterator(m_listeners->begin()); iterator != m_listeners->end(); ++iterator) - static_cast<V8WorkerContextEventListener*>(*iterator)->disconnect(); - - m_listeners->clear(); - } + m_listenerGuard->disconnectListeners(); // Detach all events from their JS wrappers. for (size_t eventIndex = 0; eventIndex < m_events.size(); ++eventIndex) { @@ -169,8 +168,6 @@ void WorkerContextExecutionProxy::initContextIfNeeded() // Insert the object instance as the prototype of the shadow object. v8::Handle<v8::Object> globalObject = m_context->Global(); globalObject->Set(implicitProtoString, jsWorkerContext); - - m_listeners.set(new V8EventListenerList()); } v8::Handle<v8::Value> WorkerContextExecutionProxy::convertToV8Object(V8ClassIndex::V8WrapperType type, void* impl) @@ -224,6 +221,14 @@ v8::Handle<v8::Value> WorkerContextExecutionProxy::convertToV8Object(V8ClassInde case V8ClassIndex::WORKERNAVIGATOR: static_cast<WorkerNavigator*>(impl)->ref(); break; +#if ENABLE(NOTIFICATIONS) + case V8ClassIndex::NOTIFICATIONCENTER: + static_cast<NotificationCenter*>(impl)->ref(); + break; + case V8ClassIndex::NOTIFICATION: + static_cast<Notification*>(impl)->ref(); + break; +#endif case V8ClassIndex::DOMCOREEXCEPTION: static_cast<DOMCoreException*>(impl)->ref(); break; @@ -398,40 +403,9 @@ v8::Local<v8::Value> WorkerContextExecutionProxy::runScript(v8::Handle<v8::Scrip return result; } -PassRefPtr<V8EventListener> WorkerContextExecutionProxy::findOrCreateEventListenerHelper(v8::Local<v8::Value> object, bool isInline, bool findOnly, bool createObjectEventListener) -{ - if (!object->IsObject()) - return 0; - - V8EventListener* listener = m_listeners->find(object->ToObject(), isInline); - if (findOnly) - return listener; - - // Create a new one, and add to cache. - RefPtr<V8EventListener> newListener; - if (createObjectEventListener) - newListener = V8WorkerContextObjectEventListener::create(this, v8::Local<v8::Object>::Cast(object), isInline); - else - newListener = V8WorkerContextEventListener::create(this, v8::Local<v8::Object>::Cast(object), isInline); - - m_listeners->add(newListener.get()); - - return newListener.release(); -} - PassRefPtr<V8EventListener> WorkerContextExecutionProxy::findOrCreateEventListener(v8::Local<v8::Value> object, bool isInline, bool findOnly) { - return findOrCreateEventListenerHelper(object, isInline, findOnly, false); -} - -PassRefPtr<V8EventListener> WorkerContextExecutionProxy::findOrCreateObjectEventListener(v8::Local<v8::Value> object, bool isInline, bool findOnly) -{ - return findOrCreateEventListenerHelper(object, isInline, findOnly, true); -} - -void WorkerContextExecutionProxy::removeEventListener(V8EventListener* listener) -{ - m_listeners->remove(listener); + return findOnly ? V8EventListenerList::findWrapper(object, isInline) : V8EventListenerList::findOrCreateWrapper<V8WorkerContextEventListener>(this, m_listenerGuard, object, isInline); } void WorkerContextExecutionProxy::trackEvent(Event* event) diff --git a/WebCore/bindings/v8/WorkerContextExecutionProxy.h b/WebCore/bindings/v8/WorkerContextExecutionProxy.h index 75024df..a08395c 100644 --- a/WebCore/bindings/v8/WorkerContextExecutionProxy.h +++ b/WebCore/bindings/v8/WorkerContextExecutionProxy.h @@ -64,12 +64,8 @@ namespace WebCore { WorkerContextExecutionProxy(WorkerContext*); ~WorkerContextExecutionProxy(); - void removeEventListener(V8EventListener*); - // Finds/creates event listener wrappers. PassRefPtr<V8EventListener> findOrCreateEventListener(v8::Local<v8::Value> listener, bool isInline, bool findOnly); - PassRefPtr<V8EventListener> findOrCreateObjectEventListener(v8::Local<v8::Value> object, bool isInline, bool findOnly); - PassRefPtr<V8EventListener> findOrCreateEventListenerHelper(v8::Local<v8::Value> object, bool isInline, bool findOnly, bool createObjectEventListener); // Track the event so that we can detach it from the JS wrapper when a worker // terminates. This is needed because we need to be able to dispose these @@ -114,8 +110,8 @@ namespace WebCore { WorkerContext* m_workerContext; v8::Persistent<v8::Context> m_context; int m_recursion; + RefPtr<V8ListenerGuard> m_listenerGuard; - OwnPtr<V8EventListenerList> m_listeners; Vector<Event*> m_events; }; diff --git a/WebCore/bindings/v8/custom/V8AbstractWorkerCustom.cpp b/WebCore/bindings/v8/custom/V8AbstractWorkerCustom.cpp index ce759eb..0240895 100644 --- a/WebCore/bindings/v8/custom/V8AbstractWorkerCustom.cpp +++ b/WebCore/bindings/v8/custom/V8AbstractWorkerCustom.cpp @@ -38,75 +38,18 @@ #include "ScriptExecutionContext.h" #include "V8Binding.h" #include "V8CustomBinding.h" -#include "V8ObjectEventListener.h" #include "V8Proxy.h" #include "V8Utilities.h" #include "WorkerContextExecutionProxy.h" namespace WebCore { -PassRefPtr<EventListener> getEventListener(AbstractWorker* worker, v8::Local<v8::Value> value, bool isAttribute, bool findOnly) -{ - if (worker->scriptExecutionContext()->isWorkerContext()) { - WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); - ASSERT(workerContextProxy); - return workerContextProxy->findOrCreateObjectEventListener(value, isAttribute, findOnly); - } - - V8Proxy* proxy = V8Proxy::retrieve(worker->scriptExecutionContext()); - if (proxy) { - V8EventListenerList* list = proxy->objectListeners(); - return findOnly ? list->findWrapper(value, isAttribute) : list->findOrCreateWrapper<V8ObjectEventListener>(proxy->frame(), value, isAttribute); - } - - return 0; -} - -ACCESSOR_GETTER(AbstractWorkerOnerror) -{ - INC_STATS(L"DOM.AbstractWorker.onerror._get"); - AbstractWorker* worker = V8DOMWrapper::convertToNativeObject<AbstractWorker>(V8ClassIndex::ABSTRACTWORKER, info.Holder()); - if (worker->onerror()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(worker->onerror()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - return v8Listener; - } - return v8::Undefined(); -} - -ACCESSOR_SETTER(AbstractWorkerOnerror) -{ - INC_STATS(L"DOM.AbstractWorker.onerror._set"); - AbstractWorker* worker = V8DOMWrapper::convertToNativeObject<AbstractWorker>(V8ClassIndex::ABSTRACTWORKER, info.Holder()); - V8ObjectEventListener* oldListener = static_cast<V8ObjectEventListener*>(worker->onerror()); - if (value->IsNull()) { - if (oldListener) { - v8::Local<v8::Object> oldV8Listener = oldListener->getListenerObject(); - removeHiddenDependency(info.Holder(), oldV8Listener, V8Custom::kAbstractWorkerRequestCacheIndex); - } - - // Clear the listener. - worker->setOnerror(0); - } else { - RefPtr<EventListener> listener = getEventListener(worker, value, true, false); - if (listener) { - if (oldListener) { - v8::Local<v8::Object> oldV8Listener = oldListener->getListenerObject(); - removeHiddenDependency(info.Holder(), oldV8Listener, V8Custom::kAbstractWorkerRequestCacheIndex); - } - - worker->setOnerror(listener); - createHiddenDependency(info.Holder(), value, V8Custom::kAbstractWorkerRequestCacheIndex); - } - } -} - CALLBACK_FUNC_DECL(AbstractWorkerAddEventListener) { INC_STATS(L"DOM.AbstractWorker.addEventListener()"); AbstractWorker* worker = V8DOMWrapper::convertToNativeObject<AbstractWorker>(V8ClassIndex::ABSTRACTWORKER, args.Holder()); - RefPtr<EventListener> listener = getEventListener(worker, args[1], false, false); + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(worker, args[1], false, ListenerFindOrCreate); if (listener) { String type = toWebCoreString(args[0]); bool useCapture = args[2]->BooleanValue(); @@ -122,7 +65,7 @@ CALLBACK_FUNC_DECL(AbstractWorkerRemoveEventListener) INC_STATS(L"DOM.AbstractWorker.removeEventListener()"); AbstractWorker* worker = V8DOMWrapper::convertToNativeObject<AbstractWorker>(V8ClassIndex::ABSTRACTWORKER, args.Holder()); - RefPtr<EventListener> listener = getEventListener(worker, args[1], false, true); + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(worker, args[1], false, ListenerFindOnly); if (listener) { String type = toWebCoreString(args[0]); bool useCapture = args[2]->BooleanValue(); diff --git a/WebCore/bindings/v8/custom/V8CanvasArrayBufferCustom.cpp b/WebCore/bindings/v8/custom/V8CanvasArrayBufferCustom.cpp new file mode 100644 index 0000000..4a85e82 --- /dev/null +++ b/WebCore/bindings/v8/custom/V8CanvasArrayBufferCustom.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "CanvasArrayBuffer.h" + +#include "V8Binding.h" +#include "V8CanvasArrayBuffer.h" +#include "V8CustomBinding.h" +#include "V8Proxy.h" + +namespace WebCore { + +CALLBACK_FUNC_DECL(CanvasArrayBufferConstructor) +{ + INC_STATS("DOM.CanvasArrayBuffer.Contructor"); + + if (!args.IsConstructCall()) + return throwError("DOM object constructor cannot be called as a function."); + + int argLen = args.Length(); + // Supported constructors: + // CanvasArrayBuffer(n) where n is an integer: + // -- create an empty buffer of n bytes + + if (argLen != 1) + return throwError("Wrong number of arguments specified to constructor (requires 1)"); + + int len = 0; + if (!args[0]->IsInt32()) + return throwError("Argument to CanvasArrayBuffer constructor was not an integer"); + len = toInt32(args[0]); + RefPtr<CanvasArrayBuffer> buffer = CanvasArrayBuffer::create(len); + // Transform the holder into a wrapper object for the array. + V8DOMWrapper::setDOMWrapper(args.Holder(), V8ClassIndex::ToInt(V8ClassIndex::CANVASARRAYBUFFER), buffer.get()); + return toV8(buffer.release(), args.Holder()); +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/v8/custom/V8CanvasArrayCustom.h b/WebCore/bindings/v8/custom/V8CanvasArrayCustom.h new file mode 100644 index 0000000..311b838 --- /dev/null +++ b/WebCore/bindings/v8/custom/V8CanvasArrayCustom.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "CanvasArrayBuffer.h" + +#include "V8Binding.h" +#include "V8CanvasArrayBuffer.h" +#include "V8CustomBinding.h" +#include "V8Proxy.h" + +namespace WebCore { + + // Template function used by the CanvasArray*Constructor callbacks. + template<class ArrayClass> + v8::Handle<v8::Value> constructCanvasArray(const v8::Arguments& args, + int classIndex) + { + if (!args.IsConstructCall()) + return throwError("DOM object constructor cannot be called as a function."); + + int argLen = args.Length(); + // Supported constructors: + // Canvas<T>Array(n) where n is an integer: + // -- create an empty array of n elements + // Canvas<T>Array(arr) where arr is an array: + // -- create a Canvas<T>Array containing the contents of "arr" + // Canvas<T>Array(buf, offset, length) + // -- create a Canvas<T>Array pointing to the CanvasArrayBuffer + // "buf", starting at the specified offset, for the given + // length + + if (argLen == 0) + return throwError("No arguments specified to constructor"); + + // See whether the first argument is a CanvasArrayBuffer. + if (V8CanvasArrayBuffer::HasInstance(args[0])) { + if (argLen > 3) + return throwError("Wrong number of arguments to new Canvas<T>Array(CanvasArrayBuffer, int, int)"); + + CanvasArrayBuffer* buf = + V8DOMWrapper::convertToNativeObject<CanvasArrayBuffer>(V8ClassIndex::CANVASARRAYBUFFER, + args[0]->ToObject()); + if (buf == NULL) + return throwError("Could not convert argument 0 to a CanvasArrayBuffer"); + bool ok; + int offset = 0; + if (argLen > 1) { + offset = toInt32(args[1], ok); + if (!ok) + return throwError("Could not convert argument 1 to an integer"); + } + int length = buf->byteLength() - offset; + if (argLen > 2) { + length = toInt32(args[2], ok); + if (!ok) + return throwError("Could not convert argument 2 to an integer"); + } + if (length < 0) + return throwError("Length / offset out of range"); + + RefPtr<ArrayClass> array = ArrayClass::create(buf, offset, length); + if (array == NULL) + return throwError("Invalid arguments to new Canvas<T>Array(CanvasArrayBuffer, int, int)"); + // Transform the holder into a wrapper object for the array. + V8DOMWrapper::setDOMWrapper(args.Holder(), classIndex, array.get()); + return toV8(array.release(), args.Holder()); + } + + int len = 0; + v8::Handle<v8::Array> srcArray; + if (argLen != 1) + return throwError("Wrong number of arguments to new Canvas<T>Array(int / array)"); + + if (args[0]->IsInt32()) { + len = toInt32(args[0]); + } else if (args[0]->IsArray()) { + srcArray = v8::Local<v8::Array>::Cast(args[0]); + if (srcArray.IsEmpty()) + return throwError("Could not convert argument 0 to an array"); + len = srcArray->Length(); + } else + return throwError("Could not convert argument 0 to either an int32 or an array"); + + RefPtr<ArrayClass> array = ArrayClass::create(len); + if (!srcArray.IsEmpty()) { + // Need to copy the incoming array into the newly created CanvasArray. + for (int i = 0; i < len; i++) { + v8::Local<v8::Value> val = srcArray->Get(v8::Integer::New(i)); + if (!val->IsNumber()) { + char buf[256]; + sprintf(buf, "Could not convert array element %d to a number", i); + return throwError(buf); + } + array->set(i, val->NumberValue()); + } + } + + // Transform the holder into a wrapper object for the array. + V8DOMWrapper::setDOMWrapper(args.Holder(), classIndex, array.get()); + return toV8(array.release(), args.Holder()); + } + +} + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/v8/custom/V8CanvasByteArrayCustom.cpp b/WebCore/bindings/v8/custom/V8CanvasByteArrayCustom.cpp new file mode 100644 index 0000000..503e5e8 --- /dev/null +++ b/WebCore/bindings/v8/custom/V8CanvasByteArrayCustom.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "CanvasArrayBuffer.h" +#include "CanvasByteArray.h" + +#include "V8Binding.h" +#include "V8CanvasArrayBuffer.h" +#include "V8CanvasArrayCustom.h" +#include "V8CustomBinding.h" +#include "V8Proxy.h" + +namespace WebCore { + +CALLBACK_FUNC_DECL(CanvasByteArrayConstructor) +{ + INC_STATS("DOM.CanvasByteArray.Contructor"); + + return constructCanvasArray<CanvasByteArray>(args, V8ClassIndex::ToInt(V8ClassIndex::CANVASBYTEARRAY)); +} + +// Get the specified value from the byte buffer and return it wrapped as a JavaScript Number object to V8. Accesses outside the valid byte buffer range return "undefined". +INDEXED_PROPERTY_GETTER(CanvasByteArray) +{ + INC_STATS("DOM.CanvasByteArray.IndexedPropertyGetter"); + CanvasByteArray* byteBuffer = V8DOMWrapper::convertToNativeObject<CanvasByteArray>(V8ClassIndex::CANVASBYTEARRAY, info.Holder()); + + if ((index < 0) || (index >= byteBuffer->length())) + return v8::Undefined(); + signed char result; + if (!byteBuffer->get(index, result)) + return v8::Undefined(); + return v8::Number::New(result); +} + +// Set the specified value in the byte buffer. Accesses outside the valid byte buffer range are silently ignored. +INDEXED_PROPERTY_SETTER(CanvasByteArray) +{ + INC_STATS("DOM.CanvasByteArray.IndexedPropertySetter"); + CanvasByteArray* array = V8DOMWrapper::convertToNativeObject<CanvasByteArray>(V8ClassIndex::CANVASBYTEARRAY, info.Holder()); + + if ((index >= 0) && (index < array->length())) { + if (!value->IsNumber()) + return throwError("Could not convert value argument to a number"); + array->set(index, value->NumberValue()); + } + return value; +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/v8/custom/V8CanvasFloatArrayCustom.cpp b/WebCore/bindings/v8/custom/V8CanvasFloatArrayCustom.cpp new file mode 100644 index 0000000..b3c1d62 --- /dev/null +++ b/WebCore/bindings/v8/custom/V8CanvasFloatArrayCustom.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "CanvasArrayBuffer.h" +#include "CanvasFloatArray.h" + +#include "V8Binding.h" +#include "V8CanvasArrayBuffer.h" +#include "V8CanvasArrayCustom.h" +#include "V8CustomBinding.h" +#include "V8Proxy.h" + +namespace WebCore { + +CALLBACK_FUNC_DECL(CanvasFloatArrayConstructor) +{ + INC_STATS("DOM.CanvasFloatArray.Contructor"); + + return constructCanvasArray<CanvasFloatArray>(args, V8ClassIndex::ToInt(V8ClassIndex::CANVASFLOATARRAY)); +} + +// Get the specified value from the array and return it wrapped as a JavaScript Number object to V8. Accesses outside the valid array range return "undefined". +INDEXED_PROPERTY_GETTER(CanvasFloatArray) +{ + INC_STATS("DOM.CanvasFloatArray.IndexedPropertyGetter"); + CanvasFloatArray* array = V8DOMWrapper::convertToNativeObject<CanvasFloatArray>(V8ClassIndex::CANVASFLOATARRAY, info.Holder()); + + if ((index < 0) || (index >= array->length())) + return v8::Undefined(); + float result; + if (!array->get(index, result)) + return v8::Undefined(); + return v8::Number::New(result); +} + +// Set the specified value in the array. Accesses outside the valid array range are silently ignored. +INDEXED_PROPERTY_SETTER(CanvasFloatArray) +{ + INC_STATS("DOM.CanvasFloatArray.IndexedPropertySetter"); + CanvasFloatArray* array = V8DOMWrapper::convertToNativeObject<CanvasFloatArray>(V8ClassIndex::CANVASFLOATARRAY, info.Holder()); + + if ((index >= 0) && (index < array->length())) + array->set(index, value->NumberValue()); + return value; +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/v8/custom/V8CanvasIntArrayCustom.cpp b/WebCore/bindings/v8/custom/V8CanvasIntArrayCustom.cpp new file mode 100644 index 0000000..6f35db8 --- /dev/null +++ b/WebCore/bindings/v8/custom/V8CanvasIntArrayCustom.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "CanvasArrayBuffer.h" +#include "CanvasIntArray.h" + +#include "V8Binding.h" +#include "V8CanvasArrayBuffer.h" +#include "V8CanvasArrayCustom.h" +#include "V8CustomBinding.h" +#include "V8Proxy.h" + +namespace WebCore { + +CALLBACK_FUNC_DECL(CanvasIntArrayConstructor) +{ + INC_STATS("DOM.CanvasIntArray.Contructor"); + + return constructCanvasArray<CanvasIntArray>(args, V8ClassIndex::ToInt(V8ClassIndex::CANVASINTARRAY)); +} + +// Get the specified value from the integer array and return it wrapped as a JavaScript Number object to V8. Accesses outside the valid pixel buffer range return "undefined". +INDEXED_PROPERTY_GETTER(CanvasIntArray) +{ + INC_STATS("DOM.CanvasIntArray.IndexedPropertyGetter"); + CanvasIntArray* array = V8DOMWrapper::convertToNativeObject<CanvasIntArray>(V8ClassIndex::CANVASINTARRAY, info.Holder()); + + if ((index < 0) || (index >= array->length())) + return v8::Undefined(); + int result; + if (!array->get(index, result)) + return v8::Undefined(); + return v8::Number::New(result); +} + +// Set the specified value in the integer array. Accesses outside the valid integer array range are silently ignored. +INDEXED_PROPERTY_SETTER(CanvasIntArray) +{ + INC_STATS("DOM.CanvasIntArray.IndexedPropertySetter"); + CanvasIntArray* array = V8DOMWrapper::convertToNativeObject<CanvasIntArray>(V8ClassIndex::CANVASINTARRAY, info.Holder()); + + if ((index >= 0) && (index < array->length())) { + if (!value->IsNumber()) + return throwError("Could not convert value argument to a number"); + array->set(index, value->NumberValue()); + } + return value; +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/v8/custom/V8CanvasRenderingContext3DCustom.cpp b/WebCore/bindings/v8/custom/V8CanvasRenderingContext3DCustom.cpp new file mode 100644 index 0000000..c109bb8 --- /dev/null +++ b/WebCore/bindings/v8/custom/V8CanvasRenderingContext3DCustom.cpp @@ -0,0 +1,597 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "CanvasRenderingContext3D.h" + +#include "ExceptionCode.h" + +#include "NotImplemented.h" + +#include <wtf/FastMalloc.h> + +#include "V8Binding.h" +#include "V8CanvasArray.h" +#include "V8CanvasByteArray.h" +#include "V8CanvasFloatArray.h" +#include "V8CanvasIntArray.h" +#include "V8CanvasShortArray.h" +#include "V8CanvasUnsignedByteArray.h" +#include "V8CanvasUnsignedIntArray.h" +#include "V8CanvasUnsignedShortArray.h" +#include "V8HTMLImageElement.h" +#include "V8Proxy.h" + +namespace WebCore { + +// Allocates new storage via tryFastMalloc. +// Returns NULL if array failed to convert for any reason. +static float* jsArrayToFloatArray(v8::Handle<v8::Array> array, uint32_t len) +{ + // Convert the data element-by-element. + float* data; + if (!tryFastMalloc(len * sizeof(float)).getValue(data)) + return 0; + for (uint32_t i = 0; i < len; i++) { + v8::Local<v8::Value> val = array->Get(v8::Integer::New(i)); + if (!val->IsNumber()) { + fastFree(data); + return 0; + } + data[i] = toFloat(val); + } + return data; +} + +// Allocates new storage via tryFastMalloc. +// Returns NULL if array failed to convert for any reason. +static int* jsArrayToIntArray(v8::Handle<v8::Array> array, uint32_t len) +{ + // Convert the data element-by-element. + int* data; + if (!tryFastMalloc(len * sizeof(int)).getValue(data)) + return 0; + for (uint32_t i = 0; i < len; i++) { + v8::Local<v8::Value> val = array->Get(v8::Integer::New(i)); + bool ok; + int ival = toInt32(val, ok); + if (!ok) { + fastFree(data); + return 0; + } + data[i] = ival; + } + return data; +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DBufferData) +{ + INC_STATS("DOM.CanvasRenderingContext3D.bufferData()"); + + // Forms: + // * bufferData(GLenum target, CanvasArray data, GLenum usage); + // - Sets the buffer's data from the given CanvasArray + // * bufferData(GLenum target, GLsizeiptr size, GLenum usage); + // - Sets the size of the buffer to the given size in bytes + if (args.Length() != 3) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + + CanvasRenderingContext3D* context = + V8DOMWrapper::convertDOMWrapperToNative<CanvasRenderingContext3D>(args.Holder()); + bool ok; + int target = toInt32(args[0], ok); + if (!ok) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + int usage = toInt32(args[2], ok); + if (!ok) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + if (args[1]->IsInt32()) { + int size = toInt32(args[1]); + context->bufferData(target, size, usage); + } else if (V8CanvasArray::HasInstance(args[1])) { + CanvasArray* array = V8DOMWrapper::convertToNativeObject<CanvasArray>(V8ClassIndex::CANVASARRAY, args[1]->ToObject()); + context->bufferData(target, array, usage); + } else { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DBufferSubData) +{ + INC_STATS("DOM.CanvasRenderingContext3D.bufferSubData()"); + + // Forms: + // * bufferSubData(GLenum target, GLintptr offset, CanvasArray data); + if (args.Length() != 3) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + + CanvasRenderingContext3D* context = + V8DOMWrapper::convertDOMWrapperToNative<CanvasRenderingContext3D>(args.Holder()); + bool ok; + int target = toInt32(args[0], ok); + if (!ok) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + int offset = toInt32(args[1], ok); + if (!ok) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + if (!V8CanvasArray::HasInstance(args[2])) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + CanvasArray* array = V8DOMWrapper::convertToNativeObject<CanvasArray>(V8ClassIndex::CANVASARRAY, args[2]->ToObject()); + context->bufferSubData(target, offset, array); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DTexImage2D) +{ + INC_STATS("DOM.CanvasRenderingContext3D.texImage2D()"); + + // Currently supported forms: + // * void texImage2D(in GLenum target, in GLint level, + // in GLint internalformat, + // in GLsizei width, in GLsizei height, in GLint border, + // in GLenum format, in GLenum type, in CanvasArray pixels); + // * void texImage2D(in GLenum target, in GLint level, in HTMLImageElement image, + // [Optional] in GLboolean flipY, [Optional] in GLboolean premultiplyAlpha); + if (args.Length() != 3 && + args.Length() != 4 && + args.Length() != 5 && + args.Length() != 9) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + + CanvasRenderingContext3D* context = + V8DOMWrapper::convertDOMWrapperToNative<CanvasRenderingContext3D>(args.Holder()); + bool ok; + int target = toInt32(args[0], ok); + if (!ok) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + int level = toInt32(args[1], ok); + if (!ok) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + + ExceptionCode ec = 0; + if (args.Length() == 3 || + args.Length() == 4 || + args.Length() == 5) { + v8::Handle<v8::Value> arg = args[2]; + if (V8HTMLImageElement::HasInstance(arg)) { + HTMLImageElement* image_element = V8DOMWrapper::convertDOMWrapperToNode<HTMLImageElement>(v8::Handle<v8::Object>::Cast(arg)); + bool flipY = false; + bool premultiplyAlpha = false; + if (args.Length() >= 4) + flipY = args[3]->BooleanValue(); + if (args.Length() >= 5) + premultiplyAlpha = args[4]->BooleanValue(); + context->texImage2D(target, level, image_element, flipY, premultiplyAlpha, ec); + } else { + // FIXME: consider different / better exception type. + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + // Fall through + } else if (args.Length() == 9) { + int internalformat = toInt32(args[2], ok); + if (!ok) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + int width = toInt32(args[3], ok); + if (!ok) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + int height = toInt32(args[4], ok); + if (!ok) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + int border = toInt32(args[5], ok); + if (!ok) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + int format = toInt32(args[6], ok); + if (!ok) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + int type = toInt32(args[7], ok); + if (!ok) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + v8::Handle<v8::Value> arg = args[8]; + if (V8CanvasArray::HasInstance(arg)) { + CanvasArray* array = V8DOMWrapper::convertToNativeObject<CanvasArray>(V8ClassIndex::CANVASARRAY, arg->ToObject()); + // FIXME: must do validation similar to JOGL's to ensure that + // the incoming array is of the appropriate length and type + context->texImage2D(target, + level, + internalformat, + width, + height, + border, + format, + type, + array, + ec); + // Fall through + } else { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + } else { + ASSERT_NOT_REACHED(); + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + if (ec) { + V8Proxy::setDOMException(ec); + return v8::Handle<v8::Value>(); + } + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DTexSubImage2D) +{ + INC_STATS("DOM.CanvasRenderingContext3D.texSubImage2D()"); + + // FIXME: implement + notImplemented(); + + return v8::Undefined(); +} + +enum FunctionToCall { + kUniform1v, kUniform2v, kUniform3v, kUniform4v, + kVertexAttrib1v, kVertexAttrib2v, kVertexAttrib3v, kVertexAttrib4v +}; + +static v8::Handle<v8::Value> vertexAttribAndUniformHelperf(const v8::Arguments& args, + FunctionToCall functionToCall) { + // Forms: + // * glUniform1fv(GLint location, Array data); + // * glUniform1fv(GLint location, CanvasFloatArray data); + // * glUniform2fv(GLint location, Array data); + // * glUniform2fv(GLint location, CanvasFloatArray data); + // * glUniform3fv(GLint location, Array data); + // * glUniform3fv(GLint location, CanvasFloatArray data); + // * glUniform4fv(GLint location, Array data); + // * glUniform4fv(GLint location, CanvasFloatArray data); + // * glVertexAttrib1fv(GLint location, Array data); + // * glVertexAttrib1fv(GLint location, CanvasFloatArray data); + // * glVertexAttrib2fv(GLint location, Array data); + // * glVertexAttrib2fv(GLint location, CanvasFloatArray data); + // * glVertexAttrib3fv(GLint location, Array data); + // * glVertexAttrib3fv(GLint location, CanvasFloatArray data); + // * glVertexAttrib4fv(GLint location, Array data); + // * glVertexAttrib4fv(GLint location, CanvasFloatArray data); + + if (args.Length() != 3) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + + CanvasRenderingContext3D* context = + V8DOMWrapper::convertDOMWrapperToNative<CanvasRenderingContext3D>(args.Holder()); + bool ok; + int location = toInt32(args[0], ok); + if (!ok) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + if (V8CanvasFloatArray::HasInstance(args[1])) { + CanvasFloatArray* array = + V8DOMWrapper::convertToNativeObject<CanvasFloatArray>(V8ClassIndex::CANVASFLOATARRAY, args[1]->ToObject()); + ASSERT(array != NULL); + switch (functionToCall) { + case kUniform1v: context->uniform1fv(location, array); break; + case kUniform2v: context->uniform2fv(location, array); break; + case kUniform3v: context->uniform3fv(location, array); break; + case kUniform4v: context->uniform4fv(location, array); break; + case kVertexAttrib1v: context->vertexAttrib1fv(location, array); break; + case kVertexAttrib2v: context->vertexAttrib2fv(location, array); break; + case kVertexAttrib3v: context->vertexAttrib3fv(location, array); break; + case kVertexAttrib4v: context->vertexAttrib4fv(location, array); break; + default: ASSERT_NOT_REACHED(); break; + } + return v8::Undefined(); + } + + v8::Handle<v8::Array> array = + v8::Local<v8::Array>::Cast(args[1]); + if (array.IsEmpty()) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + uint32_t len = array->Length(); + float* data = jsArrayToFloatArray(array, len); + if (!data) { + // FIXME: consider different / better exception type. + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + switch (functionToCall) { + case kUniform1v: context->uniform1fv(location, data, len); break; + case kUniform2v: context->uniform2fv(location, data, len); break; + case kUniform3v: context->uniform3fv(location, data, len); break; + case kUniform4v: context->uniform4fv(location, data, len); break; + case kVertexAttrib1v: context->vertexAttrib1fv(location, data, len); break; + case kVertexAttrib2v: context->vertexAttrib2fv(location, data, len); break; + case kVertexAttrib3v: context->vertexAttrib3fv(location, data, len); break; + case kVertexAttrib4v: context->vertexAttrib4fv(location, data, len); break; + default: ASSERT_NOT_REACHED(); break; + } + fastFree(data); + return v8::Undefined(); +} + +static v8::Handle<v8::Value> uniformHelperi(const v8::Arguments& args, + FunctionToCall functionToCall) { + // Forms: + // * glUniform1iv(GLint location, Array data); + // * glUniform1iv(GLint location, CanvasIntArray data); + // * glUniform2iv(GLint location, Array data); + // * glUniform2iv(GLint location, CanvasIntArray data); + // * glUniform3iv(GLint location, Array data); + // * glUniform3iv(GLint location, CanvasIntArray data); + // * glUniform4iv(GLint location, Array data); + // * glUniform4iv(GLint location, CanvasIntArray data); + + if (args.Length() != 3) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + + CanvasRenderingContext3D* context = + V8DOMWrapper::convertDOMWrapperToNative<CanvasRenderingContext3D>(args.Holder()); + bool ok; + int location = toInt32(args[0], ok); + if (!ok) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + if (V8CanvasIntArray::HasInstance(args[1])) { + CanvasIntArray* array = + V8DOMWrapper::convertToNativeObject<CanvasIntArray>(V8ClassIndex::CANVASINTARRAY, args[1]->ToObject()); + ASSERT(array != NULL); + switch (functionToCall) { + case kUniform1v: context->uniform1iv(location, array); break; + case kUniform2v: context->uniform2iv(location, array); break; + case kUniform3v: context->uniform3iv(location, array); break; + case kUniform4v: context->uniform4iv(location, array); break; + default: ASSERT_NOT_REACHED(); break; + } + return v8::Undefined(); + } + + v8::Handle<v8::Array> array = + v8::Local<v8::Array>::Cast(args[1]); + if (array.IsEmpty()) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + uint32_t len = array->Length(); + int* data = jsArrayToIntArray(array, len); + if (!data) { + // FIXME: consider different / better exception type. + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + switch (functionToCall) { + case kUniform1v: context->uniform1iv(location, data, len); break; + case kUniform2v: context->uniform2iv(location, data, len); break; + case kUniform3v: context->uniform3iv(location, data, len); break; + case kUniform4v: context->uniform4iv(location, data, len); break; + default: ASSERT_NOT_REACHED(); break; + } + fastFree(data); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DUniform1fv) +{ + INC_STATS("DOM.CanvasRenderingContext3D.uniform1fv()"); + return vertexAttribAndUniformHelperf(args, kUniform1v); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DUniform1iv) +{ + INC_STATS("DOM.CanvasRenderingContext3D.uniform1iv()"); + return uniformHelperi(args, kUniform1v); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DUniform2fv) +{ + INC_STATS("DOM.CanvasRenderingContext3D.uniform2fv()"); + return vertexAttribAndUniformHelperf(args, kUniform2v); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DUniform2iv) +{ + INC_STATS("DOM.CanvasRenderingContext3D.uniform2iv()"); + return uniformHelperi(args, kUniform2v); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DUniform3fv) +{ + INC_STATS("DOM.CanvasRenderingContext3D.uniform3fv()"); + return vertexAttribAndUniformHelperf(args, kUniform3v); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DUniform3iv) +{ + INC_STATS("DOM.CanvasRenderingContext3D.uniform3iv()"); + return uniformHelperi(args, kUniform3v); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DUniform4fv) +{ + INC_STATS("DOM.CanvasRenderingContext3D.uniform4fv()"); + return vertexAttribAndUniformHelperf(args, kUniform4v); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DUniform4iv) +{ + INC_STATS("DOM.CanvasRenderingContext3D.uniform4iv()"); + return uniformHelperi(args, kUniform4v); +} + +static v8::Handle<v8::Value> uniformMatrixHelper(const v8::Arguments& args, + int matrixSize) +{ + // Forms: + // * glUniformMatrix2fv(GLint location, GLboolean transpose, Array data); + // * glUniformMatrix2fv(GLint location, GLboolean transpose, CanvasFloatArray data); + // * glUniformMatrix3fv(GLint location, GLboolean transpose, Array data); + // * glUniformMatrix3fv(GLint location, GLboolean transpose, CanvasFloatArray data); + // * glUniformMatrix4fv(GLint location, GLboolean transpose, Array data); + // * glUniformMatrix4fv(GLint location, GLboolean transpose, CanvasFloatArray data); + // + // FIXME: need to change to accept CanvasFloatArray as well. + if (args.Length() != 3) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + + CanvasRenderingContext3D* context = + V8DOMWrapper::convertDOMWrapperToNative<CanvasRenderingContext3D>(args.Holder()); + bool ok; + int location = toInt32(args[0], ok); + if (!ok) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + bool transpose = args[1]->BooleanValue(); + if (V8CanvasFloatArray::HasInstance(args[2])) { + CanvasFloatArray* array = + V8DOMWrapper::convertToNativeObject<CanvasFloatArray>(V8ClassIndex::CANVASFLOATARRAY, args[2]->ToObject()); + ASSERT(array != NULL); + switch (matrixSize) { + case 2: context->uniformMatrix2fv(location, transpose, array); break; + case 3: context->uniformMatrix3fv(location, transpose, array); break; + case 4: context->uniformMatrix4fv(location, transpose, array); break; + default: ASSERT_NOT_REACHED(); break; + } + return v8::Undefined(); + } + + v8::Handle<v8::Array> array = + v8::Local<v8::Array>::Cast(args[2]); + if (array.IsEmpty()) { + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + uint32_t len = array->Length(); + float* data = jsArrayToFloatArray(array, len); + if (!data) { + // FIXME: consider different / better exception type. + V8Proxy::setDOMException(SYNTAX_ERR); + return notHandledByInterceptor(); + } + switch (matrixSize) { + case 2: context->uniformMatrix2fv(location, transpose, data, len); break; + case 3: context->uniformMatrix3fv(location, transpose, data, len); break; + case 4: context->uniformMatrix4fv(location, transpose, data, len); break; + default: ASSERT_NOT_REACHED(); break; + } + fastFree(data); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DUniformMatrix2fv) +{ + INC_STATS("DOM.CanvasRenderingContext3D.uniformMatrix2fv()"); + return uniformMatrixHelper(args, 2); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DUniformMatrix3fv) +{ + INC_STATS("DOM.CanvasRenderingContext3D.uniformMatrix3fv()"); + return uniformMatrixHelper(args, 3); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DUniformMatrix4fv) +{ + INC_STATS("DOM.CanvasRenderingContext3D.uniformMatrix4fv()"); + return uniformMatrixHelper(args, 4); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DVertexAttrib1fv) +{ + INC_STATS("DOM.CanvasRenderingContext3D.vertexAttrib1fv()"); + return vertexAttribAndUniformHelperf(args, kVertexAttrib1v); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DVertexAttrib2fv) +{ + INC_STATS("DOM.CanvasRenderingContext3D.vertexAttrib2fv()"); + return vertexAttribAndUniformHelperf(args, kVertexAttrib2v); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DVertexAttrib3fv) +{ + INC_STATS("DOM.CanvasRenderingContext3D.vertexAttrib3fv()"); + return vertexAttribAndUniformHelperf(args, kVertexAttrib3v); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext3DVertexAttrib4fv) +{ + INC_STATS("DOM.CanvasRenderingContext3D.vertexAttrib4fv()"); + return vertexAttribAndUniformHelperf(args, kVertexAttrib4v); +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/v8/custom/V8CanvasShortArrayCustom.cpp b/WebCore/bindings/v8/custom/V8CanvasShortArrayCustom.cpp new file mode 100644 index 0000000..8b83022 --- /dev/null +++ b/WebCore/bindings/v8/custom/V8CanvasShortArrayCustom.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "CanvasArrayBuffer.h" +#include "CanvasShortArray.h" + +#include "V8Binding.h" +#include "V8CanvasArrayBuffer.h" +#include "V8CanvasArrayCustom.h" +#include "V8CustomBinding.h" +#include "V8Proxy.h" + +namespace WebCore { + +CALLBACK_FUNC_DECL(CanvasShortArrayConstructor) +{ + INC_STATS("DOM.CanvasShortArray.Contructor"); + + return constructCanvasArray<CanvasShortArray>(args, V8ClassIndex::ToInt(V8ClassIndex::CANVASSHORTARRAY)); +} + +// Get the specified value from the array and return it wrapped as a JavaScript Number object to V8. Accesses outside the valid array range return "undefined". +INDEXED_PROPERTY_GETTER(CanvasShortArray) +{ + INC_STATS("DOM.CanvasShortArray.IndexedPropertyGetter"); + CanvasShortArray* array = V8DOMWrapper::convertToNativeObject<CanvasShortArray>(V8ClassIndex::CANVASSHORTARRAY, info.Holder()); + + if ((index < 0) || (index >= array->length())) + return v8::Undefined(); + short result; + if (!array->get(index, result)) + return v8::Undefined(); + return v8::Number::New(result); +} + +// Set the specified value in the array. Accesses outside the valid array range are silently ignored. +INDEXED_PROPERTY_SETTER(CanvasShortArray) +{ + INC_STATS("DOM.CanvasShortArray.IndexedPropertySetter"); + CanvasShortArray* array = V8DOMWrapper::convertToNativeObject<CanvasShortArray>(V8ClassIndex::CANVASSHORTARRAY, info.Holder()); + + if ((index >= 0) && (index < array->length())) { + if (!value->IsNumber()) + return throwError("Could not convert value argument to a number"); + array->set(index, value->NumberValue()); + } + return value; +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/v8/custom/V8CanvasUnsignedByteArrayCustom.cpp b/WebCore/bindings/v8/custom/V8CanvasUnsignedByteArrayCustom.cpp new file mode 100644 index 0000000..62ab880 --- /dev/null +++ b/WebCore/bindings/v8/custom/V8CanvasUnsignedByteArrayCustom.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "CanvasArrayBuffer.h" +#include "CanvasUnsignedByteArray.h" + +#include "V8Binding.h" +#include "V8CanvasArrayBuffer.h" +#include "V8CanvasArrayCustom.h" +#include "V8CustomBinding.h" +#include "V8Proxy.h" + +namespace WebCore { + +CALLBACK_FUNC_DECL(CanvasUnsignedByteArrayConstructor) +{ + INC_STATS("DOM.CanvasUnsignedByteArray.Contructor"); + + return constructCanvasArray<CanvasUnsignedByteArray>(args, V8ClassIndex::ToInt(V8ClassIndex::CANVASUNSIGNEDBYTEARRAY)); +} + +// Get the specified value from the array and return it wrapped as a JavaScript Number object to V8. Accesses outside the valid array range return "undefined". +INDEXED_PROPERTY_GETTER(CanvasUnsignedByteArray) +{ + INC_STATS("DOM.CanvasUnsignedByteArray.IndexedPropertyGetter"); + CanvasUnsignedByteArray* array = V8DOMWrapper::convertToNativeObject<CanvasUnsignedByteArray>(V8ClassIndex::CANVASUNSIGNEDBYTEARRAY, info.Holder()); + + if ((index < 0) || (index >= array->length())) + return v8::Undefined(); + unsigned char result; + if (!array->get(index, result)) + return v8::Undefined(); + return v8::Number::New(result); +} + +// Set the specified value in the array. Accesses outside the valid array range are silently ignored. +INDEXED_PROPERTY_SETTER(CanvasUnsignedByteArray) +{ + INC_STATS("DOM.CanvasUnsignedByteArray.IndexedPropertySetter"); + CanvasUnsignedByteArray* array = V8DOMWrapper::convertToNativeObject<CanvasUnsignedByteArray>(V8ClassIndex::CANVASUNSIGNEDBYTEARRAY, info.Holder()); + + if ((index >= 0) && (index < array->length())) { + if (!value->IsNumber()) + return throwError("Could not convert value argument to a number"); + array->set(index, value->NumberValue()); + } + return value; +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/v8/custom/V8CanvasUnsignedIntArrayCustom.cpp b/WebCore/bindings/v8/custom/V8CanvasUnsignedIntArrayCustom.cpp new file mode 100644 index 0000000..94ec7d0 --- /dev/null +++ b/WebCore/bindings/v8/custom/V8CanvasUnsignedIntArrayCustom.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "CanvasArrayBuffer.h" +#include "CanvasUnsignedIntArray.h" + +#include "V8Binding.h" +#include "V8CanvasArrayBuffer.h" +#include "V8CanvasArrayCustom.h" +#include "V8CustomBinding.h" +#include "V8Proxy.h" + +namespace WebCore { + +CALLBACK_FUNC_DECL(CanvasUnsignedIntArrayConstructor) +{ + INC_STATS("DOM.CanvasUnsignedIntArray.Contructor"); + + return constructCanvasArray<CanvasUnsignedIntArray>(args, V8ClassIndex::ToInt(V8ClassIndex::CANVASUNSIGNEDINTARRAY)); +} + +// Get the specified value from the integer array and return it wrapped as a JavaScript Number object to V8. Accesses outside the valid pixel buffer range return "undefined". +INDEXED_PROPERTY_GETTER(CanvasUnsignedIntArray) +{ + INC_STATS("DOM.CanvasUnsignedIntArray.IndexedPropertyGetter"); + CanvasUnsignedIntArray* array = V8DOMWrapper::convertToNativeObject<CanvasUnsignedIntArray>(V8ClassIndex::CANVASUNSIGNEDINTARRAY, info.Holder()); + + if ((index < 0) || (index >= array->length())) + return v8::Undefined(); + unsigned int result; + if (!array->get(index, result)) + return v8::Undefined(); + return v8::Number::New(result); +} + +// Set the specified value in the integer array. Accesses outside the valid integer array range are silently ignored. +INDEXED_PROPERTY_SETTER(CanvasUnsignedIntArray) +{ + INC_STATS("DOM.CanvasUnsignedIntArray.IndexedPropertySetter"); + CanvasUnsignedIntArray* array = V8DOMWrapper::convertToNativeObject<CanvasUnsignedIntArray>(V8ClassIndex::CANVASUNSIGNEDINTARRAY, info.Holder()); + + if ((index >= 0) && (index < array->length())) { + if (!value->IsNumber()) + return throwError("Could not convert value argument to a number"); + array->set(index, value->NumberValue()); + } + return value; +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/v8/custom/V8CanvasUnsignedShortArrayCustom.cpp b/WebCore/bindings/v8/custom/V8CanvasUnsignedShortArrayCustom.cpp new file mode 100644 index 0000000..eeef82c --- /dev/null +++ b/WebCore/bindings/v8/custom/V8CanvasUnsignedShortArrayCustom.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "CanvasArrayBuffer.h" +#include "CanvasUnsignedShortArray.h" + +#include "V8Binding.h" +#include "V8CanvasArrayBuffer.h" +#include "V8CanvasArrayCustom.h" +#include "V8CustomBinding.h" +#include "V8Proxy.h" + +namespace WebCore { + +CALLBACK_FUNC_DECL(CanvasUnsignedShortArrayConstructor) +{ + INC_STATS("DOM.CanvasUnsignedShortArray.Contructor"); + + return constructCanvasArray<CanvasUnsignedShortArray>(args, V8ClassIndex::ToInt(V8ClassIndex::CANVASUNSIGNEDSHORTARRAY)); +} + +// Get the specified value from the array and return it wrapped as a JavaScript Number object to V8. Accesses outside the valid array range return "undefined". +INDEXED_PROPERTY_GETTER(CanvasUnsignedShortArray) +{ + INC_STATS("DOM.CanvasUnsignedShortArray.IndexedPropertyGetter"); + CanvasUnsignedShortArray* array = V8DOMWrapper::convertToNativeObject<CanvasUnsignedShortArray>(V8ClassIndex::CANVASUNSIGNEDSHORTARRAY, info.Holder()); + + if ((index < 0) || (index >= array->length())) + return v8::Undefined(); + unsigned short result; + if (!array->get(index, result)) + return v8::Undefined(); + return v8::Number::New(result); +} + +// Set the specified value in the array. Accesses outside the valid array range are silently ignored. +INDEXED_PROPERTY_SETTER(CanvasUnsignedShortArray) +{ + INC_STATS("DOM.CanvasUnsignedShortArray.IndexedPropertySetter"); + CanvasUnsignedShortArray* array = V8DOMWrapper::convertToNativeObject<CanvasUnsignedShortArray>(V8ClassIndex::CANVASUNSIGNEDSHORTARRAY, info.Holder()); + + if ((index >= 0) && (index < array->length())) { + if (!value->IsNumber()) + return throwError("Could not convert value argument to a number"); + array->set(index, value->NumberValue()); + } + return value; +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/bindings/v8/custom/V8CustomBinding.h b/WebCore/bindings/v8/custom/V8CustomBinding.h index 22b4a94..82ce1c1 100644 --- a/WebCore/bindings/v8/custom/V8CustomBinding.h +++ b/WebCore/bindings/v8/custom/V8CustomBinding.h @@ -135,6 +135,16 @@ namespace WebCore { static const int kAbstractWorkerInternalFieldCount = kDefaultWrapperInternalFieldCount + 1; #endif +#if ENABLE(NOTIFICATIONS) + static const int kNotificationRequestCacheIndex = kDefaultWrapperInternalFieldCount + 0; + static const int kNotificationInternalFieldCount = kDefaultWrapperInternalFieldCount + 1; +#endif + +#if ENABLE(SVG) + static const int kSVGElementInstanceEventListenerCacheIndex = kDefaultWrapperInternalFieldCount + 0; + static const int kSVGElementInstanceInternalFieldCount = kDefaultWrapperInternalFieldCount + 1; +#endif + static const int kDOMWindowConsoleIndex = kDefaultWrapperInternalFieldCount + 0; static const int kDOMWindowHistoryIndex = kDefaultWrapperInternalFieldCount + 1; static const int kDOMWindowLocationbarIndex = kDefaultWrapperInternalFieldCount + 2; @@ -148,7 +158,8 @@ namespace WebCore { static const int kDOMWindowToolbarIndex = kDefaultWrapperInternalFieldCount + 10; static const int kDOMWindowLocationIndex = kDefaultWrapperInternalFieldCount + 11; static const int kDOMWindowDOMSelectionIndex = kDefaultWrapperInternalFieldCount + 12; - static const int kDOMWindowInternalFieldCount = kDefaultWrapperInternalFieldCount + 13; + static const int kDOMWindowEventListenerCacheIndex = kDefaultWrapperInternalFieldCount + 13; + static const int kDOMWindowInternalFieldCount = kDefaultWrapperInternalFieldCount + 14; static const int kStyleSheetOwnerNodeIndex = kDefaultWrapperInternalFieldCount + 0; static const int kStyleSheetInternalFieldCount = kDefaultWrapperInternalFieldCount + 1; @@ -158,6 +169,11 @@ namespace WebCore { static const int kDOMApplicationCacheFieldCount = kDefaultWrapperInternalFieldCount + 1; #endif +#if ENABLE(WEB_SOCKETS) + static const int kWebSocketCacheIndex = kDefaultWrapperInternalFieldCount + 0; + static const int kWebSocketInternalFieldCount = kDefaultWrapperInternalFieldCount + 1; +#endif + #define DECLARE_PROPERTY_ACCESSOR_GETTER(NAME) \ static v8::Handle<v8::Value> v8##NAME##AccessorGetter( \ v8::Local<v8::String> name, const v8::AccessorInfo& info) @@ -218,11 +234,18 @@ namespace WebCore { DECLARE_PROPERTY_ACCESSOR(CanvasRenderingContext2DStrokeStyle); DECLARE_PROPERTY_ACCESSOR(CanvasRenderingContext2DFillStyle); - DECLARE_PROPERTY_ACCESSOR_GETTER(DOMWindowEvent); + DECLARE_PROPERTY_ACCESSOR(DOMWindowEvent); DECLARE_PROPERTY_ACCESSOR_GETTER(DOMWindowCrypto); DECLARE_PROPERTY_ACCESSOR_SETTER(DOMWindowLocation); DECLARE_PROPERTY_ACCESSOR_SETTER(DOMWindowOpener); +#if ENABLE(VIDEO) + DECLARE_PROPERTY_ACCESSOR_GETTER(DOMWindowAudio); +#endif + + DECLARE_PROPERTY_ACCESSOR_GETTER(DOMWindowImage); + DECLARE_PROPERTY_ACCESSOR_GETTER(DOMWindowOption); + DECLARE_PROPERTY_ACCESSOR(DocumentLocation); DECLARE_PROPERTY_ACCESSOR(DocumentImplementation); DECLARE_PROPERTY_ACCESSOR_GETTER(EventSrcElement); @@ -231,7 +254,6 @@ namespace WebCore { DECLARE_PROPERTY_ACCESSOR_GETTER(EventClipboardData); DECLARE_PROPERTY_ACCESSOR(DOMWindowEventHandler); - DECLARE_PROPERTY_ACCESSOR(NodeEventHandler); DECLARE_CALLBACK(HTMLCanvasElementGetContext); @@ -319,6 +341,38 @@ namespace WebCore { DECLARE_CALLBACK(CanvasRenderingContext2DStrokeText); DECLARE_CALLBACK(CanvasRenderingContext2DPutImageData); +#if ENABLE(3D_CANVAS) + DECLARE_CALLBACK(CanvasRenderingContext3DBufferData); + DECLARE_CALLBACK(CanvasRenderingContext3DBufferSubData); + DECLARE_CALLBACK(CanvasRenderingContext3DSizeof); + DECLARE_CALLBACK(CanvasRenderingContext3DTexImage2D); + DECLARE_CALLBACK(CanvasRenderingContext3DTexSubImage2D); + DECLARE_CALLBACK(CanvasRenderingContext3DUniform1fv); + DECLARE_CALLBACK(CanvasRenderingContext3DUniform1iv); + DECLARE_CALLBACK(CanvasRenderingContext3DUniform2fv); + DECLARE_CALLBACK(CanvasRenderingContext3DUniform2iv); + DECLARE_CALLBACK(CanvasRenderingContext3DUniform3fv); + DECLARE_CALLBACK(CanvasRenderingContext3DUniform3iv); + DECLARE_CALLBACK(CanvasRenderingContext3DUniform4fv); + DECLARE_CALLBACK(CanvasRenderingContext3DUniform4iv); + DECLARE_CALLBACK(CanvasRenderingContext3DUniformMatrix2fv); + DECLARE_CALLBACK(CanvasRenderingContext3DUniformMatrix3fv); + DECLARE_CALLBACK(CanvasRenderingContext3DUniformMatrix4fv); + DECLARE_CALLBACK(CanvasRenderingContext3DVertexAttrib1fv); + DECLARE_CALLBACK(CanvasRenderingContext3DVertexAttrib2fv); + DECLARE_CALLBACK(CanvasRenderingContext3DVertexAttrib3fv); + DECLARE_CALLBACK(CanvasRenderingContext3DVertexAttrib4fv); + + DECLARE_CALLBACK(CanvasArrayBufferConstructor); + DECLARE_CALLBACK(CanvasByteArrayConstructor); + DECLARE_CALLBACK(CanvasFloatArrayConstructor); + DECLARE_CALLBACK(CanvasIntArrayConstructor); + DECLARE_CALLBACK(CanvasShortArrayConstructor); + DECLARE_CALLBACK(CanvasUnsignedByteArrayConstructor); + DECLARE_CALLBACK(CanvasUnsignedIntArrayConstructor); + DECLARE_CALLBACK(CanvasUnsignedShortArrayConstructor); +#endif + DECLARE_PROPERTY_ACCESSOR_GETTER(ClipboardTypes); DECLARE_CALLBACK(ClipboardClearData); DECLARE_CALLBACK(ClipboardGetData); @@ -400,14 +454,22 @@ namespace WebCore { DECLARE_CALLBACK(InspectorBackendAddSourceToFrame); DECLARE_CALLBACK(InspectorBackendSearch); DECLARE_CALLBACK(InspectorBackendSetting); + DECLARE_CALLBACK(InspectorBackendDatabaseForId); DECLARE_CALLBACK(InspectorBackendInspectedWindow); DECLARE_CALLBACK(InspectorBackendSetSetting); DECLARE_CALLBACK(InspectorBackendCurrentCallFrame); DECLARE_CALLBACK(InspectorBackendDebuggerEnabled); DECLARE_CALLBACK(InspectorBackendPauseOnExceptions); DECLARE_CALLBACK(InspectorBackendProfilerEnabled); + DECLARE_CALLBACK(InspectorBackendNodeForId); + DECLARE_CALLBACK(InspectorBackendWrapObject); + DECLARE_CALLBACK(InspectorBackendUnwrapObject); + DECLARE_CALLBACK(InspectorBackendPushNodePathToFrontend); #if ENABLE(DATABASE) - DECLARE_CALLBACK(InspectorBackendDatabaseTableNames); + DECLARE_CALLBACK(InspectorBackendSelectDatabase); +#endif +#if ENABLE(DOM_STORAGE) + DECLARE_CALLBACK(InspectorBackendSelectDOMStorage); #endif DECLARE_CALLBACK(InspectorBackendWrapCallback); @@ -445,21 +507,52 @@ namespace WebCore { DECLARE_INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection); DECLARE_NAMED_PROPERTY_GETTER(HTMLCollection); +#if ENABLE(3D_CANVAS) + DECLARE_INDEXED_PROPERTY_GETTER(CanvasByteArray); + DECLARE_INDEXED_PROPERTY_SETTER(CanvasByteArray); + + DECLARE_INDEXED_PROPERTY_GETTER(CanvasFloatArray); + DECLARE_INDEXED_PROPERTY_SETTER(CanvasFloatArray); + + DECLARE_INDEXED_PROPERTY_GETTER(CanvasIntArray); + DECLARE_INDEXED_PROPERTY_SETTER(CanvasIntArray); +#endif + DECLARE_INDEXED_PROPERTY_GETTER(CanvasPixelArray); DECLARE_INDEXED_PROPERTY_SETTER(CanvasPixelArray); +#if ENABLE(3D_CANVAS) + DECLARE_INDEXED_PROPERTY_GETTER(CanvasShortArray); + DECLARE_INDEXED_PROPERTY_SETTER(CanvasShortArray); + + DECLARE_INDEXED_PROPERTY_GETTER(CanvasUnsignedByteArray); + DECLARE_INDEXED_PROPERTY_SETTER(CanvasUnsignedByteArray); + + DECLARE_INDEXED_PROPERTY_GETTER(CanvasUnsignedIntArray); + DECLARE_INDEXED_PROPERTY_SETTER(CanvasUnsignedIntArray); + + DECLARE_INDEXED_PROPERTY_GETTER(CanvasUnsignedShortArray); + DECLARE_INDEXED_PROPERTY_SETTER(CanvasUnsignedShortArray); +#endif + + DECLARE_PROPERTY_ACCESSOR_GETTER(MessageEventPorts); + DECLARE_CALLBACK(MessageEventInitMessageEvent); + DECLARE_PROPERTY_ACCESSOR(MessagePortOnmessage); DECLARE_PROPERTY_ACCESSOR(MessagePortOnclose); - DECLARE_CALLBACK(MessagePortStartConversation); DECLARE_CALLBACK(MessagePortAddEventListener); + DECLARE_CALLBACK(MessagePortPostMessage); DECLARE_CALLBACK(MessagePortRemoveEventListener); + DECLARE_CALLBACK(MessagePortStartConversation); DECLARE_CALLBACK(DatabaseChangeVersion); DECLARE_CALLBACK(DatabaseTransaction); + DECLARE_CALLBACK(DatabaseReadTransaction); DECLARE_CALLBACK(SQLTransactionExecuteSql); DECLARE_CALLBACK(SQLResultSetRowListItem); DECLARE_INDEXED_PROPERTY_GETTER(ClientRectList); + DECLARE_INDEXED_PROPERTY_GETTER(FileList); #if ENABLE(DATAGRID) DECLARE_PROPERTY_ACCESSOR(HTMLDataGridElementDataSource); @@ -496,8 +589,10 @@ namespace WebCore { DECLARE_CALLBACK(AbstractWorkerRemoveEventListener); DECLARE_PROPERTY_ACCESSOR(DedicatedWorkerContextOnmessage); + DECLARE_CALLBACK(DedicatedWorkerContextPostMessage); DECLARE_PROPERTY_ACCESSOR(WorkerOnmessage); + DECLARE_CALLBACK(WorkerPostMessage); DECLARE_CALLBACK(WorkerConstructor); DECLARE_PROPERTY_ACCESSOR_GETTER(WorkerContextSelf); @@ -509,7 +604,17 @@ namespace WebCore { DECLARE_CALLBACK(WorkerContextClearInterval); DECLARE_CALLBACK(WorkerContextAddEventListener); DECLARE_CALLBACK(WorkerContextRemoveEventListener); -#endif +#endif // ENABLE(WORKERS) + +#if ENABLE(NOTIFICATIONS) + DECLARE_CALLBACK(NotificationCenterRequestPermission); + DECLARE_CALLBACK(NotificationCenterCreateNotification); + DECLARE_CALLBACK(NotificationCenterCreateHTMLNotification); + + DECLARE_CALLBACK(NotificationAddEventListener); + DECLARE_CALLBACK(NotificationRemoveEventListener); + DECLARE_PROPERTY_ACCESSOR(NotificationEventHandler); +#endif // ENABLE(NOTIFICATIONS) #if ENABLE(OFFLINE_WEB_APPLICATIONS) DECLARE_PROPERTY_ACCESSOR(DOMApplicationCacheEventHandler); @@ -528,6 +633,15 @@ namespace WebCore { DECLARE_PROPERTY_ACCESSOR_GETTER(CoordinatesHeading); DECLARE_PROPERTY_ACCESSOR_GETTER(CoordinatesSpeed); +#if ENABLE(WEB_SOCKETS) + DECLARE_PROPERTY_ACCESSOR(WebSocketOnopen); + DECLARE_PROPERTY_ACCESSOR(WebSocketOnmessage); + DECLARE_PROPERTY_ACCESSOR(WebSocketOnclose); + DECLARE_CALLBACK(WebSocketConstructor); + DECLARE_CALLBACK(WebSocketSend); + DECLARE_CALLBACK(WebSocketClose); +#endif + #undef DECLARE_INDEXED_ACCESS_CHECK #undef DECLARE_NAMED_ACCESS_CHECK diff --git a/WebCore/bindings/v8/custom/V8CustomEventListener.cpp b/WebCore/bindings/v8/custom/V8CustomEventListener.cpp index 305da8d..91abecd 100644 --- a/WebCore/bindings/v8/custom/V8CustomEventListener.cpp +++ b/WebCore/bindings/v8/custom/V8CustomEventListener.cpp @@ -35,37 +35,25 @@ namespace WebCore { -V8EventListener::V8EventListener(Frame* frame, v8::Local<v8::Object> listener, bool isAttribute) - : V8AbstractEventListener(frame, isAttribute) +V8EventListener::V8EventListener(Frame* frame, PassRefPtr<V8ListenerGuard> guard, v8::Local<v8::Object> listener, bool isAttribute) + : V8AbstractEventListener(frame, guard, isAttribute) { - m_listener = v8::Persistent<v8::Object>::New(listener); -#ifndef NDEBUG - V8GCController::registerGlobalHandle(EVENT_LISTENER, this, m_listener); -#endif -} - -V8EventListener::~V8EventListener() -{ - if (m_frame) { - V8Proxy* proxy = V8Proxy::retrieve(m_frame); - if (proxy) - proxy->eventListeners()->remove(this); - } - - disposeListenerObject(); + setListenerObject(listener); } v8::Local<v8::Function> V8EventListener::getListenerFunction() { + v8::Local<v8::Object> listener = getListenerObject(); + // Has the listener been disposed? - if (m_listener.IsEmpty()) + if (listener.IsEmpty()) return v8::Local<v8::Function>(); - if (m_listener->IsFunction()) - return v8::Local<v8::Function>::New(v8::Persistent<v8::Function>::Cast(m_listener)); + if (listener->IsFunction()) + return v8::Local<v8::Function>::Cast(listener); - if (m_listener->IsObject()) { - v8::Local<v8::Value> property = m_listener->Get(v8::String::NewSymbol("handleEvent")); + if (listener->IsObject()) { + v8::Local<v8::Value> property = listener->Get(v8::String::NewSymbol("handleEvent")); if (property->IsFunction()) return v8::Local<v8::Function>::Cast(property); } @@ -73,16 +61,16 @@ v8::Local<v8::Function> V8EventListener::getListenerFunction() return v8::Local<v8::Function>(); } -v8::Local<v8::Value> V8EventListener::callListenerFunction(v8::Handle<v8::Value> jsEvent, Event* event, bool isWindowEvent) +v8::Local<v8::Value> V8EventListener::callListenerFunction(v8::Handle<v8::Value> jsEvent, Event* event) { v8::Local<v8::Function> handlerFunction = getListenerFunction(); - v8::Local<v8::Object> receiver = getReceiverObject(event, isWindowEvent); + v8::Local<v8::Object> receiver = getReceiverObject(event); if (handlerFunction.IsEmpty() || receiver.IsEmpty()) return v8::Local<v8::Value>(); v8::Handle<v8::Value> parameters[1] = { jsEvent }; - V8Proxy* proxy = V8Proxy::retrieve(m_frame); + V8Proxy* proxy = V8Proxy::retrieve(frame()); if (!proxy) return v8::Local<v8::Value>(); return proxy->callFunction(handlerFunction, receiver, 1, parameters); diff --git a/WebCore/bindings/v8/custom/V8CustomEventListener.h b/WebCore/bindings/v8/custom/V8CustomEventListener.h index 20adf99..e34f24f 100644 --- a/WebCore/bindings/v8/custom/V8CustomEventListener.h +++ b/WebCore/bindings/v8/custom/V8CustomEventListener.h @@ -44,23 +44,19 @@ namespace WebCore { // that can handle the event. class V8EventListener : public V8AbstractEventListener { public: - static PassRefPtr<V8EventListener> create(Frame* frame, v8::Local<v8::Object> listener, bool isAttribute) + static PassRefPtr<V8EventListener> create(Frame* frame, PassRefPtr<V8ListenerGuard> guard, v8::Local<v8::Object> listener, bool isAttribute) { - return adoptRef(new V8EventListener(frame, listener, isAttribute)); + return adoptRef(new V8EventListener(frame, guard, listener, isAttribute)); } - // Detach the listener from its owner frame. - void disconnectFrame() { m_frame = 0; } - protected: - V8EventListener(Frame*, v8::Local<v8::Object> listener, bool isAttribute); - virtual ~V8EventListener(); + V8EventListener(Frame*, PassRefPtr<V8ListenerGuard>, v8::Local<v8::Object> listener, bool isAttribute); + v8::Local<v8::Function> getListenerFunction(); private: - virtual v8::Local<v8::Value> callListenerFunction(v8::Handle<v8::Value> jsEvent, Event*, bool isWindowEvent); - virtual bool virtualisAttribute() const { return m_isAttribute; } - }; + virtual v8::Local<v8::Value> callListenerFunction(v8::Handle<v8::Value> jsEvent, Event*); + }; } // namespace WebCore diff --git a/WebCore/bindings/v8/custom/V8DOMApplicationCacheCustom.cpp b/WebCore/bindings/v8/custom/V8DOMApplicationCacheCustom.cpp index 7a3bfe6..134de95 100644 --- a/WebCore/bindings/v8/custom/V8DOMApplicationCacheCustom.cpp +++ b/WebCore/bindings/v8/custom/V8DOMApplicationCacheCustom.cpp @@ -37,77 +37,19 @@ #include "V8Binding.h" #include "V8CustomBinding.h" #include "V8Document.h" -#include "V8ObjectEventListener.h" #include "V8Proxy.h" #include "V8Utilities.h" #include "WorkerContextExecutionProxy.h" namespace WebCore { -static const bool kFindOnly = true; -static const bool kFindOrCreate = false; - -static PassRefPtr<EventListener> argumentToEventListener(DOMApplicationCache* appcache, v8::Local<v8::Value> value, bool findOnly) -{ - V8Proxy* proxy = V8Proxy::retrieve(appcache->scriptExecutionContext()); - if (proxy) - return findOnly ? proxy->objectListeners()->findWrapper(value, false) - : proxy->objectListeners()->findOrCreateWrapper<V8ObjectEventListener>(proxy->frame(), value, false); - return 0; -} - -static v8::Local<v8::Object> eventListenerToV8Object(EventListener* listener) -{ - return (static_cast<V8ObjectEventListener*>(listener))->getListenerObject(); -} - -static inline ApplicationCacheHost::EventID toEventID(v8::Local<v8::String> value) -{ - String key = toWebCoreString(value); - ASSERT(key.startsWith("on")); - return DOMApplicationCache::toEventID(key.substring(2)); -} - -// Handles appcache.onfooevent attribute getting -ACCESSOR_GETTER(DOMApplicationCacheEventHandler) -{ - INC_STATS("DOMApplicationCache.onevent_getter"); - DOMApplicationCache* appcache = V8DOMWrapper::convertToNativeObject<DOMApplicationCache>(V8ClassIndex::DOMAPPLICATIONCACHE, info.Holder()); - EventListener* listener = appcache->getAttributeEventListener(toEventID(name)); - if (!listener) - return v8::Null(); - return eventListenerToV8Object(listener); -} - -// Handles appcache.onfooevent attribute setting -ACCESSOR_SETTER(DOMApplicationCacheEventHandler) -{ - INC_STATS("DOMApplicationCache.onevent_setter"); - DOMApplicationCache* appcache = V8DOMWrapper::convertToNativeObject<DOMApplicationCache>(V8ClassIndex::DOMAPPLICATIONCACHE, info.Holder()); - ApplicationCacheHost::EventID eventType = toEventID(name); - - if (EventListener* oldListener = appcache->getAttributeEventListener(eventType)) { - v8::Local<v8::Object> object = eventListenerToV8Object(oldListener); - removeHiddenDependency(info.Holder(), object, V8Custom::kDOMApplicationCacheCacheIndex); - appcache->clearAttributeEventListener(eventType); - } - - if (value->IsFunction()) { - RefPtr<EventListener> newListener = argumentToEventListener(appcache, value, kFindOrCreate); - if (newListener) { - createHiddenDependency(info.Holder(), value, V8Custom::kDOMApplicationCacheCacheIndex); - appcache->setAttributeEventListener(eventType, newListener); - } - } -} - // Handles appcache.addEventListner(name, func, capture) method calls CALLBACK_FUNC_DECL(DOMApplicationCacheAddEventListener) { INC_STATS("DOMApplicationCache.addEventListener()"); DOMApplicationCache* appcache = V8DOMWrapper::convertToNativeObject<DOMApplicationCache>(V8ClassIndex::DOMAPPLICATIONCACHE, args.Holder()); - RefPtr<EventListener> listener = argumentToEventListener(appcache, args[1], kFindOrCreate); + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(appcache, args[1], false, ListenerFindOrCreate); if (listener) { createHiddenDependency(args.Holder(), args[1], V8Custom::kDOMApplicationCacheCacheIndex); String eventType = toWebCoreString(args[0]); @@ -123,7 +65,7 @@ CALLBACK_FUNC_DECL(DOMApplicationCacheRemoveEventListener) INC_STATS("DOMApplicationCache.removeEventListener()"); DOMApplicationCache* appcache = V8DOMWrapper::convertToNativeObject<DOMApplicationCache>(V8ClassIndex::DOMAPPLICATIONCACHE, args.Holder()); - RefPtr<EventListener> listener = argumentToEventListener(appcache, args[1], kFindOnly); + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(appcache, args[1], false, ListenerFindOnly); if (listener) { removeHiddenDependency(args.Holder(), args[1], V8Custom::kDOMApplicationCacheCacheIndex); String eventType = toWebCoreString(args[0]); diff --git a/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp b/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp index 7d0b9e6..0dc5a96 100644 --- a/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp +++ b/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp @@ -34,6 +34,7 @@ #include "V8Binding.h" #include "V8CustomBinding.h" #include "V8CustomEventListener.h" +#include "V8MessagePortCustom.h" #include "V8Proxy.h" #include "V8Utilities.h" @@ -48,6 +49,7 @@ #include "PlatformScreen.h" #include "ScheduledAction.h" #include "ScriptSourceCode.h" +#include "SerializedScriptValue.h" #include "Settings.h" #include "WindowFeatures.h" @@ -64,32 +66,44 @@ v8::Handle<v8::Value> V8Custom::WindowSetTimeoutImpl(const v8::Arguments& args, if (argumentCount < 1) return v8::Undefined(); - DOMWindow* imp = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, args.Holder()); - - if (!imp->frame()) - return v8::Undefined(); - - if (!V8Proxy::canAccessFrame(imp->frame(), true)) - return v8::Undefined(); + v8::Handle<v8::Value> function = args[0]; - ScriptExecutionContext* scriptContext = static_cast<ScriptExecutionContext*>(imp->frame()->document()); + WebCore::String functionString; + if (!function->IsFunction()) { + if (function->IsString()) + functionString = toWebCoreString(function); + else { + v8::Handle<v8::Value> v8String = function->ToString(); - v8::Handle<v8::Value> function = args[0]; + // Bail out if string conversion failed. + if (v8String.IsEmpty()) + return v8::Undefined(); - int32_t timeout = 0; - if (argumentCount >= 2) - timeout = args[1]->Int32Value(); + functionString = toWebCoreString(v8String); + } - int id; - if (function->IsString()) { // Don't allow setting timeouts to run empty functions! // (Bug 1009597) - WebCore::String functionString = toWebCoreString(function); if (functionString.length() == 0) return v8::Undefined(); + } + + int32_t timeout = 0; + if (argumentCount >= 2) + timeout = args[1]->Int32Value(); + + DOMWindow* imp = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, args.Holder()); + + if (!V8Proxy::canAccessFrame(imp->frame(), true)) + return v8::Undefined(); - id = DOMTimer::install(scriptContext, new ScheduledAction(functionString), timeout, singleShot); - } else if (function->IsFunction()) { + ScriptExecutionContext* scriptContext = static_cast<ScriptExecutionContext*>(imp->document()); + + if (!scriptContext) + return v8::Undefined(); + + int id; + if (function->IsFunction()) { int paramCount = argumentCount >= 2 ? argumentCount - 2 : 0; v8::Local<v8::Value>* params = 0; if (paramCount > 0) { @@ -100,14 +114,14 @@ v8::Handle<v8::Value> V8Custom::WindowSetTimeoutImpl(const v8::Arguments& args, } // params is passed to action, and released in action's destructor - ScheduledAction* action = new ScheduledAction(v8::Handle<v8::Function>::Cast(function), paramCount, params); + ScheduledAction* action = new ScheduledAction(V8Proxy::context(imp->frame()), v8::Handle<v8::Function>::Cast(function), paramCount, params); delete[] params; id = DOMTimer::install(scriptContext, action, timeout, singleShot); - } else - // FIXME(fqian): what's the right return value if failed. - return v8::Undefined(); + } else { + id = DOMTimer::install(scriptContext, new ScheduledAction(V8Proxy::context(imp->frame()), functionString), timeout, singleShot); + } return v8::Integer::New(id); } @@ -145,14 +159,37 @@ static v8::Handle<v8::Value> convertBase64(const String& str, bool encode) ACCESSOR_GETTER(DOMWindowEvent) { + v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, info.This()); + if (holder.IsEmpty()) + return v8::Undefined(); + + Frame* frame = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, holder)->frame(); + if (!V8Proxy::canAccessFrame(frame, true)) + return v8::Undefined(); + + v8::Local<v8::Context> context = V8Proxy::context(frame); v8::Local<v8::String> eventSymbol = v8::String::NewSymbol("event"); - v8::Local<v8::Context> context = v8::Context::GetCurrent(); v8::Handle<v8::Value> jsEvent = context->Global()->GetHiddenValue(eventSymbol); if (jsEvent.IsEmpty()) return v8::Undefined(); return jsEvent; } +ACCESSOR_SETTER(DOMWindowEvent) +{ + v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, info.This()); + if (holder.IsEmpty()) + return; + + Frame* frame = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, holder)->frame(); + if (!V8Proxy::canAccessFrame(frame, true)) + return; + + v8::Local<v8::Context> context = V8Proxy::context(frame); + v8::Local<v8::String> eventSymbol = v8::String::NewSymbol("event"); + context->Global()->SetHiddenValue(eventSymbol, value); +} + ACCESSOR_GETTER(DOMWindowCrypto) { // FIXME: Implement me. @@ -161,11 +198,7 @@ ACCESSOR_GETTER(DOMWindowCrypto) ACCESSOR_SETTER(DOMWindowLocation) { - v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, info.This()); - if (holder.IsEmpty()) - return; - - DOMWindow* imp = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, holder); + DOMWindow* imp = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, info.Holder()); WindowSetLocation(imp, toWebCoreString(value)); } @@ -194,18 +227,42 @@ ACCESSOR_SETTER(DOMWindowOpener) info.This()->Set(name, value); } +#if ENABLE(VIDEO) + +ACCESSOR_GETTER(DOMWindowAudio) +{ + DOMWindow* window = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, info.Holder()); + return V8DOMWrapper::getConstructor(V8ClassIndex::AUDIO, window); +} + +#endif + +ACCESSOR_GETTER(DOMWindowImage) +{ + DOMWindow* window = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, info.Holder()); + return V8DOMWrapper::getConstructor(V8ClassIndex::IMAGE, window); +} + +ACCESSOR_GETTER(DOMWindowOption) +{ + DOMWindow* window = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, info.Holder()); + return V8DOMWrapper::getConstructor(V8ClassIndex::OPTION, window); +} + CALLBACK_FUNC_DECL(DOMWindowAddEventListener) { INC_STATS("DOM.DOMWindow.addEventListener()"); + + String eventType = toWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + DOMWindow* imp = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, args.Holder()); if (!V8Proxy::canAccessFrame(imp->frame(), true)) return v8::Undefined(); - if (!imp->frame()) - return v8::Undefined(); // DOMWindow could be disconnected from the frame - - Document* doc = imp->frame()->document(); + Document* doc = imp->document(); + if (!doc) return v8::Undefined(); @@ -214,12 +271,11 @@ CALLBACK_FUNC_DECL(DOMWindowAddEventListener) if (!proxy) return v8::Undefined(); - RefPtr<EventListener> listener = proxy->eventListeners()->findOrCreateWrapper<V8EventListener>(proxy->frame(), args[1], false); + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(proxy, args[1], false, ListenerFindOrCreate); if (listener) { - String eventType = toWebCoreString(args[0]); - bool useCapture = args[2]->BooleanValue(); imp->addEventListener(eventType, listener, useCapture); + createHiddenDependency(args.Holder(), args[1], V8Custom::kDOMWindowEventListenerCacheIndex); } return v8::Undefined(); @@ -229,15 +285,17 @@ CALLBACK_FUNC_DECL(DOMWindowAddEventListener) CALLBACK_FUNC_DECL(DOMWindowRemoveEventListener) { INC_STATS("DOM.DOMWindow.removeEventListener()"); + + String eventType = toWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + DOMWindow* imp = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, args.Holder()); if (!V8Proxy::canAccessFrame(imp->frame(), true)) return v8::Undefined(); - if (!imp->frame()) - return v8::Undefined(); + Document* doc = imp->document(); - Document* doc = imp->frame()->document(); if (!doc) return v8::Undefined(); @@ -245,12 +303,11 @@ CALLBACK_FUNC_DECL(DOMWindowRemoveEventListener) if (!proxy) return v8::Undefined(); - RefPtr<EventListener> listener = proxy->eventListeners()->findWrapper(args[1], false); + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(proxy, args[1], false, ListenerFindOnly); if (listener) { - String eventType = toWebCoreString(args[0]); - bool useCapture = args[2]->BooleanValue(); imp->removeEventListener(eventType, listener.get(), useCapture); + removeHiddenDependency(args.Holder(), args[1], V8Custom::kDOMWindowEventListenerCacheIndex); } return v8::Undefined(); @@ -265,8 +322,8 @@ CALLBACK_FUNC_DECL(DOMWindowPostMessage) ASSERT(source->frame()); v8::TryCatch tryCatch; - String message = toWebCoreString(args[0]); - MessagePort* port = 0; + RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(toWebCoreString(args[0])); + MessagePortArray portArray; String targetOrigin; // This function has variable arguments and can either be: @@ -274,8 +331,8 @@ CALLBACK_FUNC_DECL(DOMWindowPostMessage) // or // postMessage(message, targetOrigin); if (args.Length() > 2) { - if (V8DOMWrapper::isWrapperOfType(args[1], V8ClassIndex::MESSAGEPORT)) - port = V8DOMWrapper::convertToNativeObject<MessagePort>(V8ClassIndex::MESSAGEPORT, v8::Handle<v8::Object>::Cast(args[1])); + if (!getMessagePortArray(args[1], portArray)) + return v8::Undefined(); targetOrigin = toWebCoreStringWithNullOrUndefinedCheck(args[2]); } else { targetOrigin = toWebCoreStringWithNullOrUndefinedCheck(args[1]); @@ -285,16 +342,18 @@ CALLBACK_FUNC_DECL(DOMWindowPostMessage) return v8::Undefined(); ExceptionCode ec = 0; - window->postMessage(message, port, targetOrigin, source, ec); - if (ec) - V8Proxy::setDOMException(ec); - - return v8::Undefined(); + window->postMessage(message.release(), &portArray, targetOrigin, source, ec); + return throwError(ec); } CALLBACK_FUNC_DECL(DOMWindowAtob) { INC_STATS("DOM.DOMWindow.atob()"); + + if (args[0]->IsNull()) + return v8String(""); + String str = toWebCoreString(args[0]); + DOMWindow* imp = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, args.Holder()); if (!V8Proxy::canAccessFrame(imp->frame(), true)) @@ -303,16 +362,17 @@ CALLBACK_FUNC_DECL(DOMWindowAtob) if (args.Length() < 1) return throwError("Not enough arguments", V8Proxy::SyntaxError); - if (args[0]->IsNull()) - return v8String(""); - - String str = toWebCoreString(args[0]); return convertBase64(str, false); } CALLBACK_FUNC_DECL(DOMWindowBtoa) { INC_STATS("DOM.DOMWindow.btoa()"); + + if (args[0]->IsNull()) + return v8String(""); + String str = toWebCoreString(args[0]); + DOMWindow* imp = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, args.Holder()); if (!V8Proxy::canAccessFrame(imp->frame(), true)) @@ -321,10 +381,6 @@ CALLBACK_FUNC_DECL(DOMWindowBtoa) if (args.Length() < 1) return throwError("Not enough arguments", V8Proxy::SyntaxError); - if (args[0]->IsNull()) - return v8String(""); - - String str = toWebCoreString(args[0]); return convertBase64(str, true); } @@ -335,7 +391,10 @@ CALLBACK_FUNC_DECL(DOMWindowBtoa) CALLBACK_FUNC_DECL(DOMWindowToString) { INC_STATS("DOM.DOMWindow.toString()"); - return args.This()->ObjectProtoToString(); + v8::Handle<v8::Object> domWrapper = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, args.This()); + if (domWrapper.IsEmpty()) + return args.This()->ObjectProtoToString(); + return domWrapper->ObjectProtoToString(); } CALLBACK_FUNC_DECL(DOMWindowNOP) @@ -344,84 +403,6 @@ CALLBACK_FUNC_DECL(DOMWindowNOP) return v8::Undefined(); } -static String eventNameFromAttributeName(const String& name) -{ - ASSERT(name.startsWith("on")); - String eventType = name.substring(2); - - if (eventType.startsWith("w")) { - switch(eventType[eventType.length() - 1]) { - case 't': - eventType = "webkitAnimationStart"; - break; - case 'n': - eventType = "webkitAnimationIteration"; - break; - case 'd': - ASSERT(eventType.length() > 7); - if (eventType[7] == 'a') - eventType = "webkitAnimationEnd"; - else - eventType = "webkitTransitionEnd"; - break; - } - } - - return eventType; -} - -ACCESSOR_SETTER(DOMWindowEventHandler) -{ - v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, info.This()); - if (holder.IsEmpty()) - return; - - DOMWindow* imp = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, holder); - if (!imp->frame()) - return; - - Document* doc = imp->frame()->document(); - if (!doc) - return; - - String key = toWebCoreString(name); - String eventType = eventNameFromAttributeName(key); - - if (value->IsNull()) { - // Clear the event listener - imp->clearAttributeEventListener(eventType); - } else { - V8Proxy* proxy = V8Proxy::retrieve(imp->frame()); - if (!proxy) - return; - - RefPtr<EventListener> listener = proxy->eventListeners()->findOrCreateWrapper<V8EventListener>(proxy->frame(), value, true); - if (listener) - imp->setAttributeEventListener(eventType, listener); - } -} - -ACCESSOR_GETTER(DOMWindowEventHandler) -{ - v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, info.This()); - if (holder.IsEmpty()) - return v8::Undefined(); - - DOMWindow* imp = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, holder); - if (!imp->frame()) - return v8::Undefined(); - - Document* doc = imp->frame()->document(); - if (!doc) - return v8::Undefined(); - - String key = toWebCoreString(name); - String eventType = eventNameFromAttributeName(key); - - EventListener* listener = imp->getAttributeEventListener(eventType); - return V8DOMWrapper::convertEventListenerToV8Object(listener); -} - static bool canShowModalDialogNow(const Frame* frame) { // A frame can out live its page. See bug 1219613. @@ -512,7 +493,7 @@ static Frame* createWindow(Frame* callingFrame, return 0; newFrame->loader()->setOpener(openerFrame); - newFrame->loader()->setOpenedByDOM(); + newFrame->page()->setOpenedByDOM(); // Set dialog arguments on the global object of the new frame. if (!dialogArgs.IsEmpty()) { @@ -525,13 +506,13 @@ static Frame* createWindow(Frame* callingFrame, if (protocolIsJavaScript(url) || ScriptController::isSafeScript(newFrame)) { KURL completedUrl = - url.isEmpty() ? KURL("") : completeURL(url); + url.isEmpty() ? KURL(ParsedURLString, "") : completeURL(url); bool userGesture = processingUserGesture(); if (created) newFrame->loader()->changeLocation(completedUrl, referrer, false, false, userGesture); else if (!url.isEmpty()) - newFrame->loader()->scheduleLocationChange(completedUrl.string(), referrer, false, userGesture); + newFrame->redirectScheduler()->scheduleLocationChange(completedUrl.string(), referrer, false, userGesture); } return newFrame; @@ -542,11 +523,16 @@ static Frame* createWindow(Frame* callingFrame, CALLBACK_FUNC_DECL(DOMWindowShowModalDialog) { INC_STATS("DOM.DOMWindow.showModalDialog()"); + + String url = toWebCoreStringWithNullOrUndefinedCheck(args[0]); + v8::Local<v8::Value> dialogArgs = args[1]; + String featureArgs = toWebCoreStringWithNullOrUndefinedCheck(args[2]); + DOMWindow* window = V8DOMWrapper::convertToNativeObject<DOMWindow>( V8ClassIndex::DOMWINDOW, args.Holder()); Frame* frame = window->frame(); - if (!frame || !V8Proxy::canAccessFrame(frame, true)) + if (!V8Proxy::canAccessFrame(frame, true)) return v8::Undefined(); Frame* callingFrame = V8Proxy::retrieveFrameForCallingContext(); @@ -560,10 +546,6 @@ CALLBACK_FUNC_DECL(DOMWindowShowModalDialog) if (!canShowModalDialogNow(frame) || !allowPopUp()) return v8::Undefined(); - String url = toWebCoreStringWithNullOrUndefinedCheck(args[0]); - v8::Local<v8::Value> dialogArgs = args[1]; - String featureArgs = toWebCoreStringWithNullOrUndefinedCheck(args[2]); - const HashMap<String, String> features = parseModalDialogFeatures(featureArgs); const bool trusted = false; @@ -631,10 +613,14 @@ CALLBACK_FUNC_DECL(DOMWindowShowModalDialog) CALLBACK_FUNC_DECL(DOMWindowOpen) { INC_STATS("DOM.DOMWindow.open()"); + + String urlString = toWebCoreStringWithNullOrUndefinedCheck(args[0]); + AtomicString frameName = (args[1]->IsUndefined() || args[1]->IsNull()) ? "_blank" : AtomicString(toWebCoreString(args[1])); + DOMWindow* parent = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, args.Holder()); Frame* frame = parent->frame(); - if (!frame || !V8Proxy::canAccessFrame(frame, true)) + if (!V8Proxy::canAccessFrame(frame, true)) return v8::Undefined(); Frame* callingFrame = V8Proxy::retrieveFrameForCallingContext(); @@ -649,9 +635,6 @@ CALLBACK_FUNC_DECL(DOMWindowOpen) if (!page) return v8::Undefined(); - String urlString = toWebCoreStringWithNullOrUndefinedCheck(args[0]); - AtomicString frameName = (args[1]->IsUndefined() || args[1]->IsNull()) ? "_blank" : AtomicString(toWebCoreString(args[1])); - // Because FrameTree::find() returns true for empty strings, we must check // for empty framenames. Otherwise, illegitimate window.open() calls with // no name will pass right through the popup blocker. @@ -687,7 +670,7 @@ CALLBACK_FUNC_DECL(DOMWindowOpen) // the outgoingReferrer. We replicate that behavior here. String referrer = enteredFrame->loader()->outgoingReferrer(); - frame->loader()->scheduleLocationChange(completedUrl, referrer, false, userGesture); + frame->redirectScheduler()->scheduleLocationChange(completedUrl, referrer, false, userGesture); } return V8DOMWrapper::convertToV8Object(V8ClassIndex::DOMWINDOW, frame->domWindow()); } @@ -756,11 +739,8 @@ CALLBACK_FUNC_DECL(DOMWindowOpen) INDEXED_PROPERTY_GETTER(DOMWindow) { INC_STATS("DOM.DOMWindow.IndexedPropertyGetter"); - v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, info.This()); - if (holder.IsEmpty()) - return notHandledByInterceptor(); - DOMWindow* window = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, holder); + DOMWindow* window = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, info.Holder()); if (!window) return notHandledByInterceptor(); @@ -780,11 +760,8 @@ NAMED_PROPERTY_GETTER(DOMWindow) { INC_STATS("DOM.DOMWindow.NamedPropertyGetter"); - v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, info.This()); - if (holder.IsEmpty()) - return notHandledByInterceptor(); - - DOMWindow* window = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, holder); + // TODO(antonm): investigate what convertToNativeObject does for the case of DOMWINDOW. + DOMWindow* window = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, info.Holder()); if (!window) return notHandledByInterceptor(); @@ -800,12 +777,13 @@ NAMED_PROPERTY_GETTER(DOMWindow) return V8DOMWrapper::convertToV8Object(V8ClassIndex::DOMWINDOW, child->domWindow()); // Search IDL functions defined in the prototype - v8::Handle<v8::Value> result = holder->GetRealNamedPropertyInPrototypeChain(name); + v8::Handle<v8::Value> result = info.Holder()->GetRealNamedProperty(name); if (!result.IsEmpty()) return result; // Search named items in the document. Document* doc = frame->document(); + if (doc) { RefPtr<HTMLCollection> items = doc->windowNamedItems(propName); if (items->length() >= 1) { @@ -826,13 +804,13 @@ void V8Custom::WindowSetLocation(DOMWindow* window, const String& relativeURL) if (!frame) return; - if (!shouldAllowNavigation(frame)) - return; - KURL url = completeURL(relativeURL); if (url.isNull()) return; + if (!shouldAllowNavigation(frame)) + return; + navigateIfAllowed(frame, url, false, false); } @@ -853,12 +831,15 @@ CALLBACK_FUNC_DECL(DOMWindowSetInterval) void V8Custom::ClearTimeoutImpl(const v8::Arguments& args) { + int handle = toInt32(args[0]); + v8::Handle<v8::Object> holder = args.Holder(); DOMWindow* imp = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, holder); if (!V8Proxy::canAccessFrame(imp->frame(), true)) return; - ScriptExecutionContext* context = static_cast<ScriptExecutionContext*>(imp->frame()->document()); - int handle = toInt32(args[0]); + ScriptExecutionContext* context = static_cast<ScriptExecutionContext*>(imp->document()); + if (!context) + return; DOMTimer::removeById(context, handle); } diff --git a/WebCore/bindings/v8/custom/V8DatabaseCustom.cpp b/WebCore/bindings/v8/custom/V8DatabaseCustom.cpp index 300e829..9ddd620 100644 --- a/WebCore/bindings/v8/custom/V8DatabaseCustom.cpp +++ b/WebCore/bindings/v8/custom/V8DatabaseCustom.cpp @@ -45,13 +45,50 @@ namespace WebCore { CALLBACK_FUNC_DECL(DatabaseChangeVersion) { INC_STATS("DOM.Database.changeVersion()"); + + if (args.Length() < 2) + return throwError("The old and new version strings are required.", V8Proxy::SyntaxError); + + if (!(args[0]->IsString() && args[1]->IsString())) + return throwError("The old and new versions must be strings."); + + Database* database = V8DOMWrapper::convertToNativeObject<Database>(V8ClassIndex::DATABASE, args.Holder()); + + Frame* frame = V8Proxy::retrieveFrameForCurrentContext(); + if (!frame) + return v8::Undefined(); + + RefPtr<V8CustomSQLTransactionCallback> callback; + if (args.Length() > 2) { + if (!args[2]->IsObject()) + return throwError("changeVersion transaction callback must be of valid type."); + + callback = V8CustomSQLTransactionCallback::create(args[2], frame); + } + + RefPtr<V8CustomSQLTransactionErrorCallback> errorCallback; + if (args.Length() > 3) { + if (!args[3]->IsObject()) + return throwError("changeVersion error callback must be of valid type."); + + errorCallback = V8CustomSQLTransactionErrorCallback::create(args[3], frame); + } + + RefPtr<V8CustomVoidCallback> successCallback; + if (args.Length() > 4) { + if (!args[4]->IsObject()) + return throwError("changeVersion success callback must be of valid type."); + + successCallback = V8CustomVoidCallback::create(args[4], frame); + } + + database->changeVersion(toWebCoreString(args[0]), toWebCoreString(args[1]), callback.release(), errorCallback.release(), successCallback.release()); + return v8::Undefined(); } -CALLBACK_FUNC_DECL(DatabaseTransaction) +static v8::Handle<v8::Value> createTransaction(const v8::Arguments& args, bool readOnly) { - INC_STATS("DOM.Database.transaction()"); - if (!args.Length()) return throwError("Transaction callback is required.", V8Proxy::SyntaxError); @@ -76,18 +113,28 @@ CALLBACK_FUNC_DECL(DatabaseTransaction) RefPtr<V8CustomVoidCallback> successCallback; if (args.Length() > 2) { - if (!args[1]->IsObject()) + if (!args[2]->IsObject()) return throwError("Transaction success callback must be of valid type."); successCallback = V8CustomVoidCallback::create(args[2], frame); } - database->transaction(callback.release(), errorCallback.release(), successCallback.release()); - + database->transaction(callback.release(), errorCallback.release(), successCallback.release(), readOnly); return v8::Undefined(); } +CALLBACK_FUNC_DECL(DatabaseTransaction) +{ + INC_STATS("DOM.Database.transaction()"); + return createTransaction(args, false); +} + +CALLBACK_FUNC_DECL(DatabaseReadTransaction) +{ + INC_STATS("DOM.Database.readTransaction()"); + return createTransaction(args, true); +} + } // namespace WebCore #endif - diff --git a/WebCore/bindings/v8/custom/V8DedicatedWorkerContextCustom.cpp b/WebCore/bindings/v8/custom/V8DedicatedWorkerContextCustom.cpp index f13e45e..263c005 100644 --- a/WebCore/bindings/v8/custom/V8DedicatedWorkerContextCustom.cpp +++ b/WebCore/bindings/v8/custom/V8DedicatedWorkerContextCustom.cpp @@ -35,48 +35,26 @@ #include "WorkerContextExecutionProxy.h" #include "DedicatedWorkerContext.h" +#include "V8Binding.h" +#include "V8MessagePortCustom.h" #include "V8Proxy.h" #include "V8WorkerContextEventListener.h" namespace WebCore { -ACCESSOR_GETTER(DedicatedWorkerContextOnmessage) +CALLBACK_FUNC_DECL(DedicatedWorkerContextPostMessage) { - INC_STATS(L"DOM.DedicatedWorkerContext.onmessage._get"); - DedicatedWorkerContext* workerContext = V8DOMWrapper::convertToNativeObject<DedicatedWorkerContext>(V8ClassIndex::DEDICATEDWORKERCONTEXT, info.Holder()); - if (workerContext->onmessage()) { - V8WorkerContextEventListener* listener = static_cast<V8WorkerContextEventListener*>(workerContext->onmessage()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - return v8Listener; - } - return v8::Undefined(); -} - -ACCESSOR_SETTER(DedicatedWorkerContextOnmessage) -{ - INC_STATS(L"DOM.DedicatedWorkerContext.onmessage._set"); - DedicatedWorkerContext* workerContext = V8DOMWrapper::convertToNativeObject<DedicatedWorkerContext>(V8ClassIndex::DEDICATEDWORKERCONTEXT, info.Holder()); - V8WorkerContextEventListener* oldListener = static_cast<V8WorkerContextEventListener*>(workerContext->onmessage()); - if (value->IsNull()) { - if (workerContext->onmessage()) { - v8::Local<v8::Object> oldV8Listener = oldListener->getListenerObject(); - removeHiddenDependency(info.Holder(), oldV8Listener, V8Custom::kDedicatedWorkerContextRequestCacheIndex); - } - - // Clear the listener. - workerContext->setOnmessage(0); - } else { - RefPtr<V8EventListener> listener = workerContext->script()->proxy()->findOrCreateEventListener(v8::Local<v8::Object>::Cast(value), false, false); - if (listener) { - if (oldListener) { - v8::Local<v8::Object> oldV8Listener = oldListener->getListenerObject(); - removeHiddenDependency(info.Holder(), oldV8Listener, V8Custom::kDedicatedWorkerContextRequestCacheIndex); - } - - workerContext->setOnmessage(listener); - createHiddenDependency(info.Holder(), value, V8Custom::kDedicatedWorkerContextRequestCacheIndex); - } + INC_STATS(L"DOM.DedicatedWorkerContext.postMessage"); + DedicatedWorkerContext* workerContext = V8DOMWrapper::convertToNativeObject<DedicatedWorkerContext>(V8ClassIndex::DEDICATEDWORKERCONTEXT, args.Holder()); + RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(v8ValueToWebCoreString(args[0])); + MessagePortArray portArray; + if (args.Length() > 1) { + if (!getMessagePortArray(args[1], portArray)) + return v8::Undefined(); } + ExceptionCode ec = 0; + workerContext->postMessage(message.release(), &portArray, ec); + return throwError(ec); } } // namespace WebCore diff --git a/WebCore/bindings/v8/custom/V8DocumentCustom.cpp b/WebCore/bindings/v8/custom/V8DocumentCustom.cpp index 80d204b..8b77a3a 100644 --- a/WebCore/bindings/v8/custom/V8DocumentCustom.cpp +++ b/WebCore/bindings/v8/custom/V8DocumentCustom.cpp @@ -31,10 +31,12 @@ #include "config.h" #include "Document.h" +#include "CanvasRenderingContext.h" #include "ExceptionCode.h" #include "Node.h" #include "XPathNSResolver.h" #include "XPathResult.h" +#include "CanvasRenderingContext.h" #include "V8Binding.h" #include "V8CustomBinding.h" @@ -62,12 +64,8 @@ CALLBACK_FUNC_DECL(DocumentEvaluate) if (V8Node::HasInstance(args[1])) contextNode = V8DOMWrapper::convertDOMWrapperToNode<Node>(v8::Handle<v8::Object>::Cast(args[1])); - RefPtr<XPathNSResolver> resolver; - if (V8XPathNSResolver::HasInstance(args[2])) - resolver = V8DOMWrapper::convertToNativeObject<XPathNSResolver>(V8ClassIndex::XPATHNSRESOLVER, v8::Handle<v8::Object>::Cast(args[2])); - else if (args[2]->IsObject()) - resolver = V8CustomXPathNSResolver::create(args[2]->ToObject()); - else if (!args[2]->IsNull() && !args[2]->IsUndefined()) + RefPtr<XPathNSResolver> resolver = V8DOMWrapper::getXPathNSResolver(args[2]); + if (!resolver && !args[2]->IsNull() && !args[2]->IsUndefined()) return throwError(TYPE_MISMATCH_ERR); int type = toInt32(args[3]); @@ -99,8 +97,17 @@ CALLBACK_FUNC_DECL(DocumentGetCSSCanvasContext) String name = toWebCoreString(args[1]); int width = toInt32(args[2]); int height = toInt32(args[3]); - CanvasRenderingContext2D* result = imp->getCSSCanvasContext(contextId, name, width, height); - return V8DOMWrapper::convertToV8Object(V8ClassIndex::CANVASRENDERINGCONTEXT2D, result); + CanvasRenderingContext* result = imp->getCSSCanvasContext(contextId, name, width, height); + if (!result) + return v8::Undefined(); + if (result->is2d()) + return V8DOMWrapper::convertToV8Object(V8ClassIndex::CANVASRENDERINGCONTEXT2D, result); +#if ENABLE(3D_CANVAS) + else if (result->is3d()) + return V8DOMWrapper::convertToV8Object(V8ClassIndex::CANVASRENDERINGCONTEXT3D, result); +#endif // ENABLE(3D_CANVAS) + ASSERT_NOT_REACHED(); + return v8::Undefined(); } } // namespace WebCore diff --git a/WebCore/bindings/v8/V8WorkerContextObjectEventListener.cpp b/WebCore/bindings/v8/custom/V8FileListCustom.cpp index ce56563..bc533cf 100644 --- a/WebCore/bindings/v8/V8WorkerContextObjectEventListener.cpp +++ b/WebCore/bindings/v8/custom/V8FileListCustom.cpp @@ -29,31 +29,26 @@ */ #include "config.h" +#include "FileList.h" -#if ENABLE(WORKERS) +#include "File.h" +#include "V8Binding.h" +#include "V8CustomBinding.h" +#include "V8Proxy.h" -#include "V8WorkerContextObjectEventListener.h" - -#include "WorkerContextExecutionProxy.h" +#include <wtf/RefPtr.h> namespace WebCore { -static void weakObjectEventListenerCallback(v8::Persistent<v8::Value>, void* parameter) +INDEXED_PROPERTY_GETTER(FileList) { - V8WorkerContextObjectEventListener* listener = static_cast<V8WorkerContextObjectEventListener*>(parameter); - - // Remove the wrapper - listener->proxy()->removeEventListener(listener); - - listener->disposeListenerObject(); -} + INC_STATS("DOM.FileList.IndexedPropertyGetter"); + FileList* fileList = V8DOMWrapper::convertToNativeObject<FileList>(V8ClassIndex::FILELIST, info.Holder()); + RefPtr<File> file = fileList->item(index); + if (!file) + return notHandledByInterceptor(); -V8WorkerContextObjectEventListener::V8WorkerContextObjectEventListener(WorkerContextExecutionProxy* proxy, v8::Local<v8::Object> listener, bool isInline) - : V8WorkerContextEventListener(proxy, listener, isInline) -{ - m_listener.MakeWeak(this, weakObjectEventListenerCallback); + return V8DOMWrapper::convertToV8Object(V8ClassIndex::FILE, file.release()); } } // namespace WebCore - -#endif // WORKERS diff --git a/WebCore/bindings/v8/custom/V8GeolocationCustom.cpp b/WebCore/bindings/v8/custom/V8GeolocationCustom.cpp index 7bc687c..b4fd9f5 100644 --- a/WebCore/bindings/v8/custom/V8GeolocationCustom.cpp +++ b/WebCore/bindings/v8/custom/V8GeolocationCustom.cpp @@ -130,13 +130,7 @@ static PassRefPtr<PositionOptions> createPositionOptions(v8::Local<v8::Value> va return 0; } double timeoutDouble = timeoutNumber->Value(); - // V8 does not export a public symbol for infinity, so we must use a - // platform type. On Android, it seems that V8 uses 0xf70f000000000000, - // which is the standard way to represent infinity in a double. However, - // numeric_limits<double>::infinity uses the system HUGE_VAL, which is - // different. Therefore we test using isinf() and check that the value - // is positive, which seems to handle things correctly. - // If the value is infinity, there's nothing to do. + // If the value is positive infinity, there's nothing to do. if (!(isinf(timeoutDouble) && timeoutDouble > 0)) { v8::Local<v8::Int32> timeoutInt32 = timeoutValue->ToInt32(); if (timeoutInt32.IsEmpty()) { @@ -161,7 +155,7 @@ static PassRefPtr<PositionOptions> createPositionOptions(v8::Local<v8::Value> va } double maximumAgeDouble = maximumAgeNumber->Value(); if (isinf(maximumAgeDouble) && maximumAgeDouble > 0) { - // If the value is infinity, clear maximumAge. + // If the value is positive infinity, clear maximumAge. options->clearMaximumAge(); } else { v8::Local<v8::Int32> maximumAgeInt32 = maximumAgeValue->ToInt32(); diff --git a/WebCore/bindings/v8/custom/V8HTMLAudioElementConstructor.cpp b/WebCore/bindings/v8/custom/V8HTMLAudioElementConstructor.cpp index 6f9b761..c735c49 100644 --- a/WebCore/bindings/v8/custom/V8HTMLAudioElementConstructor.cpp +++ b/WebCore/bindings/v8/custom/V8HTMLAudioElementConstructor.cpp @@ -29,8 +29,9 @@ */ #include "config.h" -#include "HTMLAudioElement.h" +#include "V8HTMLAudioElementConstructor.h" +#include "HTMLAudioElement.h" #include "Document.h" #include "Frame.h" #include "HTMLNames.h" @@ -42,6 +43,24 @@ namespace WebCore { +v8::Persistent<v8::FunctionTemplate> V8HTMLAudioElementConstructor::GetTemplate() +{ + static v8::Persistent<v8::FunctionTemplate> cachedTemplate; + if (!cachedTemplate.IsEmpty()) + return cachedTemplate; + + v8::HandleScope scope; + v8::Local<v8::FunctionTemplate> result = v8::FunctionTemplate::New(USE_CALLBACK(HTMLAudioElementConstructor)); + + v8::Local<v8::ObjectTemplate> instance = result->InstanceTemplate(); + instance->SetInternalFieldCount(V8Custom::kNodeMinimumInternalFieldCount); + result->SetClassName(v8::String::New("HTMLAudioElement")); + result->Inherit(V8DOMWrapper::getTemplate(V8ClassIndex::HTMLAUDIOELEMENT)); + + cachedTemplate = v8::Persistent<v8::FunctionTemplate>::New(result); + return cachedTemplate; +} + CALLBACK_FUNC_DECL(HTMLAudioElementConstructor) { INC_STATS("DOM.HTMLAudioElement.Contructor"); diff --git a/WebCore/bindings/js/JSSharedWorkerContextCustom.cpp b/WebCore/bindings/v8/custom/V8HTMLAudioElementConstructor.h index dca3536..ac4b46d 100644..100755 --- a/WebCore/bindings/js/JSSharedWorkerContextCustom.cpp +++ b/WebCore/bindings/v8/custom/V8HTMLAudioElementConstructor.h @@ -28,23 +28,20 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" +#ifndef V8HTMLAudioElementConstructor_h +#define V8HTMLAudioElementConstructor_h -#if ENABLE(SHARED_WORKERS) - -#include "JSSharedWorkerContext.h" - -using namespace JSC; +#include <v8.h> namespace WebCore { -void JSSharedWorkerContext::markChildren(MarkStack& markStack) -{ - Base::markChildren(markStack); +class V8HTMLAudioElementConstructor { +private: + static v8::Persistent<v8::FunctionTemplate> GetTemplate(); - markIfNotNull(markStack, impl()->onconnect()); -} + friend class V8ClassIndex; +}; -} // namespace WebCore +} -#endif // ENABLE(SHARED_WORKERS) +#endif // V8HTMLAudioElementConstructor_h diff --git a/WebCore/bindings/v8/custom/V8HTMLCanvasElementCustom.cpp b/WebCore/bindings/v8/custom/V8HTMLCanvasElementCustom.cpp index 6ba9367..4116673 100644 --- a/WebCore/bindings/v8/custom/V8HTMLCanvasElementCustom.cpp +++ b/WebCore/bindings/v8/custom/V8HTMLCanvasElementCustom.cpp @@ -30,7 +30,9 @@ #include "config.h" #include "HTMLCanvasElement.h" +#include "CanvasRenderingContext.h" +#include "CanvasRenderingContext.h" #include "V8Binding.h" #include "V8CustomBinding.h" #include "V8Node.h" @@ -44,8 +46,17 @@ CALLBACK_FUNC_DECL(HTMLCanvasElementGetContext) v8::Handle<v8::Object> holder = args.Holder(); HTMLCanvasElement* imp = V8DOMWrapper::convertDOMWrapperToNode<HTMLCanvasElement>(holder); String contextId = toWebCoreString(args[0]); - CanvasRenderingContext2D* result = imp->getContext(contextId); - return V8DOMWrapper::convertToV8Object(V8ClassIndex::CANVASRENDERINGCONTEXT2D, result); + CanvasRenderingContext* result = imp->getContext(contextId); + if (!result) + return v8::Undefined(); + if (result->is2d()) + return V8DOMWrapper::convertToV8Object(V8ClassIndex::CANVASRENDERINGCONTEXT2D, result); +#if ENABLE(3D_CANVAS) + else if (result->is3d()) + return V8DOMWrapper::convertToV8Object(V8ClassIndex::CANVASRENDERINGCONTEXT3D, result); +#endif + ASSERT_NOT_REACHED(); + return v8::Undefined(); } } // namespace WebCore diff --git a/WebCore/bindings/v8/custom/V8HTMLFrameElementCustom.cpp b/WebCore/bindings/v8/custom/V8HTMLFrameElementCustom.cpp index 4f865dd..2f55758 100644 --- a/WebCore/bindings/v8/custom/V8HTMLFrameElementCustom.cpp +++ b/WebCore/bindings/v8/custom/V8HTMLFrameElementCustom.cpp @@ -30,6 +30,7 @@ #include "config.h" #include "HTMLFrameElement.h" +#include "HTMLNames.h" #include "V8Binding.h" #include "V8CustomBinding.h" @@ -37,6 +38,8 @@ namespace WebCore { +using namespace HTMLNames; + ACCESSOR_SETTER(HTMLFrameElementSrc) { HTMLFrameElement* frame = V8DOMWrapper::convertDOMWrapperToNode<HTMLFrameElement>(info.Holder()); @@ -45,7 +48,7 @@ ACCESSOR_SETTER(HTMLFrameElementSrc) if (!allowSettingFrameSrcToJavascriptUrl(frame, srcValue)) return; - frame->setSrc(srcValue); + frame->setAttribute(srcAttr, srcValue); } ACCESSOR_SETTER(HTMLFrameElementLocation) diff --git a/WebCore/bindings/v8/custom/V8HTMLIFrameElementCustom.cpp b/WebCore/bindings/v8/custom/V8HTMLIFrameElementCustom.cpp index ce2c29a..a4863e8 100644 --- a/WebCore/bindings/v8/custom/V8HTMLIFrameElementCustom.cpp +++ b/WebCore/bindings/v8/custom/V8HTMLIFrameElementCustom.cpp @@ -30,6 +30,7 @@ #include "config.h" #include "HTMLIFrameElement.h" +#include "HTMLNames.h" #include "V8Binding.h" #include "V8CustomBinding.h" @@ -37,6 +38,8 @@ namespace WebCore { +using namespace HTMLNames; + ACCESSOR_SETTER(HTMLIFrameElementSrc) { HTMLIFrameElement* iframe = V8DOMWrapper::convertDOMWrapperToNode<HTMLIFrameElement>(info.Holder()); @@ -45,7 +48,7 @@ ACCESSOR_SETTER(HTMLIFrameElementSrc) if (!allowSettingFrameSrcToJavascriptUrl(iframe, v)) return; - iframe->setSrc(v); + iframe->setAttribute(srcAttr, v); } } // namespace WebCore diff --git a/WebCore/bindings/v8/custom/V8HTMLImageElementConstructor.cpp b/WebCore/bindings/v8/custom/V8HTMLImageElementConstructor.cpp index 91ebd5f..71c99cf 100644 --- a/WebCore/bindings/v8/custom/V8HTMLImageElementConstructor.cpp +++ b/WebCore/bindings/v8/custom/V8HTMLImageElementConstructor.cpp @@ -29,8 +29,9 @@ */ #include "config.h" -#include "HTMLImageElement.h" +#include "V8HTMLImageElementConstructor.h" +#include "HTMLImageElement.h" #include "Document.h" #include "Frame.h" #include "HTMLNames.h" @@ -42,6 +43,24 @@ namespace WebCore { +v8::Persistent<v8::FunctionTemplate> V8HTMLImageElementConstructor::GetTemplate() +{ + static v8::Persistent<v8::FunctionTemplate> cachedTemplate; + if (!cachedTemplate.IsEmpty()) + return cachedTemplate; + + v8::HandleScope scope; + v8::Local<v8::FunctionTemplate> result = v8::FunctionTemplate::New(USE_CALLBACK(HTMLImageElementConstructor)); + + v8::Local<v8::ObjectTemplate> instance = result->InstanceTemplate(); + instance->SetInternalFieldCount(V8Custom::kNodeMinimumInternalFieldCount); + result->SetClassName(v8::String::New("HTMLImageElement")); + result->Inherit(V8DOMWrapper::getTemplate(V8ClassIndex::HTMLIMAGEELEMENT)); + + cachedTemplate = v8::Persistent<v8::FunctionTemplate>::New(result); + return cachedTemplate; +} + CALLBACK_FUNC_DECL(HTMLImageElementConstructor) { INC_STATS("DOM.HTMLImageElement.Contructor"); diff --git a/WebCore/bindings/v8/V8WorkerContextObjectEventListener.h b/WebCore/bindings/v8/custom/V8HTMLImageElementConstructor.h index 6471637..cdce0e0 100644..100755 --- a/WebCore/bindings/v8/V8WorkerContextObjectEventListener.h +++ b/WebCore/bindings/v8/custom/V8HTMLImageElementConstructor.h @@ -28,32 +28,20 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef V8WorkerContextObjectEventListener_h -#define V8WorkerContextObjectEventListener_h +#ifndef V8HTMLImageElementConstructor_h +#define V8HTMLImageElementConstructor_h -#if ENABLE(WORKERS) - -#include "V8WorkerContextEventListener.h" #include <v8.h> -#include <wtf/PassRefPtr.h> namespace WebCore { - class WorkerContextExecutionProxy; - - class V8WorkerContextObjectEventListener : public V8WorkerContextEventListener { - public: - static PassRefPtr<V8WorkerContextObjectEventListener> create(WorkerContextExecutionProxy* proxy, v8::Local<v8::Object> listener, bool isInline) - { - return adoptRef(new V8WorkerContextObjectEventListener(proxy, listener, isInline)); - } - + class V8HTMLImageElementConstructor { private: - V8WorkerContextObjectEventListener(WorkerContextExecutionProxy*, v8::Local<v8::Object> listener, bool isInline); - }; + static v8::Persistent<v8::FunctionTemplate> GetTemplate(); -} // namespace WebCore + friend class V8ClassIndex; + }; -#endif // WORKERS +} -#endif // V8WorkerContextObjectEventListener_h +#endif // V8HTMLImageElementConstructor_h diff --git a/WebCore/bindings/v8/custom/V8HTMLOptionElementConstructor.cpp b/WebCore/bindings/v8/custom/V8HTMLOptionElementConstructor.cpp index c22d127..f9c9cb4 100644 --- a/WebCore/bindings/v8/custom/V8HTMLOptionElementConstructor.cpp +++ b/WebCore/bindings/v8/custom/V8HTMLOptionElementConstructor.cpp @@ -29,8 +29,9 @@ */ #include "config.h" -#include "HTMLOptionElement.h" +#include "V8HTMLOptionElementConstructor.h" +#include "HTMLOptionElement.h" #include "Document.h" #include "Frame.h" #include "HTMLNames.h" @@ -43,6 +44,24 @@ namespace WebCore { +v8::Persistent<v8::FunctionTemplate> V8HTMLOptionElementConstructor::GetTemplate() +{ + static v8::Persistent<v8::FunctionTemplate> cachedTemplate; + if (!cachedTemplate.IsEmpty()) + return cachedTemplate; + + v8::HandleScope scope; + v8::Local<v8::FunctionTemplate> result = v8::FunctionTemplate::New(USE_CALLBACK(HTMLOptionElementConstructor)); + + v8::Local<v8::ObjectTemplate> instance = result->InstanceTemplate(); + instance->SetInternalFieldCount(V8Custom::kNodeMinimumInternalFieldCount); + result->SetClassName(v8::String::New("HTMLOptionElement")); + result->Inherit(V8DOMWrapper::getTemplate(V8ClassIndex::HTMLOPTIONELEMENT)); + + cachedTemplate = v8::Persistent<v8::FunctionTemplate>::New(result); + return cachedTemplate; +} + CALLBACK_FUNC_DECL(HTMLOptionElementConstructor) { INC_STATS("DOM.HTMLOptionElement.Contructor"); diff --git a/WebCore/bindings/v8/custom/V8HTMLOptionElementConstructor.h b/WebCore/bindings/v8/custom/V8HTMLOptionElementConstructor.h new file mode 100755 index 0000000..70076a5 --- /dev/null +++ b/WebCore/bindings/v8/custom/V8HTMLOptionElementConstructor.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef V8HTMLOptionElementConstructor_h +#define V8HTMLOptionElementConstructor_h + +#include <v8.h> + +namespace WebCore { + + class V8HTMLOptionElementConstructor { + private: + static v8::Persistent<v8::FunctionTemplate> GetTemplate(); + + friend class V8ClassIndex; + }; + +} + +#endif // V8HTMLOptionElementConstructor_h diff --git a/WebCore/bindings/v8/custom/V8InspectorBackendCustom.cpp b/WebCore/bindings/v8/custom/V8InspectorBackendCustom.cpp index 2571df4..ec9b034 100644 --- a/WebCore/bindings/v8/custom/V8InspectorBackendCustom.cpp +++ b/WebCore/bindings/v8/custom/V8InspectorBackendCustom.cpp @@ -31,6 +31,7 @@ #include "config.h" #include "InspectorBackend.h" +#include "Database.h" #include "DOMWindow.h" #include "Frame.h" #include "FrameLoader.h" @@ -57,13 +58,8 @@ CALLBACK_FUNC_DECL(InspectorBackendHighlightDOMNode) if (args.Length() < 1) return v8::Undefined(); - Node* node = V8DOMWrapper::convertDOMWrapperToNode<Node>(v8::Handle<v8::Object>::Cast(args[0])); - if (!node) - return v8::Undefined(); - InspectorBackend* inspectorBackend = V8DOMWrapper::convertToNativeObject<InspectorBackend>(V8ClassIndex::INSPECTORBACKEND, args.Holder()); - inspectorBackend->highlight(node); - + inspectorBackend->highlight(args[0]->ToInt32()->Value()); return v8::Undefined(); } @@ -107,11 +103,17 @@ CALLBACK_FUNC_DECL(InspectorBackendSearch) } #if ENABLE(DATABASE) -CALLBACK_FUNC_DECL(InspectorBackendDatabaseTableNames) +CALLBACK_FUNC_DECL(InspectorBackendDatabaseForId) { - INC_STATS("InspectorBackend.databaseTableNames()"); - v8::Local<v8::Array> result = v8::Array::New(0); - return result; + INC_STATS("InspectorBackend.databaseForId()"); + if (args.Length() < 1) + return v8::Undefined(); + + InspectorBackend* inspectorBackend = V8DOMWrapper::convertToNativeObject<InspectorBackend>(V8ClassIndex::INSPECTORBACKEND, args.Holder()); + Database* database = inspectorBackend->databaseForId(args[0]->ToInt32()->Value()); + if (!database) + return v8::Undefined(); + return V8DOMWrapper::convertToV8Object<Database>(V8ClassIndex::DATABASE, database); } #endif @@ -215,4 +217,90 @@ CALLBACK_FUNC_DECL(InspectorBackendWrapCallback) return args[0]; } +CALLBACK_FUNC_DECL(InspectorBackendNodeForId) +{ + INC_STATS("InspectorBackend.nodeForId()"); + if (args.Length() < 1) + return v8::Undefined(); + + InspectorBackend* inspectorBackend = V8DOMWrapper::convertToNativeObject<InspectorBackend>(V8ClassIndex::INSPECTORBACKEND, args.Holder()); + + Node* node = inspectorBackend->nodeForId(args[0]->ToInt32()->Value()); + if (!node) + return v8::Undefined(); + + InspectorController* ic = inspectorBackend->inspectorController(); + if (!ic) + return v8::Undefined(); + + return V8DOMWrapper::convertToV8Object(V8ClassIndex::NODE, node); +} + +CALLBACK_FUNC_DECL(InspectorBackendWrapObject) +{ + INC_STATS("InspectorBackend.wrapObject()"); + if (args.Length() < 2) + return v8::Undefined(); + + InspectorBackend* inspectorBackend = V8DOMWrapper::convertToNativeObject<InspectorBackend>(V8ClassIndex::INSPECTORBACKEND, args.Holder()); + return inspectorBackend->wrapObject(ScriptValue(args[0]), toWebCoreStringWithNullCheck(args[1])).v8Value(); +} + +CALLBACK_FUNC_DECL(InspectorBackendUnwrapObject) +{ + INC_STATS("InspectorBackend.unwrapObject()"); + if (args.Length() < 1) + return v8::Undefined(); + + InspectorBackend* inspectorBackend = V8DOMWrapper::convertToNativeObject<InspectorBackend>(V8ClassIndex::INSPECTORBACKEND, args.Holder()); + return inspectorBackend->unwrapObject(toWebCoreStringWithNullCheck(args[0])).v8Value(); +} + +CALLBACK_FUNC_DECL(InspectorBackendPushNodePathToFrontend) +{ + INC_STATS("InspectorBackend.pushNodePathToFrontend()"); + if (args.Length() < 2) + return v8::Undefined(); + + InspectorBackend* inspectorBackend = V8DOMWrapper::convertToNativeObject<InspectorBackend>(V8ClassIndex::INSPECTORBACKEND, args.Holder()); + Node* node = V8DOMWrapper::convertDOMWrapperToNode<Node>(v8::Handle<v8::Object>::Cast(args[0])); + bool selectInUI = args[1]->ToBoolean()->Value(); + if (node) + return v8::Number::New(inspectorBackend->pushNodePathToFrontend(node, selectInUI)); + + return v8::Undefined(); +} + +#if ENABLE(DATABASE) +CALLBACK_FUNC_DECL(InspectorBackendSelectDatabase) +{ + INC_STATS("InspectorBackend.selectDatabase()"); + if (args.Length() < 1) + return v8::Undefined(); + + InspectorBackend* inspectorBackend = V8DOMWrapper::convertToNativeObject<InspectorBackend>(V8ClassIndex::INSPECTORBACKEND, args.Holder()); + Database* database = V8DOMWrapper::convertToNativeObject<Database>(V8ClassIndex::DATABASE, v8::Handle<v8::Object>::Cast(args[0])); + if (database) + inspectorBackend->selectDatabase(database); + + return v8::Undefined(); +} +#endif + +#if ENABLE(DOM_STORAGE) +CALLBACK_FUNC_DECL(InspectorBackendSelectDOMStorage) +{ + INC_STATS("InspectorBackend.selectDOMStorage()"); + if (args.Length() < 1) + return v8::Undefined(); + + InspectorBackend* inspectorBackend = V8DOMWrapper::convertToNativeObject<InspectorBackend>(V8ClassIndex::INSPECTORBACKEND, args.Holder()); + Storage* storage = V8DOMWrapper::convertToNativeObject<Storage>(V8ClassIndex::STORAGE, v8::Handle<v8::Object>::Cast(args[0])); + if (storage) + inspectorBackend->selectDOMStorage(storage); + + return v8::Undefined(); +} +#endif + } // namespace WebCore diff --git a/WebCore/bindings/v8/custom/V8LocationCustom.cpp b/WebCore/bindings/v8/custom/V8LocationCustom.cpp index 3f3ff6b..1ed4c51 100644 --- a/WebCore/bindings/v8/custom/V8LocationCustom.cpp +++ b/WebCore/bindings/v8/custom/V8LocationCustom.cpp @@ -128,13 +128,13 @@ ACCESSOR_SETTER(LocationHref) if (!frame) return; - if (!shouldAllowNavigation(frame)) - return; - KURL url = completeURL(toWebCoreString(value)); if (url.isNull()) return; + if (!shouldAllowNavigation(frame)) + return; + navigateIfAllowed(frame, url, false, false); } @@ -274,7 +274,7 @@ CALLBACK_FUNC_DECL(LocationReload) return v8::Undefined(); if (!protocolIsJavaScript(frame->loader()->url())) - frame->loader()->scheduleRefresh(processingUserGesture()); + frame->redirectScheduler()->scheduleRefresh(processingUserGesture()); return v8::Undefined(); } @@ -288,13 +288,13 @@ CALLBACK_FUNC_DECL(LocationReplace) if (!frame) return v8::Undefined(); - if (!shouldAllowNavigation(frame)) - return v8::Undefined(); - KURL url = completeURL(toWebCoreString(args[0])); if (url.isNull()) return v8::Undefined(); + if (!shouldAllowNavigation(frame)) + return v8::Undefined(); + navigateIfAllowed(frame, url, true, true); return v8::Undefined(); } @@ -309,13 +309,13 @@ CALLBACK_FUNC_DECL(LocationAssign) if (!frame) return v8::Undefined(); - if (!shouldAllowNavigation(frame)) - return v8::Undefined(); - KURL url = completeURL(toWebCoreString(args[0])); if (url.isNull()) return v8::Undefined(); + if (!shouldAllowNavigation(frame)) + return v8::Undefined(); + navigateIfAllowed(frame, url, false, false); return v8::Undefined(); } diff --git a/WebCore/bindings/v8/custom/V8MessageChannelConstructor.cpp b/WebCore/bindings/v8/custom/V8MessageChannelConstructor.cpp index f45aecf..ca02b16 100644 --- a/WebCore/bindings/v8/custom/V8MessageChannelConstructor.cpp +++ b/WebCore/bindings/v8/custom/V8MessageChannelConstructor.cpp @@ -36,6 +36,7 @@ #include "Document.h" #include "Frame.h" +#include "V8Utilities.h" #include "WorkerContext.h" #include "WorkerContextExecutionProxy.h" @@ -52,16 +53,9 @@ CALLBACK_FUNC_DECL(MessageChannelConstructor) return throwError("DOM object constructor cannot be called as a function."); // Get the ScriptExecutionContext (WorkerContext or Document) - ScriptExecutionContext* context = 0; - WorkerContextExecutionProxy* proxy = WorkerContextExecutionProxy::retrieve(); - if (proxy) - context = proxy->workerContext(); - else { - Frame* frame = V8Proxy::retrieveFrameForCurrentContext(); - if (!frame) - return v8::Undefined(); - context = frame->document(); - } + ScriptExecutionContext* context = getScriptExecutionContext(); + if (!context) + return v8::Undefined(); // Note: it's OK to let this RefPtr go out of scope because we also call // SetDOMWrapper(), which effectively holds a reference to obj. diff --git a/WebCore/bindings/v8/custom/V8MessageEventCustom.cpp b/WebCore/bindings/v8/custom/V8MessageEventCustom.cpp new file mode 100644 index 0000000..c5af635 --- /dev/null +++ b/WebCore/bindings/v8/custom/V8MessageEventCustom.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "MessageEvent.h" +#include "SerializedScriptValue.h" + +#include "V8Binding.h" +#include "V8CustomBinding.h" +#include "V8DOMWindow.h" +#include "V8MessagePortCustom.h" +#include "V8Proxy.h" + +namespace WebCore { + +ACCESSOR_GETTER(MessageEventPorts) +{ + INC_STATS("DOM.MessageEvent.ports"); + MessageEvent* event = V8DOMWrapper::convertToNativeObject<MessageEvent>(V8ClassIndex::MESSAGEEVENT, info.Holder()); + + MessagePortArray* ports = event->ports(); + if (!ports || ports->isEmpty()) + return v8::Null(); + + v8::Local<v8::Array> portArray = v8::Array::New(ports->size()); + for (size_t i = 0; i < ports->size(); ++i) + portArray->Set(v8::Integer::New(i), V8DOMWrapper::convertToV8Object(V8ClassIndex::MESSAGEPORT, (*ports)[i].get())); + + return portArray; +} + +CALLBACK_FUNC_DECL(MessageEventInitMessageEvent) +{ + INC_STATS("DOM.MessageEvent.initMessageEvent"); + MessageEvent* event = V8DOMWrapper::convertToNativeObject<MessageEvent>(V8ClassIndex::MESSAGEEVENT, args.Holder()); + String typeArg = v8ValueToWebCoreString(args[0]); + bool canBubbleArg = args[1]->BooleanValue(); + bool cancelableArg = args[2]->BooleanValue(); + RefPtr<SerializedScriptValue> dataArg = SerializedScriptValue::create(v8ValueToWebCoreString(args[3])); + String originArg = v8ValueToWebCoreString(args[4]); + String lastEventIdArg = v8ValueToWebCoreString(args[5]); + DOMWindow* sourceArg = V8DOMWindow::HasInstance(args[6]) ? V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, v8::Handle<v8::Object>::Cast(args[6])) : 0; + OwnPtr<MessagePortArray> portArray; + + if (!isUndefinedOrNull(args[7])) { + portArray = new MessagePortArray(); + if (!getMessagePortArray(args[7], *portArray)) + return v8::Undefined(); + } + event->initMessageEvent(typeArg, canBubbleArg, cancelableArg, dataArg.release(), originArg, lastEventIdArg, sourceArg, portArray.release()); + return v8::Undefined(); + } + +} // namespace WebCore diff --git a/WebCore/bindings/v8/custom/V8MessagePortCustom.cpp b/WebCore/bindings/v8/custom/V8MessagePortCustom.cpp index 95d248c..0d8631f 100644 --- a/WebCore/bindings/v8/custom/V8MessagePortCustom.cpp +++ b/WebCore/bindings/v8/custom/V8MessagePortCustom.cpp @@ -32,66 +32,22 @@ #include "ExceptionCode.h" #include "MessagePort.h" +#include "SerializedScriptValue.h" #include "V8Binding.h" #include "V8CustomBinding.h" -#include "V8ObjectEventListener.h" +#include "V8MessagePortCustom.h" +#include "V8MessagePort.h" #include "V8Proxy.h" #include "V8Utilities.h" #include "WorkerContextExecutionProxy.h" namespace WebCore { -PassRefPtr<EventListener> getEventListener(MessagePort* messagePort, v8::Local<v8::Value> value, bool findOnly, bool createObjectEventListener) -{ - V8Proxy* proxy = V8Proxy::retrieve(messagePort->scriptExecutionContext()); - if (proxy) { - V8EventListenerList* list = proxy->objectListeners(); - return findOnly ? list->findWrapper(value, false) : list->findOrCreateWrapper<V8ObjectEventListener>(proxy->frame(), value, false); - } - -#if ENABLE(WORKERS) - WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); - if (workerContextProxy) - return workerContextProxy->findOrCreateEventListenerHelper(value, false, findOnly, createObjectEventListener); -#endif - - return PassRefPtr<EventListener>(); -} - -ACCESSOR_GETTER(MessagePortOnmessage) -{ - INC_STATS("DOM.MessagePort.onmessage._get"); - MessagePort* messagePort = V8DOMWrapper::convertToNativeObject<MessagePort>(V8ClassIndex::MESSAGEPORT, info.Holder()); - return V8DOMWrapper::convertEventListenerToV8Object(messagePort->onmessage()); -} - -ACCESSOR_SETTER(MessagePortOnmessage) -{ - INC_STATS("DOM.MessagePort.onmessage._set"); - MessagePort* messagePort = V8DOMWrapper::convertToNativeObject<MessagePort>(V8ClassIndex::MESSAGEPORT, info.Holder()); - if (value->IsNull()) { - if (messagePort->onmessage()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(messagePort->onmessage()); - removeHiddenDependency(info.Holder(), listener->getListenerObject(), V8Custom::kMessagePortRequestCacheIndex); - } - - // Clear the listener. - messagePort->setOnmessage(0); - - } else { - RefPtr<EventListener> listener = getEventListener(messagePort, value, false, false); - if (listener) { - messagePort->setOnmessage(listener); - createHiddenDependency(info.Holder(), value, V8Custom::kMessagePortRequestCacheIndex); - } - } -} - CALLBACK_FUNC_DECL(MessagePortAddEventListener) { INC_STATS("DOM.MessagePort.addEventListener()"); MessagePort* messagePort = V8DOMWrapper::convertToNativeObject<MessagePort>(V8ClassIndex::MESSAGEPORT, args.Holder()); - RefPtr<EventListener> listener = getEventListener(messagePort, args[1], false, true); + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(messagePort, args[1], false, ListenerFindOrCreate); if (listener) { String type = toWebCoreString(args[0]); bool useCapture = args[2]->BooleanValue(); @@ -106,7 +62,7 @@ CALLBACK_FUNC_DECL(MessagePortRemoveEventListener) { INC_STATS("DOM.MessagePort.removeEventListener()"); MessagePort* messagePort = V8DOMWrapper::convertToNativeObject<MessagePort>(V8ClassIndex::MESSAGEPORT, args.Holder()); - RefPtr<EventListener> listener = getEventListener(messagePort, args[1], true, true); + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(messagePort, args[1], false, ListenerFindOnly); if (listener) { String type = toWebCoreString(args[0]); bool useCapture = args[2]->BooleanValue(); @@ -118,4 +74,64 @@ CALLBACK_FUNC_DECL(MessagePortRemoveEventListener) return v8::Undefined(); } +CALLBACK_FUNC_DECL(MessagePortPostMessage) +{ + INC_STATS("DOM.MessagePort.postMessage"); + MessagePort* messagePort = V8DOMWrapper::convertToNativeObject<MessagePort>(V8ClassIndex::MESSAGEPORT, args.Holder()); + RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(toWebCoreString(args[0])); + MessagePortArray portArray; + if (args.Length() > 1) { + if (!getMessagePortArray(args[1], portArray)) + return v8::Undefined(); + } + ExceptionCode ec = 0; + messagePort->postMessage(message.release(), &portArray, ec); + return throwError(ec); +} + +bool getMessagePortArray(v8::Local<v8::Value> value, MessagePortArray& portArray) +{ + if (isUndefinedOrNull(value)) { + portArray.resize(0); + return true; + } + + if (!value->IsObject()) { + throwError("MessagePortArray argument must be an object"); + return false; + } + uint32_t length = 0; + v8::Local<v8::Object> ports = v8::Local<v8::Object>::Cast(value); + + if (value->IsArray()) { + v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(value); + length = array->Length(); + } else { + // Sequence-type object - get the length attribute + v8::Local<v8::Value> sequenceLength = ports->Get(v8::String::New("length")); + if (!sequenceLength->IsNumber()) { + throwError("MessagePortArray argument has no length attribute"); + return false; + } + length = sequenceLength->Uint32Value(); + } + portArray.resize(length); + + for (unsigned int i = 0; i < length; ++i) { + v8::Local<v8::Value> port = ports->Get(v8::Integer::New(i)); + // Validation of non-null objects, per HTML5 spec 8.3.3. + if (isUndefinedOrNull(port)) { + throwError(INVALID_STATE_ERR); + return false; + } + // Validation of Objects implementing an interface, per WebIDL spec 4.1.15. + if (!V8MessagePort::HasInstance(port)) { + throwError("MessagePortArray argument must contain only MessagePorts"); + return false; + } + portArray[i] = V8DOMWrapper::convertToNativeObject<MessagePort>(V8ClassIndex::MESSAGEPORT, v8::Handle<v8::Object>::Cast(port)); + } + return true; +} + } // namespace WebCore diff --git a/WebCore/bindings/v8/V8ObjectEventListener.h b/WebCore/bindings/v8/custom/V8MessagePortCustom.h index 3c5ae10..7ab502b 100644 --- a/WebCore/bindings/v8/V8ObjectEventListener.h +++ b/WebCore/bindings/v8/custom/V8MessagePortCustom.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2006, 2007, 2008, 2009 Google Inc. All rights reserved. + * Copyright (c) 2008, 2009 Google Inc. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -28,32 +29,20 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef V8ObjectEventListener_h -#define V8ObjectEventListener_h +#ifndef V8MessagePortCustom_h +#define V8MessagePortCustom_h -#include "V8CustomEventListener.h" #include <v8.h> -#include <wtf/PassRefPtr.h> -namespace WebCore { - - class Frame; +#include "MessagePort.h" - // V8ObjectEventListener is a special listener wrapper for objects not in the DOM. It keeps the JS listener as a weak pointer. - class V8ObjectEventListener : public V8EventListener { - public: - static PassRefPtr<V8ObjectEventListener> create(Frame* frame, v8::Local<v8::Object> listener, bool isInline) - { - return adoptRef(new V8ObjectEventListener(frame, listener, isInline)); - } - - virtual bool isObjectListener() const { return true; } +namespace WebCore { - private: - V8ObjectEventListener(Frame*, v8::Local<v8::Object> listener, bool isInline); - virtual ~V8ObjectEventListener(); - }; + // Helper function which pulls the values out of a JS sequence and into a MessagePortArray. + // Also validates the elements per sections 4.1.13 and 4.1.15 of the WebIDL spec and section 8.3.3 of the HTML5 spec and generates exceptions as appropriate. + // Returns true if the array was filled, or false if the passed value was not of an appropriate type. + bool getMessagePortArray(v8::Local<v8::Value>, MessagePortArray&); } // namespace WebCore -#endif // V8ObjectEventListener_h +#endif // V8MessagePortCustom_h diff --git a/WebCore/bindings/v8/custom/V8NodeCustom.cpp b/WebCore/bindings/v8/custom/V8NodeCustom.cpp index 6b0d740..9b4b9aa 100644 --- a/WebCore/bindings/v8/custom/V8NodeCustom.cpp +++ b/WebCore/bindings/v8/custom/V8NodeCustom.cpp @@ -39,76 +39,18 @@ #include "V8CustomBinding.h" #include "V8CustomEventListener.h" #include "V8Node.h" -#include "V8ObjectEventListener.h" #include "V8Proxy.h" #include <wtf/RefPtr.h> namespace WebCore { -static inline String toEventType(v8::Local<v8::String> value) -{ - String key = toWebCoreString(value); - ASSERT(key.startsWith("on")); - return key.substring(2); -} - -static PassRefPtr<EventListener> getEventListener(Node* node, v8::Local<v8::Value> value, bool isAttribute, bool findOnly) -{ - V8Proxy* proxy = V8Proxy::retrieve(node->scriptExecutionContext()); - // The document might be created using createDocument, which does - // not have a frame, use the active frame. - if (!proxy) - proxy = V8Proxy::retrieve(V8Proxy::retrieveFrameForEnteredContext()); - - if (proxy) { - V8EventListenerList* list = proxy->objectListeners(); - return findOnly ? list->findWrapper(value, isAttribute) : list->findOrCreateWrapper<V8ObjectEventListener>(proxy->frame(), value, isAttribute); - } - - return 0; -} - -ACCESSOR_SETTER(NodeEventHandler) -{ - Node* node = V8DOMWrapper::convertDOMWrapperToNode<Node>(info.Holder()); - String eventType = toEventType(name); - - // Remove hidden dependency on the old event handler. - if (EventListener* listener = node->getAttributeEventListener(eventType)) { - if (static_cast<V8AbstractEventListener*>(listener)->isObjectListener()) { - v8::Local<v8::Object> v8Listener = static_cast<V8ObjectEventListener*>(listener)->getListenerObject(); - removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kNodeEventListenerCacheIndex); - } - } - - // Set handler if the value is a function. - if (value->IsFunction()) { - RefPtr<EventListener> listener = getEventListener(node, value, true, false); - if (listener) { - node->setAttributeEventListener(eventType, listener); - createHiddenDependency(info.Holder(), value, V8Custom::kNodeEventListenerCacheIndex); - } - } else { - // Otherwise, clear the handler. - node->clearAttributeEventListener(eventType); - } -} - -ACCESSOR_GETTER(NodeEventHandler) -{ - Node* node = V8DOMWrapper::convertDOMWrapperToNode<Node>(info.Holder()); - - EventListener* listener = node->getAttributeEventListener(toEventType(name)); - return V8DOMWrapper::convertEventListenerToV8Object(listener); -} - CALLBACK_FUNC_DECL(NodeAddEventListener) { INC_STATS("DOM.Node.addEventListener()"); Node* node = V8DOMWrapper::convertDOMWrapperToNode<Node>(args.Holder()); - RefPtr<EventListener> listener = getEventListener(node, args[1], false, false); + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(node, args[1], false, ListenerFindOrCreate); if (listener) { String type = toWebCoreString(args[0]); bool useCapture = args[2]->BooleanValue(); @@ -126,9 +68,9 @@ CALLBACK_FUNC_DECL(NodeRemoveEventListener) // It is possbile that the owner document of the node is detached // from the frame. // See issue http://b/878909 - RefPtr<EventListener> listener = getEventListener(node, args[1], false, true); + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(node, args[1], false, ListenerFindOnly); if (listener) { - String type = toWebCoreString(args[0]); + AtomicString type = v8ValueToAtomicWebCoreString(args[0]); bool useCapture = args[2]->BooleanValue(); node->removeEventListener(type, listener.get(), useCapture); removeHiddenDependency(args.Holder(), args[1], V8Custom::kNodeEventListenerCacheIndex); diff --git a/WebCore/bindings/v8/custom/V8NotificationCenterCustom.cpp b/WebCore/bindings/v8/custom/V8NotificationCenterCustom.cpp new file mode 100644 index 0000000..bd5fb4a --- /dev/null +++ b/WebCore/bindings/v8/custom/V8NotificationCenterCustom.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(NOTIFICATIONS) + +#include "NotImplemented.h" +#include "Notification.h" +#include "NotificationCenter.h" +#include "V8Binding.h" +#include "V8CustomBinding.h" +#include "V8CustomEventListener.h" +#include "V8CustomVoidCallback.h" +#include "V8Proxy.h" +#include "V8Utilities.h" +#include "WorkerContext.h" +#include "WorkerContextExecutionProxy.h" + +namespace WebCore { + +CALLBACK_FUNC_DECL(NotificationAddEventListener) +{ + INC_STATS("DOM.Notification.addEventListener()"); + Notification* notification = V8DOMWrapper::convertToNativeObject<Notification>(V8ClassIndex::NOTIFICATION, args.Holder()); + + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(notification, args[1], false, ListenerFindOrCreate); + if (listener) { + String type = toWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + notification->addEventListener(type, listener, useCapture); + createHiddenDependency(args.Holder(), args[1], V8Custom::kNotificationRequestCacheIndex); + } + + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(NotificationRemoveEventListener) +{ + INC_STATS("DOM.Notification.removeEventListener()"); + Notification* notification = V8DOMWrapper::convertToNativeObject<Notification>(V8ClassIndex::NOTIFICATION, args.Holder()); + + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(notification, args[1], false, ListenerFindOnly); + if (listener) { + String type = toWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + notification->removeEventListener(type, listener.get(), useCapture); + removeHiddenDependency(args.Holder(), args[1], V8Custom::kNotificationRequestCacheIndex); + } + + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(NotificationCenterCreateHTMLNotification) +{ + INC_STATS(L"DOM.NotificationCenter.CreateHTMLNotification()"); + NotificationCenter* notificationCenter = V8DOMWrapper::convertToNativeObject<NotificationCenter>(V8ClassIndex::NOTIFICATIONCENTER, args.Holder()); + ScriptExecutionContext* context = notificationCenter->context(); + ExceptionCode ec = 0; + String url = toWebCoreString(args[0]); + RefPtr<Notification> notification = Notification::create(url, context, ec, notificationCenter->presenter()); + + if (ec) + return throwError(ec); + + if (context->isWorkerContext()) + return WorkerContextExecutionProxy::convertToV8Object(V8ClassIndex::NOTIFICATION, notification.get()); + + return V8DOMWrapper::convertToV8Object(V8ClassIndex::NOTIFICATION, notification.get()); +} + +CALLBACK_FUNC_DECL(NotificationCenterCreateNotification) +{ + INC_STATS(L"DOM.NotificationCenter.CreateNotification()"); + NotificationCenter* notificationCenter = V8DOMWrapper::convertToNativeObject<NotificationCenter>(V8ClassIndex::NOTIFICATIONCENTER, args.Holder()); + NotificationContents contents(toWebCoreString(args[0]), toWebCoreString(args[1]), toWebCoreString(args[2])); + + ScriptExecutionContext* context = notificationCenter->context(); + ExceptionCode ec = 0; + RefPtr<Notification> notification = Notification::create(contents, context, ec, notificationCenter->presenter()); + + if (ec) + return throwError(ec); + + if (context->isWorkerContext()) + return WorkerContextExecutionProxy::convertToV8Object(V8ClassIndex::NOTIFICATION, notification.get()); + + return V8DOMWrapper::convertToV8Object(V8ClassIndex::NOTIFICATION, notification.get()); +} + +CALLBACK_FUNC_DECL(NotificationCenterRequestPermission) +{ + INC_STATS(L"DOM.NotificationCenter.RequestPermission()"); + NotificationCenter* notificationCenter = V8DOMWrapper::convertToNativeObject<NotificationCenter>(V8ClassIndex::NOTIFICATIONCENTER, args.Holder()); + ScriptExecutionContext* context = notificationCenter->context(); + + // Requesting permission is only valid from a page context. + if (context->isWorkerContext()) + return throwError(NOT_SUPPORTED_ERR); + + RefPtr<V8CustomVoidCallback> callback; + if (args.Length() > 0) { + if (!args[0]->IsObject()) + return throwError("Callback must be of valid type.", V8Proxy::TypeError); + + callback = V8CustomVoidCallback::create(args[0], V8Proxy::retrieveFrameForCurrentContext()); + } + + notificationCenter->requestPermission(callback.release()); + return v8::Undefined(); +} + + +} // namespace WebCore + +#endif // ENABLE(NOTIFICATIONS) diff --git a/WebCore/bindings/v8/custom/V8SVGElementInstanceCustom.cpp b/WebCore/bindings/v8/custom/V8SVGElementInstanceCustom.cpp index ce9c345..dff4ff4 100644 --- a/WebCore/bindings/v8/custom/V8SVGElementInstanceCustom.cpp +++ b/WebCore/bindings/v8/custom/V8SVGElementInstanceCustom.cpp @@ -49,15 +49,12 @@ CALLBACK_FUNC_DECL(SVGElementInstanceAddEventListener) INC_STATS("DOM.SVGElementInstance.AddEventListener()"); SVGElementInstance* instance = V8DOMWrapper::convertDOMWrapperToNative<SVGElementInstance>(args.Holder()); - V8Proxy* proxy = V8Proxy::retrieve(instance->scriptExecutionContext()); - if (!proxy) - return v8::Undefined(); - - RefPtr<EventListener> listener = proxy->eventListeners()->findOrCreateWrapper<V8EventListener>(proxy->frame(), args[1], false); + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(instance, args[1], false, ListenerFindOrCreate); if (listener) { String type = toWebCoreString(args[0]); bool useCapture = args[2]->BooleanValue(); instance->addEventListener(type, listener, useCapture); + createHiddenDependency(args.Holder(), args[1], V8Custom::kNodeEventListenerCacheIndex); } return v8::Undefined(); @@ -68,15 +65,12 @@ CALLBACK_FUNC_DECL(SVGElementInstanceRemoveEventListener) INC_STATS("DOM.SVGElementInstance.RemoveEventListener()"); SVGElementInstance* instance = V8DOMWrapper::convertDOMWrapperToNative<SVGElementInstance>(args.Holder()); - V8Proxy* proxy = V8Proxy::retrieve(instance->scriptExecutionContext()); - if (!proxy) - return v8::Undefined(); - - RefPtr<EventListener> listener = proxy->eventListeners()->findWrapper(args[1], false); + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(instance, args[1], false, ListenerFindOnly); if (listener) { String type = toWebCoreString(args[0]); bool useCapture = args[2]->BooleanValue(); instance->removeEventListener(type, listener.get(), useCapture); + removeHiddenDependency(args.Holder(), args[1], V8Custom::kNodeEventListenerCacheIndex); } return v8::Undefined(); diff --git a/WebCore/bindings/v8/custom/V8SharedWorkerCustom.cpp b/WebCore/bindings/v8/custom/V8SharedWorkerCustom.cpp index 3ab2f8e..e470bc8 100644 --- a/WebCore/bindings/v8/custom/V8SharedWorkerCustom.cpp +++ b/WebCore/bindings/v8/custom/V8SharedWorkerCustom.cpp @@ -53,12 +53,15 @@ CALLBACK_FUNC_DECL(SharedWorkerConstructor) if (!args.IsConstructCall()) return throwError("DOM object constructor cannot be called as a function."); - if (args.Length() < 2) + if (args.Length() < 1) return throwError("Not enough arguments", V8Proxy::SyntaxError); v8::TryCatch tryCatch; v8::Handle<v8::String> scriptUrl = args[0]->ToString(); - v8::Handle<v8::String> name = args[1]->ToString(); + String name; + if (args.Length() > 1) + name = toWebCoreString(args[1]->ToString()); + if (tryCatch.HasCaught()) return throwError(tryCatch.Exception()); @@ -66,21 +69,14 @@ CALLBACK_FUNC_DECL(SharedWorkerConstructor) return v8::Undefined(); // Get the script execution context. - ScriptExecutionContext* context = 0; - WorkerContextExecutionProxy* proxy = WorkerContextExecutionProxy::retrieve(); - if (proxy) - context = proxy->workerContext(); - else { - Frame* frame = V8Proxy::retrieveFrame(); - if (!frame) - return v8::Undefined(); - context = frame->document(); - } + ScriptExecutionContext* context = getScriptExecutionContext(); + if (!context) + return v8::Undefined(); // Create the worker object. // Note: it's OK to let this RefPtr go out of scope because we also call SetDOMWrapper(), which effectively holds a reference to obj. ExceptionCode ec = 0; - RefPtr<SharedWorker> obj = SharedWorker::create(toWebCoreString(scriptUrl), toWebCoreString(name), context, ec); + RefPtr<SharedWorker> obj = SharedWorker::create(toWebCoreString(scriptUrl), name, context, ec); // Setup the standard wrapper object internal fields. v8::Handle<v8::Object> wrapperObject = args.Holder(); diff --git a/WebCore/bindings/v8/custom/V8WebKitPointConstructor.cpp b/WebCore/bindings/v8/custom/V8WebKitPointConstructor.cpp index dd19a88..b2a807d 100755 --- a/WebCore/bindings/v8/custom/V8WebKitPointConstructor.cpp +++ b/WebCore/bindings/v8/custom/V8WebKitPointConstructor.cpp @@ -30,17 +30,38 @@ #include "config.h" +#include "V8Binding.h" #include "V8CustomBinding.h" +#include "V8DOMWrapper.h" #include "V8Index.h" #include "V8Proxy.h" #include "WebKitPoint.h" +#include <wtf/MathExtras.h> + namespace WebCore { CALLBACK_FUNC_DECL(WebKitPointConstructor) { INC_STATS("DOM.WebKitPoint.Constructor"); - return V8Proxy::constructDOMObject<V8ClassIndex::WEBKITPOINT, WebKitPoint>(args); + float x = 0; + float y = 0; + if (args.Length() > 1) { + if (!args[0]->IsUndefined()) { + x = toFloat(args[0]); + if (isnan(x)) + x = 0; + } + if (!args[1]->IsUndefined()) { + y = toFloat(args[1]); + if (isnan(y)) + y = 0; + } + } + PassRefPtr<WebKitPoint> point = WebKitPoint::create(x, y); + point->ref(); + V8DOMWrapper::setDOMWrapper(args.Holder(), V8ClassIndex::WEBKITPOINT, point.get()); + return args.Holder(); } } // namespace WebCore diff --git a/WebCore/bindings/v8/custom/V8WebSocketCustom.cpp b/WebCore/bindings/v8/custom/V8WebSocketCustom.cpp new file mode 100644 index 0000000..f498e4f --- /dev/null +++ b/WebCore/bindings/v8/custom/V8WebSocketCustom.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(WEB_SOCKETS) + +#include "WebSocket.h" + +#include "Frame.h" +#include "Settings.h" +#include "V8Binding.h" +#include "V8Proxy.h" +#include "V8Utilities.h" +#include "WorkerContext.h" +#include "WorkerContextExecutionProxy.h" + +namespace WebCore { + +// ??? AddEventListener, RemoveEventListener + +CALLBACK_FUNC_DECL(WebSocketConstructor) +{ + INC_STATS("DOM.WebSocket.Constructor"); + + if (!args.IsConstructCall()) + return throwError("DOM object custructor cannot be called as a function."); + if (args.Length() == 0) + return throwError("Not enough arguments", V8Proxy::SyntaxError); + + v8::TryCatch tryCatch; + v8::Handle<v8::String> urlstring = args[0]->ToString(); + if (tryCatch.HasCaught()) + return throwError(tryCatch.Exception()); + if (urlstring.IsEmpty()) + return throwError("Empty URL", V8Proxy::SyntaxError); + + // Get the script execution context. + ScriptExecutionContext* context = 0; + // TODO: Workers + if (!context) { + Frame* frame = V8Proxy::retrieveFrameForCurrentContext(); + if (!frame) + return throwError("WebSocket constructor's associated frame is not available", V8Proxy::ReferenceError); + context = frame->document(); + } + + const KURL& url = context->completeURL(toWebCoreString(urlstring)); + + RefPtr<WebSocket> webSocket = WebSocket::create(context); + ExceptionCode ec = 0; + + if (args.Length() < 2) + webSocket->connect(url, ec); + else { + v8::TryCatch tryCatchProtocol; + v8::Handle<v8::String> protocol = args[1]->ToString(); + if (tryCatchProtocol.HasCaught()) + return throwError(tryCatchProtocol.Exception()); + webSocket->connect(url, toWebCoreString(protocol), ec); + } + if (ec) + return throwError(ec); + + // Setup the standard wrapper object internal fields. + V8DOMWrapper::setDOMWrapper(args.Holder(), V8ClassIndex::ToInt(V8ClassIndex::WEBSOCKET), webSocket.get()); + + // Add object to the wrapper map. + webSocket->ref(); + V8DOMWrapper::setJSWrapperForActiveDOMObject(webSocket.get(), v8::Persistent<v8::Object>::New(args.Holder())); + + return args.Holder(); +} + +CALLBACK_FUNC_DECL(WebSocketSend) +{ + INC_STATS("DOM.WebSocket.send()"); + WebSocket* webSocket = V8DOMWrapper::convertToNativeObject<WebSocket>(V8ClassIndex::WEBSOCKET, args.Holder()); + + ExceptionCode ec = 0; + bool ret = false; + if (args.Length() < 1) + return throwError("Not enough arguments", V8Proxy::SyntaxError); + else { + String msg = toWebCoreString(args[0]); + ret = webSocket->send(msg, ec); + } + if (ec) + return throwError(ec); + return v8Boolean(ret); +} + +CALLBACK_FUNC_DECL(WebSocketClose) +{ + INC_STATS("DOM.WebSocket.close()"); + WebSocket* webSocket = V8DOMWrapper::convertToNativeObject<WebSocket>(V8ClassIndex::WEBSOCKET, args.Holder()); + + webSocket->close(); + return v8::Undefined(); +} + +} // namespace WebCore + +#endif // ENABLE(WEB_SOCKETS) diff --git a/WebCore/bindings/v8/custom/V8WorkerContextCustom.cpp b/WebCore/bindings/v8/custom/V8WorkerContextCustom.cpp index b526040..21b3c30 100755 --- a/WebCore/bindings/v8/custom/V8WorkerContextCustom.cpp +++ b/WebCore/bindings/v8/custom/V8WorkerContextCustom.cpp @@ -52,45 +52,6 @@ ACCESSOR_GETTER(WorkerContextSelf) return WorkerContextExecutionProxy::convertWorkerContextToV8Object(workerContext); } -ACCESSOR_GETTER(WorkerContextOnerror) -{ - INC_STATS(L"DOM.WorkerContext.onerror._get"); - WorkerContext* workerContext = V8DOMWrapper::convertToNativeObject<WorkerContext>(V8ClassIndex::WORKERCONTEXT, info.Holder()); - if (workerContext->onerror()) { - V8WorkerContextEventListener* listener = static_cast<V8WorkerContextEventListener*>(workerContext->onerror()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - return v8Listener; - } - return v8::Undefined(); -} - -ACCESSOR_SETTER(WorkerContextOnerror) -{ - INC_STATS(L"DOM.WorkerContext.onerror._set"); - WorkerContext* workerContext = V8DOMWrapper::convertToNativeObject<WorkerContext>(V8ClassIndex::WORKERCONTEXT, info.Holder()); - V8WorkerContextEventListener* oldListener = static_cast<V8WorkerContextEventListener*>(workerContext->onerror()); - if (value->IsNull()) { - if (workerContext->onerror()) { - v8::Local<v8::Object> oldV8Listener = oldListener->getListenerObject(); - removeHiddenDependency(info.Holder(), oldV8Listener, V8Custom::kWorkerContextRequestCacheIndex); - } - - // Clear the listener. - workerContext->setOnerror(0); - } else { - RefPtr<V8EventListener> listener = workerContext->script()->proxy()->findOrCreateEventListener(v8::Local<v8::Object>::Cast(value), true, false); - if (listener) { - if (oldListener) { - v8::Local<v8::Object> oldV8Listener = oldListener->getListenerObject(); - removeHiddenDependency(info.Holder(), oldV8Listener, V8Custom::kWorkerContextRequestCacheIndex); - } - - workerContext->setOnerror(listener); - createHiddenDependency(info.Holder(), value, V8Custom::kWorkerContextRequestCacheIndex); - } - } -} - v8::Handle<v8::Value> SetTimeoutOrInterval(const v8::Arguments& args, bool singleShot) { WorkerContext* workerContext = V8DOMWrapper::convertDOMWrapperToNative<WorkerContext>(args.Holder()); @@ -103,9 +64,10 @@ v8::Handle<v8::Value> SetTimeoutOrInterval(const v8::Arguments& args, bool singl int32_t timeout = argumentCount >= 2 ? args[1]->Int32Value() : 0; int timerId; + v8::Handle<v8::Context> v8Context = workerContext->script()->proxy()->context(); if (function->IsString()) { WebCore::String stringFunction = toWebCoreString(function); - timerId = DOMTimer::install(workerContext, new ScheduledAction(stringFunction, workerContext->url()), timeout, singleShot); + timerId = DOMTimer::install(workerContext, new ScheduledAction(v8Context, stringFunction, workerContext->url()), timeout, singleShot); } else if (function->IsFunction()) { size_t paramCount = argumentCount >= 2 ? argumentCount - 2 : 0; v8::Local<v8::Value>* params = 0; @@ -115,7 +77,7 @@ v8::Handle<v8::Value> SetTimeoutOrInterval(const v8::Arguments& args, bool singl params[i] = args[i+2]; } // ScheduledAction takes ownership of actual params and releases them in its destructor. - ScheduledAction* action = new ScheduledAction(v8::Handle<v8::Function>::Cast(function), paramCount, params); + ScheduledAction* action = new ScheduledAction(v8Context, v8::Handle<v8::Function>::Cast(function), paramCount, params); delete [] params; timerId = DOMTimer::install(workerContext, action, timeout, singleShot); } else @@ -170,8 +132,7 @@ CALLBACK_FUNC_DECL(WorkerContextAddEventListener) INC_STATS(L"DOM.WorkerContext.addEventListener()"); WorkerContext* workerContext = V8DOMWrapper::convertDOMWrapperToNative<WorkerContext>(args.Holder()); - RefPtr<V8EventListener> listener = workerContext->script()->proxy()->findOrCreateEventListener(v8::Local<v8::Object>::Cast(args[1]), false, false); - + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(workerContext, args[1], false, ListenerFindOrCreate); if (listener) { String type = toWebCoreString(args[0]); bool useCapture = args[2]->BooleanValue(); @@ -186,10 +147,8 @@ CALLBACK_FUNC_DECL(WorkerContextRemoveEventListener) { INC_STATS(L"DOM.WorkerContext.removeEventListener()"); WorkerContext* workerContext = V8DOMWrapper::convertDOMWrapperToNative<WorkerContext>(args.Holder()); - WorkerContextExecutionProxy* proxy = workerContext->script()->proxy(); - - RefPtr<V8EventListener> listener = proxy->findOrCreateEventListener(v8::Local<v8::Object>::Cast(args[1]), false, true); + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(workerContext, args[1], false, ListenerFindOnly); if (listener) { String type = toWebCoreString(args[0]); bool useCapture = args[2]->BooleanValue(); @@ -197,7 +156,6 @@ CALLBACK_FUNC_DECL(WorkerContextRemoveEventListener) removeHiddenDependency(args.Holder(), args[1], V8Custom::kWorkerContextRequestCacheIndex); } - return v8::Undefined(); } diff --git a/WebCore/bindings/v8/custom/V8WorkerCustom.cpp b/WebCore/bindings/v8/custom/V8WorkerCustom.cpp index 32450b8..454e41f 100755 --- a/WebCore/bindings/v8/custom/V8WorkerCustom.cpp +++ b/WebCore/bindings/v8/custom/V8WorkerCustom.cpp @@ -36,9 +36,10 @@ #include "ExceptionCode.h" #include "Frame.h" +#include "SerializedScriptValue.h" #include "V8Binding.h" #include "V8CustomBinding.h" -#include "V8ObjectEventListener.h" +#include "V8MessagePortCustom.h" #include "V8Proxy.h" #include "V8Utilities.h" #include "WorkerContext.h" @@ -65,16 +66,9 @@ CALLBACK_FUNC_DECL(WorkerConstructor) return v8::Undefined(); // Get the script execution context. - ScriptExecutionContext* context = 0; - WorkerContextExecutionProxy* proxy = WorkerContextExecutionProxy::retrieve(); - if (proxy) - context = proxy->workerContext(); - else { - Frame* frame = V8Proxy::retrieveFrameForCurrentContext(); - if (!frame) - return v8::Undefined(); - context = frame->document(); - } + ScriptExecutionContext* context = getScriptExecutionContext(); + if (!context) + return v8::Undefined(); // Create the worker object. // Note: it's OK to let this RefPtr go out of scope because we also call setDOMWrapper(), which effectively holds a reference to obj. @@ -93,60 +87,19 @@ CALLBACK_FUNC_DECL(WorkerConstructor) return wrapperObject; } -PassRefPtr<EventListener> getEventListener(Worker* worker, v8::Local<v8::Value> value, bool isAttribute, bool findOnly) -{ - if (worker->scriptExecutionContext()->isWorkerContext()) { - WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); - ASSERT(workerContextProxy); - return workerContextProxy->findOrCreateObjectEventListener(value, isAttribute, findOnly); - } - - V8Proxy* proxy = V8Proxy::retrieve(worker->scriptExecutionContext()); - if (proxy) { - V8EventListenerList* list = proxy->objectListeners(); - return findOnly ? list->findWrapper(value, isAttribute) : list->findOrCreateWrapper<V8ObjectEventListener>(proxy->frame(), value, isAttribute); - } - - return 0; -} - -ACCESSOR_GETTER(WorkerOnmessage) -{ - INC_STATS(L"DOM.Worker.onmessage._get"); - Worker* worker = V8DOMWrapper::convertToNativeObject<Worker>(V8ClassIndex::WORKER, info.Holder()); - if (worker->onmessage()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(worker->onmessage()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - return v8Listener; - } - return v8::Undefined(); -} - -ACCESSOR_SETTER(WorkerOnmessage) +CALLBACK_FUNC_DECL(WorkerPostMessage) { - INC_STATS(L"DOM.Worker.onmessage._set"); - Worker* worker = V8DOMWrapper::convertToNativeObject<Worker>(V8ClassIndex::WORKER, info.Holder()); - V8ObjectEventListener* oldListener = static_cast<V8ObjectEventListener*>(worker->onmessage()); - if (value->IsNull()) { - if (oldListener) { - v8::Local<v8::Object> oldV8Listener = oldListener->getListenerObject(); - removeHiddenDependency(info.Holder(), oldV8Listener, V8Custom::kWorkerRequestCacheIndex); - } - - // Clear the listener. - worker->setOnmessage(0); - } else { - RefPtr<EventListener> listener = getEventListener(worker, value, true, false); - if (listener) { - if (oldListener) { - v8::Local<v8::Object> oldV8Listener = oldListener->getListenerObject(); - removeHiddenDependency(info.Holder(), oldV8Listener, V8Custom::kWorkerRequestCacheIndex); - } - - worker->setOnmessage(listener); - createHiddenDependency(info.Holder(), value, V8Custom::kWorkerRequestCacheIndex); - } + INC_STATS("DOM.Worker.postMessage"); + Worker* worker = V8DOMWrapper::convertToNativeObject<Worker>(V8ClassIndex::WORKER, args.Holder()); + RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(toWebCoreString(args[0])); + MessagePortArray portArray; + if (args.Length() > 1) { + if (!getMessagePortArray(args[1], portArray)) + return v8::Undefined(); } + ExceptionCode ec = 0; + worker->postMessage(message.release(), &portArray, ec); + return throwError(ec); } } // namespace WebCore diff --git a/WebCore/bindings/v8/custom/V8XMLHttpRequestConstructor.cpp b/WebCore/bindings/v8/custom/V8XMLHttpRequestConstructor.cpp index 02ce8e2..af647cd 100644 --- a/WebCore/bindings/v8/custom/V8XMLHttpRequestConstructor.cpp +++ b/WebCore/bindings/v8/custom/V8XMLHttpRequestConstructor.cpp @@ -33,8 +33,8 @@ #include "Frame.h" #include "V8Binding.h" #include "V8CustomBinding.h" -#include "V8ObjectEventListener.h" #include "V8Proxy.h" +#include "V8Utilities.h" #include "XMLHttpRequest.h" #include "WorkerContext.h" #include "WorkerContextExecutionProxy.h" @@ -50,20 +50,9 @@ CALLBACK_FUNC_DECL(XMLHttpRequestConstructor) // Expect no parameters. // Allocate a XMLHttpRequest object as its internal field. - ScriptExecutionContext* context = 0; -#if ENABLE(WORKERS) - WorkerContextExecutionProxy* proxy = WorkerContextExecutionProxy::retrieve(); - if (proxy) - context = proxy->workerContext(); - else { -#endif - Frame* frame = V8Proxy::retrieveFrameForCurrentContext(); - if (!frame) - return throwError("XMLHttpRequest constructor's associated frame is not available", V8Proxy::ReferenceError); - context = frame->document(); -#if ENABLE(WORKERS) - } -#endif + ScriptExecutionContext* context = getScriptExecutionContext(); + if (!context) + return throwError("XMLHttpRequest constructor's associated context is not available", V8Proxy::ReferenceError); RefPtr<XMLHttpRequest> xmlHttpRequest = XMLHttpRequest::create(context); V8DOMWrapper::setDOMWrapper(args.Holder(), V8ClassIndex::ToInt(V8ClassIndex::XMLHTTPREQUEST), xmlHttpRequest.get()); diff --git a/WebCore/bindings/v8/custom/V8XMLHttpRequestCustom.cpp b/WebCore/bindings/v8/custom/V8XMLHttpRequestCustom.cpp index 7204a61..39105de 100644 --- a/WebCore/bindings/v8/custom/V8XMLHttpRequestCustom.cpp +++ b/WebCore/bindings/v8/custom/V8XMLHttpRequestCustom.cpp @@ -33,10 +33,10 @@ #include "Frame.h" #include "V8Binding.h" -#include "V8Document.h" #include "V8CustomBinding.h" +#include "V8Document.h" +#include "V8File.h" #include "V8HTMLDocument.h" -#include "V8ObjectEventListener.h" #include "V8Proxy.h" #include "V8Utilities.h" #include "WorkerContext.h" @@ -44,227 +44,6 @@ namespace WebCore { -static PassRefPtr<EventListener> getEventListener(XMLHttpRequest* xmlHttpRequest, v8::Local<v8::Value> value, bool findOnly) -{ -#if ENABLE(WORKERS) - WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); - if (workerContextProxy) - return workerContextProxy->findOrCreateObjectEventListener(value, false, findOnly); -#endif - - V8Proxy* proxy = V8Proxy::retrieve(xmlHttpRequest->scriptExecutionContext()); - if (proxy) { - V8EventListenerList* list = proxy->objectListeners(); - return findOnly ? list->findWrapper(value, false) : list->findOrCreateWrapper<V8ObjectEventListener>(proxy->frame(), value, false); - } - - return PassRefPtr<EventListener>(); -} - -ACCESSOR_GETTER(XMLHttpRequestOnabort) -{ - INC_STATS("DOM.XMLHttpRequest.onabort._get"); - XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder()); - if (xmlHttpRequest->onabort()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onabort()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - return v8Listener; - } - return v8::Null(); -} - -ACCESSOR_SETTER(XMLHttpRequestOnabort) -{ - INC_STATS("DOM.XMLHttpRequest.onabort._set"); - XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder()); - if (value->IsNull()) { - if (xmlHttpRequest->onabort()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onabort()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kXMLHttpRequestCacheIndex); - } - - // Clear the listener. - xmlHttpRequest->setOnabort(0); - } else { - RefPtr<EventListener> listener = getEventListener(xmlHttpRequest, value, false); - if (listener) { - xmlHttpRequest->setOnabort(listener); - createHiddenDependency(info.Holder(), value, V8Custom::kXMLHttpRequestCacheIndex); - } - } -} - -ACCESSOR_GETTER(XMLHttpRequestOnerror) -{ - INC_STATS("DOM.XMLHttpRequest.onerror._get"); - XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder()); - if (xmlHttpRequest->onerror()) { - RefPtr<V8ObjectEventListener> listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onerror()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - return v8Listener; - } - return v8::Null(); -} - -ACCESSOR_SETTER(XMLHttpRequestOnerror) -{ - INC_STATS("DOM.XMLHttpRequest.onerror._set"); - XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder()); - if (value->IsNull()) { - if (xmlHttpRequest->onerror()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onerror()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kXMLHttpRequestCacheIndex); - } - - // Clear the listener. - xmlHttpRequest->setOnerror(0); - } else { - RefPtr<EventListener> listener = getEventListener(xmlHttpRequest, value, false); - if (listener) { - xmlHttpRequest->setOnerror(listener); - createHiddenDependency(info.Holder(), value, V8Custom::kXMLHttpRequestCacheIndex); - } - } -} - -ACCESSOR_GETTER(XMLHttpRequestOnload) -{ - INC_STATS("DOM.XMLHttpRequest.onload._get"); - XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder()); - if (xmlHttpRequest->onload()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onload()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - return v8Listener; - } - return v8::Null(); -} - -ACCESSOR_SETTER(XMLHttpRequestOnload) -{ - INC_STATS("DOM.XMLHttpRequest.onload._set"); - XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder()); - if (value->IsNull()) { - if (xmlHttpRequest->onload()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onload()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kXMLHttpRequestCacheIndex); - } - - xmlHttpRequest->setOnload(0); - - } else { - RefPtr<EventListener> listener = getEventListener(xmlHttpRequest, value, false); - if (listener) { - xmlHttpRequest->setOnload(listener.get()); - createHiddenDependency(info.Holder(), value, V8Custom::kXMLHttpRequestCacheIndex); - } - } -} - -ACCESSOR_GETTER(XMLHttpRequestOnloadstart) -{ - INC_STATS("DOM.XMLHttpRequest.onloadstart._get"); - XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder()); - if (xmlHttpRequest->onloadstart()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onloadstart()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - return v8Listener; - } - return v8::Null(); -} - -ACCESSOR_SETTER(XMLHttpRequestOnloadstart) -{ - INC_STATS("DOM.XMLHttpRequest.onloadstart._set"); - XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder()); - if (value->IsNull()) { - if (xmlHttpRequest->onloadstart()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onloadstart()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kXMLHttpRequestCacheIndex); - } - - // Clear the listener. - xmlHttpRequest->setOnloadstart(0); - } else { - RefPtr<EventListener> listener = getEventListener(xmlHttpRequest, value, false); - if (listener) { - xmlHttpRequest->setOnloadstart(listener); - createHiddenDependency(info.Holder(), value, V8Custom::kXMLHttpRequestCacheIndex); - } - } -} - -ACCESSOR_GETTER(XMLHttpRequestOnprogress) -{ - INC_STATS("DOM.XMLHttpRequest.onprogress._get"); - XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder()); - if (xmlHttpRequest->onprogress()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onprogress()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - return v8Listener; - } - return v8::Null(); -} - -ACCESSOR_SETTER(XMLHttpRequestOnprogress) -{ - INC_STATS("DOM.XMLHttpRequest.onprogress._set"); - XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder()); - if (value->IsNull()) { - if (xmlHttpRequest->onprogress()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onprogress()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kXMLHttpRequestCacheIndex); - } - - // Clear the listener. - xmlHttpRequest->setOnprogress(0); - } else { - RefPtr<EventListener> listener = getEventListener(xmlHttpRequest, value, false); - if (listener) { - xmlHttpRequest->setOnprogress(listener); - createHiddenDependency(info.Holder(), value, V8Custom::kXMLHttpRequestCacheIndex); - } - } -} - -ACCESSOR_GETTER(XMLHttpRequestOnreadystatechange) -{ - INC_STATS("DOM.XMLHttpRequest.onreadystatechange._get"); - XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder()); - if (xmlHttpRequest->onreadystatechange()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onreadystatechange()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - return v8Listener; - } - return v8::Null(); -} - -ACCESSOR_SETTER(XMLHttpRequestOnreadystatechange) -{ - INC_STATS("DOM.XMLHttpRequest.onreadystatechange._set"); - XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, info.Holder()); - if (value->IsNull()) { - if (xmlHttpRequest->onreadystatechange()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequest->onreadystatechange()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kXMLHttpRequestCacheIndex); - } - - // Clear the listener. - xmlHttpRequest->setOnreadystatechange(0); - } else { - RefPtr<EventListener> listener = getEventListener(xmlHttpRequest, value, false); - if (listener) { - xmlHttpRequest->setOnreadystatechange(listener.get()); - createHiddenDependency(info.Holder(), value, V8Custom::kXMLHttpRequestCacheIndex); - } - } -} - ACCESSOR_GETTER(XMLHttpRequestResponseText) { // FIXME: This is only needed because webkit set this getter as custom. @@ -279,7 +58,7 @@ CALLBACK_FUNC_DECL(XMLHttpRequestAddEventListener) INC_STATS("DOM.XMLHttpRequest.addEventListener()"); XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, args.Holder()); - RefPtr<EventListener> listener = getEventListener(xmlHttpRequest, args[1], false); + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(xmlHttpRequest, args[1], false, ListenerFindOrCreate); if (listener) { String type = toWebCoreString(args[0]); bool useCapture = args[2]->BooleanValue(); @@ -295,7 +74,7 @@ CALLBACK_FUNC_DECL(XMLHttpRequestRemoveEventListener) INC_STATS("DOM.XMLHttpRequest.removeEventListener()"); XMLHttpRequest* xmlHttpRequest = V8DOMWrapper::convertToNativeObject<XMLHttpRequest>(V8ClassIndex::XMLHTTPREQUEST, args.Holder()); - RefPtr<EventListener> listener = getEventListener(xmlHttpRequest, args[1], true); + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(xmlHttpRequest, args[1], false, ListenerFindOnly); if (listener) { String type = toWebCoreString(args[0]); bool useCapture = args[2]->BooleanValue(); @@ -323,22 +102,9 @@ CALLBACK_FUNC_DECL(XMLHttpRequestOpen) String method = toWebCoreString(args[0]); String urlstring = toWebCoreString(args[1]); - ScriptExecutionContext* context = 0; -#if ENABLE(WORKERS) - WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); - if (workerContextProxy) { - context = workerContextProxy->workerContext(); - ASSERT(context); - } -#endif - - if (!context) { - V8Proxy* proxy = V8Proxy::retrieve(); - if (!proxy) - return v8::Undefined(); - context = proxy->frame()->document(); - ASSERT(context); - } + ScriptExecutionContext* context = getScriptExecutionContext(); + if (!context) + return v8::Undefined(); KURL url = context->completeURL(urlstring); @@ -379,12 +145,16 @@ CALLBACK_FUNC_DECL(XMLHttpRequestSend) xmlHttpRequest->send(ec); else { v8::Handle<v8::Value> arg = args[0]; - // FIXME: upstream handles "File" objects too. if (IsDocumentType(arg)) { v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(arg); Document* document = V8DOMWrapper::convertDOMWrapperToNode<Document>(object); ASSERT(document); xmlHttpRequest->send(document, ec); + } else if (V8File::HasInstance(arg)) { + v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(arg); + File* file = V8DOMWrapper::convertDOMWrapperToNative<File>(object); + ASSERT(file); + xmlHttpRequest->send(file, ec); } else xmlHttpRequest->send(toWebCoreStringWithNullCheck(arg), ec); } diff --git a/WebCore/bindings/v8/custom/V8XMLHttpRequestUploadCustom.cpp b/WebCore/bindings/v8/custom/V8XMLHttpRequestUploadCustom.cpp index bbc69dd..9323f71 100644 --- a/WebCore/bindings/v8/custom/V8XMLHttpRequestUploadCustom.cpp +++ b/WebCore/bindings/v8/custom/V8XMLHttpRequestUploadCustom.cpp @@ -34,7 +34,6 @@ #include "ExceptionCode.h" #include "V8Binding.h" #include "V8CustomBinding.h" -#include "V8ObjectEventListener.h" #include "V8Proxy.h" #include "V8Utilities.h" #include "XMLHttpRequest.h" @@ -43,212 +42,14 @@ namespace WebCore { -ACCESSOR_GETTER(XMLHttpRequestUploadOnabort) -{ - INC_STATS("DOM.XMLHttpRequestUpload.onabort._get"); - XMLHttpRequestUpload* xmlHttpRequestUpload = V8DOMWrapper::convertToNativeObject<XMLHttpRequestUpload>(V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); - if (xmlHttpRequestUpload->onabort()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequestUpload->onabort()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - return v8Listener; - } - return v8::Null(); -} - -ACCESSOR_SETTER(XMLHttpRequestUploadOnabort) -{ - INC_STATS("DOM.XMLHttpRequestUpload.onabort._set"); - XMLHttpRequestUpload* xmlHttpRequestUpload = V8DOMWrapper::convertToNativeObject<XMLHttpRequestUpload>(V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); - if (value->IsNull()) { - if (xmlHttpRequestUpload->onabort()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequestUpload->onabort()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kXMLHttpRequestCacheIndex); - } - - // Clear the listener. - xmlHttpRequestUpload->setOnabort(0); - } else { - XMLHttpRequest* xmlHttpRequest = xmlHttpRequestUpload->associatedXMLHttpRequest(); - V8Proxy* proxy = V8Proxy::retrieve(xmlHttpRequest->scriptExecutionContext()); - if (!proxy) - return; - - RefPtr<EventListener> listener = proxy->objectListeners()->findOrCreateWrapper<V8ObjectEventListener>(proxy->frame(), value, false); - if (listener) { - xmlHttpRequestUpload->setOnabort(listener); - createHiddenDependency(info.Holder(), value, V8Custom::kXMLHttpRequestCacheIndex); - } - } -} - -ACCESSOR_GETTER(XMLHttpRequestUploadOnerror) -{ - INC_STATS("DOM.XMLHttpRequestUpload.onerror._get"); - XMLHttpRequestUpload* xmlHttpRequestUpload = V8DOMWrapper::convertToNativeObject<XMLHttpRequestUpload>(V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); - if (xmlHttpRequestUpload->onerror()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequestUpload->onerror()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - return v8Listener; - } - return v8::Null(); -} - -ACCESSOR_SETTER(XMLHttpRequestUploadOnerror) -{ - INC_STATS("DOM.XMLHttpRequestUpload.onerror._set"); - XMLHttpRequestUpload* xmlHttpRequestUpload = V8DOMWrapper::convertToNativeObject<XMLHttpRequestUpload>(V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); - if (value->IsNull()) { - if (xmlHttpRequestUpload->onerror()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequestUpload->onerror()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kXMLHttpRequestCacheIndex); - } - - // Clear the listener. - xmlHttpRequestUpload->setOnerror(0); - } else { - XMLHttpRequest* xmlHttpRequest = xmlHttpRequestUpload->associatedXMLHttpRequest(); - V8Proxy* proxy = V8Proxy::retrieve(xmlHttpRequest->scriptExecutionContext()); - if (!proxy) - return; - - RefPtr<EventListener> listener = proxy->objectListeners()->findOrCreateWrapper<V8ObjectEventListener>(proxy->frame(), value, false); - if (listener) { - xmlHttpRequestUpload->setOnerror(listener); - createHiddenDependency(info.Holder(), value, V8Custom::kXMLHttpRequestCacheIndex); - } - } -} - -ACCESSOR_GETTER(XMLHttpRequestUploadOnload) -{ - INC_STATS("DOM.XMLHttpRequestUpload.onload._get"); - XMLHttpRequestUpload* xmlHttpRequestUpload = V8DOMWrapper::convertToNativeObject<XMLHttpRequestUpload>(V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); - if (xmlHttpRequestUpload->onload()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequestUpload->onload()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - return v8Listener; - } - return v8::Null(); -} - -ACCESSOR_SETTER(XMLHttpRequestUploadOnload) -{ - INC_STATS("DOM.XMLHttpRequestUpload.onload._set"); - XMLHttpRequestUpload* xmlHttpRequestUpload = V8DOMWrapper::convertToNativeObject<XMLHttpRequestUpload>(V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); - if (value->IsNull()) { - if (xmlHttpRequestUpload->onload()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequestUpload->onload()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kXMLHttpRequestCacheIndex); - } - - // Clear the listener. - xmlHttpRequestUpload->setOnload(0); - } else { - XMLHttpRequest* xmlHttpRequest = xmlHttpRequestUpload->associatedXMLHttpRequest(); - V8Proxy* proxy = V8Proxy::retrieve(xmlHttpRequest->scriptExecutionContext()); - if (!proxy) - return; - - RefPtr<EventListener> listener = proxy->objectListeners()->findOrCreateWrapper<V8ObjectEventListener>(proxy->frame(), value, false); - if (listener) { - xmlHttpRequestUpload->setOnload(listener); - createHiddenDependency(info.Holder(), value, V8Custom::kXMLHttpRequestCacheIndex); - } - } -} - -ACCESSOR_GETTER(XMLHttpRequestUploadOnloadstart) -{ - INC_STATS("DOM.XMLHttpRequestUpload.onloadstart._get"); - XMLHttpRequestUpload* xmlHttpRequestUpload = V8DOMWrapper::convertToNativeObject<XMLHttpRequestUpload>(V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); - if (xmlHttpRequestUpload->onloadstart()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequestUpload->onloadstart()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - return v8Listener; - } - return v8::Null(); -} - -ACCESSOR_SETTER(XMLHttpRequestUploadOnloadstart) -{ - INC_STATS("DOM.XMLHttpRequestUpload.onloadstart._set"); - XMLHttpRequestUpload* xmlHttpRequestUpload = V8DOMWrapper::convertToNativeObject<XMLHttpRequestUpload>(V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); - if (value->IsNull()) { - if (xmlHttpRequestUpload->onloadstart()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequestUpload->onloadstart()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kXMLHttpRequestCacheIndex); - } - - // Clear the listener. - xmlHttpRequestUpload->setOnloadstart(0); - } else { - XMLHttpRequest* xmlHttpRequest = xmlHttpRequestUpload->associatedXMLHttpRequest(); - V8Proxy* proxy = V8Proxy::retrieve(xmlHttpRequest->scriptExecutionContext()); - if (!proxy) - return; - - RefPtr<EventListener> listener = proxy->objectListeners()->findOrCreateWrapper<V8ObjectEventListener>(proxy->frame(), value, false); - if (listener) { - xmlHttpRequestUpload->setOnloadstart(listener); - createHiddenDependency(info.Holder(), value, V8Custom::kXMLHttpRequestCacheIndex); - } - } -} - -ACCESSOR_GETTER(XMLHttpRequestUploadOnprogress) -{ - INC_STATS("DOM.XMLHttpRequestUpload.onprogress._get"); - XMLHttpRequestUpload* xmlHttpRequestUpload = V8DOMWrapper::convertToNativeObject<XMLHttpRequestUpload>(V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); - if (xmlHttpRequestUpload->onprogress()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequestUpload->onprogress()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - return v8Listener; - } - return v8::Null(); -} - -ACCESSOR_SETTER(XMLHttpRequestUploadOnprogress) -{ - INC_STATS("DOM.XMLHttpRequestUpload.onprogress._set"); - XMLHttpRequestUpload* xmlHttpRequestUpload = V8DOMWrapper::convertToNativeObject<XMLHttpRequestUpload>(V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); - if (value->IsNull()) { - if (xmlHttpRequestUpload->onprogress()) { - V8ObjectEventListener* listener = static_cast<V8ObjectEventListener*>(xmlHttpRequestUpload->onprogress()); - v8::Local<v8::Object> v8Listener = listener->getListenerObject(); - removeHiddenDependency(info.Holder(), v8Listener, V8Custom::kXMLHttpRequestCacheIndex); - } - - // Clear the listener. - xmlHttpRequestUpload->setOnprogress(0); - } else { - XMLHttpRequest* xmlHttpRequest = xmlHttpRequestUpload->associatedXMLHttpRequest(); - V8Proxy* proxy = V8Proxy::retrieve(xmlHttpRequest->scriptExecutionContext()); - if (!proxy) - return; - - RefPtr<EventListener> listener = proxy->objectListeners()->findOrCreateWrapper<V8ObjectEventListener>(proxy->frame(), value, false); - if (listener) { - xmlHttpRequestUpload->setOnprogress(listener); - createHiddenDependency(info.Holder(), value, V8Custom::kXMLHttpRequestCacheIndex); - } - } -} - CALLBACK_FUNC_DECL(XMLHttpRequestUploadAddEventListener) { INC_STATS("DOM.XMLHttpRequestUpload.addEventListener()"); XMLHttpRequestUpload* xmlHttpRequestUpload = V8DOMWrapper::convertToNativeObject<XMLHttpRequestUpload>(V8ClassIndex::XMLHTTPREQUESTUPLOAD, args.Holder()); XMLHttpRequest* xmlHttpRequest = xmlHttpRequestUpload->associatedXMLHttpRequest(); - V8Proxy* proxy = V8Proxy::retrieve(xmlHttpRequest->scriptExecutionContext()); - if (!proxy) - return v8::Undefined(); - RefPtr<EventListener> listener = proxy->objectListeners()->findOrCreateWrapper<V8ObjectEventListener>(proxy->frame(), args[1], false); + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(xmlHttpRequest, args[1], false, ListenerFindOrCreate); if (listener) { String type = toWebCoreString(args[0]); bool useCapture = args[2]->BooleanValue(); @@ -265,12 +66,8 @@ CALLBACK_FUNC_DECL(XMLHttpRequestUploadRemoveEventListener) XMLHttpRequestUpload* xmlHttpRequestUpload = V8DOMWrapper::convertToNativeObject<XMLHttpRequestUpload>(V8ClassIndex::XMLHTTPREQUESTUPLOAD, args.Holder()); XMLHttpRequest* xmlHttpRequest = xmlHttpRequestUpload->associatedXMLHttpRequest(); - V8Proxy* proxy = V8Proxy::retrieve(xmlHttpRequest->scriptExecutionContext()); - if (!proxy) - return v8::Undefined(); // Probably leaked. - - RefPtr<EventListener> listener = proxy->objectListeners()->findWrapper(args[1], false); + RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(xmlHttpRequest, args[1], false, ListenerFindOnly); if (listener) { String type = toWebCoreString(args[0]); bool useCapture = args[2]->BooleanValue(); diff --git a/WebCore/bindings/v8/npruntime.cpp b/WebCore/bindings/v8/npruntime.cpp index 64a1927..35015b0 100644 --- a/WebCore/bindings/v8/npruntime.cpp +++ b/WebCore/bindings/v8/npruntime.cpp @@ -39,7 +39,7 @@ // The static initializer here should work okay, but we want to avoid // static initialization in general. -namespace { +namespace npruntime { // We use StringKey here as the key-type to avoid a string copy to // construct the map key and for faster comparisons than strcmp. @@ -112,7 +112,10 @@ struct StringKeyHash { static const bool safeToCompareToEmptyOrDeleted = true; }; -} // namespace +} // namespace npruntime + +using npruntime::StringKey; +using npruntime::StringKeyHash; // Implement HashTraits<StringKey> struct StringKeyHashTraits : WTF::GenericHashTraits<StringKey> { @@ -309,6 +312,15 @@ void _NPN_DeallocateObject(NPObject* npObject) } } +#if PLATFORM(ANDROID) +// Android uses NPN_ReleaseObject (the 'public' version of _NPN_ReleaseObject) +// in WebCoreFrameBridge.cpp. See http://trac.webkit.org/changeset/47021. +// TODO: Upstream this to webkit.org. +void NPN_ReleaseObject(NPObject *obj) +{ + _NPN_ReleaseObject(obj); +} +#endif void _NPN_ReleaseObject(NPObject* npObject) { ASSERT(npObject); |