V8DOMWrapper.cpp revision cae449b1dff813bce2972d779eb121f74e5d3014
1/*
2 * Copyright (C) 2009 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "V8DOMWrapper.h"
33
34#include "CSSMutableStyleDeclaration.h"
35<<<<<<< HEAD
36=======
37#include "DOMDataStore.h"
38>>>>>>> webkit.org at r54127
39#include "DOMObjectsInclude.h"
40#include "DocumentLoader.h"
41#include "FrameLoaderClient.h"
42#include "Notification.h"
43#include "SVGElementInstance.h"
44#include "SVGPathSeg.h"
45#include "ScriptController.h"
46#include "V8AbstractEventListener.h"
47#include "V8Binding.h"
48#include "V8Collection.h"
49#include "V8CustomBinding.h"
50#include "V8CustomEventListener.h"
51#include "V8DOMMap.h"
52#include "V8DOMWindow.h"
53#include "V8EventListenerList.h"
54#include "V8HTMLCollection.h"
55#include "V8HTMLDocument.h"
56#include "V8Index.h"
57#include "V8IsolatedContext.h"
58#include "V8MessageChannel.h"
59#include "V8Location.h"
60#include "V8NamedNodeMap.h"
61#include "V8NodeList.h"
62#include "V8Proxy.h"
63#include "V8StyleSheet.h"
64#include "WebGLArray.h"
65#include "WebGLContextAttributes.h"
66#include "WebGLUniformLocation.h"
67#include "WorkerContextExecutionProxy.h"
68
69#include <algorithm>
70#include <utility>
71#include <v8.h>
72#include <v8-debug.h>
73#include <wtf/Assertions.h>
74#include <wtf/OwnArrayPtr.h>
75#include <wtf/StdLibExtras.h>
76#include <wtf/UnusedParam.h>
77
78namespace WebCore {
79
80typedef HashMap<Node*, v8::Object*> DOMNodeMap;
81typedef HashMap<void*, v8::Object*> DOMObjectMap;
82
83#if ENABLE(SVG)
84
85static V8ClassIndex::V8WrapperType downcastSVGPathSeg(void* pathSeg)
86{
87    SVGPathSeg* realPathSeg = reinterpret_cast<SVGPathSeg*>(pathSeg);
88
89    switch (realPathSeg->pathSegType()) {
90    case SVGPathSeg::PATHSEG_CLOSEPATH:                    return V8ClassIndex::SVGPATHSEGCLOSEPATH;
91    case SVGPathSeg::PATHSEG_MOVETO_ABS:                   return V8ClassIndex::SVGPATHSEGMOVETOABS;
92    case SVGPathSeg::PATHSEG_MOVETO_REL:                   return V8ClassIndex::SVGPATHSEGMOVETOREL;
93    case SVGPathSeg::PATHSEG_LINETO_ABS:                   return V8ClassIndex::SVGPATHSEGLINETOABS;
94    case SVGPathSeg::PATHSEG_LINETO_REL:                   return V8ClassIndex::SVGPATHSEGLINETOREL;
95    case SVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS:            return V8ClassIndex::SVGPATHSEGCURVETOCUBICABS;
96    case SVGPathSeg::PATHSEG_CURVETO_CUBIC_REL:            return V8ClassIndex::SVGPATHSEGCURVETOCUBICREL;
97    case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS:        return V8ClassIndex::SVGPATHSEGCURVETOQUADRATICABS;
98    case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL:        return V8ClassIndex::SVGPATHSEGCURVETOQUADRATICREL;
99    case SVGPathSeg::PATHSEG_ARC_ABS:                      return V8ClassIndex::SVGPATHSEGARCABS;
100    case SVGPathSeg::PATHSEG_ARC_REL:                      return V8ClassIndex::SVGPATHSEGARCREL;
101    case SVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS:        return V8ClassIndex::SVGPATHSEGLINETOHORIZONTALABS;
102    case SVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL:        return V8ClassIndex::SVGPATHSEGLINETOHORIZONTALREL;
103    case SVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS:          return V8ClassIndex::SVGPATHSEGLINETOVERTICALABS;
104    case SVGPathSeg::PATHSEG_LINETO_VERTICAL_REL:          return V8ClassIndex::SVGPATHSEGLINETOVERTICALREL;
105    case SVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:     return V8ClassIndex::SVGPATHSEGCURVETOCUBICSMOOTHABS;
106    case SVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL:     return V8ClassIndex::SVGPATHSEGCURVETOCUBICSMOOTHREL;
107    case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: return V8ClassIndex::SVGPATHSEGCURVETOQUADRATICSMOOTHABS;
108    case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: return V8ClassIndex::SVGPATHSEGCURVETOQUADRATICSMOOTHREL;
109    default:                                               return V8ClassIndex::INVALID_CLASS_INDEX;
110    }
111}
112
113v8::Handle<v8::Value> V8DOMWrapper::convertSVGElementInstanceToV8Object(SVGElementInstance* instance)
114{
115    if (!instance)
116        return v8::Null();
117
118    v8::Handle<v8::Object> existingInstance = getDOMSVGElementInstanceMap().get(instance);
119    if (!existingInstance.IsEmpty())
120        return existingInstance;
121
122    instance->ref();
123
124    // Instantiate the V8 object and remember it
125    v8::Handle<v8::Object> result = instantiateV8Object(V8ClassIndex::SVGELEMENTINSTANCE, V8ClassIndex::SVGELEMENTINSTANCE, instance);
126    if (!result.IsEmpty()) {
127        // Only update the DOM SVG element map if the result is non-empty.
128        getDOMSVGElementInstanceMap().set(instance, v8::Persistent<v8::Object>::New(result));
129    }
130    return result;
131}
132
133v8::Handle<v8::Value> V8DOMWrapper::convertSVGObjectWithContextToV8Object(V8ClassIndex::V8WrapperType type, void* object)
134{
135    if (!object)
136        return v8::Null();
137
138    v8::Persistent<v8::Object> result = getDOMSVGObjectWithContextMap().get(object);
139    if (!result.IsEmpty())
140        return result;
141
142    // Special case: SVGPathSegs need to be downcast to their real type
143    if (type == V8ClassIndex::SVGPATHSEG)
144        type = downcastSVGPathSeg(object);
145
146    v8::Local<v8::Object> v8Object = instantiateV8Object(type, type, object);
147    if (!v8Object.IsEmpty()) {
148        result = v8::Persistent<v8::Object>::New(v8Object);
149        switch (type) {
150#define MAKE_CASE(TYPE, NAME)     \
151        case V8ClassIndex::TYPE: static_cast<NAME*>(object)->ref(); break;
152        SVG_OBJECT_TYPES(MAKE_CASE)
153#undef MAKE_CASE
154#define MAKE_CASE(TYPE, NAME)     \
155        case V8ClassIndex::TYPE:    \
156            static_cast<V8SVGPODTypeWrapper<NAME>*>(object)->ref(); break;
157        SVG_POD_NATIVE_TYPES(MAKE_CASE)
158#undef MAKE_CASE
159        default:
160            ASSERT_NOT_REACHED();
161        }
162        getDOMSVGObjectWithContextMap().set(object, result);
163    }
164
165    return result;
166}
167
168#endif // ENABLE(SVG)
169
170#if ENABLE(3D_CANVAS)
171void V8DOMWrapper::setIndexedPropertiesToExternalArray(v8::Handle<v8::Object> wrapper,
172                                                       int index,
173                                                       void* address,
174                                                       int length)
175{
176    v8::ExternalArrayType array_type = v8::kExternalByteArray;
177    V8ClassIndex::V8WrapperType classIndex = V8ClassIndex::FromInt(index);
178    switch (classIndex) {
179    case V8ClassIndex::WEBGLBYTEARRAY:
180        array_type = v8::kExternalByteArray;
181        break;
182    case V8ClassIndex::WEBGLUNSIGNEDBYTEARRAY:
183        array_type = v8::kExternalUnsignedByteArray;
184        break;
185    case V8ClassIndex::WEBGLSHORTARRAY:
186        array_type = v8::kExternalShortArray;
187        break;
188    case V8ClassIndex::WEBGLUNSIGNEDSHORTARRAY:
189        array_type = v8::kExternalUnsignedShortArray;
190        break;
191    case V8ClassIndex::WEBGLINTARRAY:
192        array_type = v8::kExternalIntArray;
193        break;
194    case V8ClassIndex::WEBGLUNSIGNEDINTARRAY:
195        array_type = v8::kExternalUnsignedIntArray;
196        break;
197    case V8ClassIndex::WEBGLFLOATARRAY:
198        array_type = v8::kExternalFloatArray;
199        break;
200    default:
201        ASSERT_NOT_REACHED();
202    }
203    wrapper->SetIndexedPropertiesToExternalArrayData(address,
204                                                     array_type,
205                                                     length);
206}
207#endif
208
209// The caller must have increased obj's ref count.
210void V8DOMWrapper::setJSWrapperForDOMObject(void* object, v8::Persistent<v8::Object> wrapper)
211{
212    ASSERT(V8DOMWrapper::maybeDOMWrapper(wrapper));
213#ifndef NDEBUG
214    V8ClassIndex::V8WrapperType type = V8DOMWrapper::domWrapperType(wrapper);
215    switch (type) {
216#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE:
217        ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
218        ASSERT_NOT_REACHED();
219#undef MAKE_CASE
220    default:
221        break;
222    }
223#endif
224    getDOMObjectMap().set(object, wrapper);
225}
226
227// The caller must have increased obj's ref count.
228void V8DOMWrapper::setJSWrapperForActiveDOMObject(void* object, v8::Persistent<v8::Object> wrapper)
229{
230    ASSERT(V8DOMWrapper::maybeDOMWrapper(wrapper));
231#ifndef NDEBUG
232    V8ClassIndex::V8WrapperType type = V8DOMWrapper::domWrapperType(wrapper);
233    switch (type) {
234#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: break;
235        ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
236    default:
237        ASSERT_NOT_REACHED();
238#undef MAKE_CASE
239    }
240#endif
241    getActiveDOMObjectMap().set(object, wrapper);
242}
243
244// The caller must have increased node's ref count.
245void V8DOMWrapper::setJSWrapperForDOMNode(Node* node, v8::Persistent<v8::Object> wrapper)
246{
247    ASSERT(V8DOMWrapper::maybeDOMWrapper(wrapper));
248    getDOMNodeMap().set(node, wrapper);
249}
250
251v8::Persistent<v8::FunctionTemplate> V8DOMWrapper::getTemplate(V8ClassIndex::V8WrapperType type)
252{
253    v8::Persistent<v8::FunctionTemplate>* cacheCell = V8ClassIndex::GetCache(type);
254    if (!cacheCell->IsEmpty())
255        return *cacheCell;
256
257    // Not in the cache.
258    FunctionTemplateFactory factory = V8ClassIndex::GetFactory(type);
259    v8::Persistent<v8::FunctionTemplate> descriptor = factory();
260
261    *cacheCell = descriptor;
262    return descriptor;
263}
264
265v8::Local<v8::Function> V8DOMWrapper::getConstructor(V8ClassIndex::V8WrapperType type, v8::Handle<v8::Value> objectPrototype)
266{
267    // A DOM constructor is a function instance created from a DOM constructor
268    // template. There is one instance per context. A DOM constructor is
269    // different from a normal function in two ways:
270    //   1) it cannot be called as constructor (aka, used to create a DOM object)
271    //   2) its __proto__ points to Object.prototype rather than
272    //      Function.prototype.
273    // The reason for 2) is that, in Safari, a DOM constructor is a normal JS
274    // object, but not a function. Hotmail relies on the fact that, in Safari,
275    // HTMLElement.__proto__ == Object.prototype.
276    v8::Handle<v8::FunctionTemplate> functionTemplate = getTemplate(type);
277    // Getting the function might fail if we're running out of
278    // stack or memory.
279    v8::TryCatch tryCatch;
280    v8::Local<v8::Function> value = functionTemplate->GetFunction();
281    if (value.IsEmpty())
282        return v8::Local<v8::Function>();
283    // Hotmail fix, see comments above.
284    if (!objectPrototype.IsEmpty())
285        value->Set(v8::String::New("__proto__"), objectPrototype);
286    return value;
287}
288
289v8::Local<v8::Function> V8DOMWrapper::getConstructorForContext(V8ClassIndex::V8WrapperType type, v8::Handle<v8::Context> context)
290{
291    // Enter the scope for this context to get the correct constructor.
292    v8::Context::Scope scope(context);
293
294    return getConstructor(type, V8DOMWindowShell::getHiddenObjectPrototype(context));
295}
296
297v8::Local<v8::Function> V8DOMWrapper::getConstructor(V8ClassIndex::V8WrapperType type, DOMWindow* window)
298{
299    Frame* frame = window->frame();
300    if (!frame)
301        return v8::Local<v8::Function>();
302
303    v8::Handle<v8::Context> context = V8Proxy::context(frame);
304    if (context.IsEmpty())
305        return v8::Local<v8::Function>();
306
307    return getConstructorForContext(type, context);
308}
309
310v8::Local<v8::Function> V8DOMWrapper::getConstructor(V8ClassIndex::V8WrapperType type, WorkerContext*)
311{
312    WorkerContextExecutionProxy* proxy = WorkerContextExecutionProxy::retrieve();
313    if (!proxy)
314        return v8::Local<v8::Function>();
315
316    v8::Handle<v8::Context> context = proxy->context();
317    if (context.IsEmpty())
318        return v8::Local<v8::Function>();
319
320    return getConstructorForContext(type, context);
321}
322
323v8::Handle<v8::Value> V8DOMWrapper::convertToV8Object(V8ClassIndex::V8WrapperType type, void* impl)
324{
325    ASSERT(type != V8ClassIndex::EVENTLISTENER);
326    ASSERT(type != V8ClassIndex::EVENTTARGET);
327    ASSERT(type != V8ClassIndex::EVENT);
328
329    // These objects can be constructed under WorkerContextExecutionProxy.  They need special
330    // handling, since if we proceed below V8Proxy::retrieve() will get called and will crash.
331    // TODO(ukai): websocket?
332    if ((type == V8ClassIndex::DOMCOREEXCEPTION
333         || type == V8ClassIndex::RANGEEXCEPTION
334         || type == V8ClassIndex::EVENTEXCEPTION
335         || type == V8ClassIndex::XMLHTTPREQUESTEXCEPTION
336         || type == V8ClassIndex::MESSAGEPORT)
337        && WorkerContextExecutionProxy::retrieve()) {
338        return WorkerContextExecutionProxy::convertToV8Object(type, impl);
339    }
340
341    bool isActiveDomObject = false;
342    switch (type) {
343#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE:
344        DOM_NODE_TYPES(MAKE_CASE)
345#if ENABLE(SVG)
346        SVG_NODE_TYPES(MAKE_CASE)
347#endif
348        return convertNodeToV8Object(static_cast<Node*>(impl));
349    case V8ClassIndex::CSSVALUE:
350        return convertCSSValueToV8Object(static_cast<CSSValue*>(impl));
351    case V8ClassIndex::CSSRULE:
352        return convertCSSRuleToV8Object(static_cast<CSSRule*>(impl));
353    case V8ClassIndex::STYLESHEET:
354        return convertStyleSheetToV8Object(static_cast<StyleSheet*>(impl));
355    case V8ClassIndex::DOMWINDOW:
356        return convertWindowToV8Object(static_cast<DOMWindow*>(impl));
357    case V8ClassIndex::NAMEDNODEMAP:
358        return convertNamedNodeMapToV8Object(static_cast<NamedNodeMap*>(impl));
359#if ENABLE(SVG)
360        SVG_NONNODE_TYPES(MAKE_CASE)
361        if (type == V8ClassIndex::SVGELEMENTINSTANCE)
362            return convertSVGElementInstanceToV8Object(static_cast<SVGElementInstance*>(impl));
363        return convertSVGObjectWithContextToV8Object(type, impl);
364#endif
365
366        ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
367        isActiveDomObject = true;
368        break;
369    default:
370        break;
371  }
372
373#undef MAKE_CASE
374
375    if (!impl)
376        return v8::Null();
377
378    // Non DOM node
379    v8::Persistent<v8::Object> result = isActiveDomObject ? getActiveDOMObjectMap().get(impl) : getDOMObjectMap().get(impl);
380    if (result.IsEmpty()) {
381#if ENABLE(3D_CANVAS)
382        if (type == V8ClassIndex::WEBGLARRAY && impl) {
383            // Determine which subclass we are wrapping.
384            WebGLArray* array = reinterpret_cast<WebGLArray*>(impl);
385            if (array->isByteArray())
386                type = V8ClassIndex::WEBGLBYTEARRAY;
387            else if (array->isFloatArray())
388                type = V8ClassIndex::WEBGLFLOATARRAY;
389            else if (array->isIntArray())
390                type = V8ClassIndex::WEBGLINTARRAY;
391            else if (array->isShortArray())
392                type = V8ClassIndex::WEBGLSHORTARRAY;
393            else if (array->isUnsignedByteArray())
394                type = V8ClassIndex::WEBGLUNSIGNEDBYTEARRAY;
395            else if (array->isUnsignedIntArray())
396                type = V8ClassIndex::WEBGLUNSIGNEDINTARRAY;
397            else if (array->isUnsignedShortArray())
398                type = V8ClassIndex::WEBGLUNSIGNEDSHORTARRAY;
399        }
400#endif
401
402        v8::Local<v8::Object> v8Object = instantiateV8Object(type, type, impl);
403        if (!v8Object.IsEmpty()) {
404            // Go through big switch statement, it has some duplications
405            // that were handled by code above (such as CSSVALUE, CSSRULE, etc).
406            switch (type) {
407#define MAKE_CASE(TYPE, NAME) \
408            case V8ClassIndex::TYPE: static_cast<NAME*>(impl)->ref(); break;
409                DOM_OBJECT_TYPES(MAKE_CASE)
410#undef MAKE_CASE
411            default:
412                ASSERT_NOT_REACHED();
413            }
414            result = v8::Persistent<v8::Object>::New(v8Object);
415            if (isActiveDomObject)
416                setJSWrapperForActiveDOMObject(impl, result);
417            else
418                setJSWrapperForDOMObject(impl, result);
419
420            if (type == V8ClassIndex::CANVASPIXELARRAY) {
421                CanvasPixelArray* pixels = reinterpret_cast<CanvasPixelArray*>(impl);
422                result->SetIndexedPropertiesToPixelData(pixels->data()->data(), pixels->length());
423            }
424
425#if ENABLE(3D_CANVAS)
426            // Set up WebGLArray subclasses' accesses similarly.
427            switch (type) {
428            case V8ClassIndex::WEBGLBYTEARRAY:
429            case V8ClassIndex::WEBGLUNSIGNEDBYTEARRAY:
430            case V8ClassIndex::WEBGLSHORTARRAY:
431            case V8ClassIndex::WEBGLUNSIGNEDSHORTARRAY:
432            case V8ClassIndex::WEBGLINTARRAY:
433            case V8ClassIndex::WEBGLUNSIGNEDINTARRAY:
434            case V8ClassIndex::WEBGLFLOATARRAY: {
435                WebGLArray* array = reinterpret_cast<WebGLArray*>(impl);
436                setIndexedPropertiesToExternalArray(result,
437                                                    V8ClassIndex::ToInt(type),
438                                                    array->baseAddress(),
439                                                    array->length());
440                break;
441            }
442            default:
443                break;
444            }
445#endif
446
447            // Special case for non-node objects associated with a
448            // DOMWindow. Both Safari and FF let the JS wrappers for these
449            // objects survive GC. To mimic their behavior, V8 creates
450            // hidden references from the DOMWindow to these wrapper
451            // objects. These references get cleared when the DOMWindow is
452            // reused by a new page.
453            switch (type) {
454            case V8ClassIndex::CONSOLE:
455                setHiddenWindowReference(static_cast<Console*>(impl)->frame(), V8DOMWindow::consoleIndex, result);
456                break;
457            case V8ClassIndex::HISTORY:
458                setHiddenWindowReference(static_cast<History*>(impl)->frame(), V8DOMWindow::historyIndex, result);
459                break;
460            case V8ClassIndex::NAVIGATOR:
461                setHiddenWindowReference(static_cast<Navigator*>(impl)->frame(), V8DOMWindow::navigatorIndex, result);
462                break;
463            case V8ClassIndex::SCREEN:
464                setHiddenWindowReference(static_cast<Screen*>(impl)->frame(), V8DOMWindow::screenIndex, result);
465                break;
466            case V8ClassIndex::LOCATION:
467                setHiddenWindowReference(static_cast<Location*>(impl)->frame(), V8DOMWindow::locationIndex, result);
468                break;
469            case V8ClassIndex::DOMSELECTION:
470                setHiddenWindowReference(static_cast<DOMSelection*>(impl)->frame(), V8DOMWindow::domSelectionIndex, result);
471                break;
472            case V8ClassIndex::BARINFO: {
473                BarInfo* barInfo = static_cast<BarInfo*>(impl);
474                Frame* frame = barInfo->frame();
475                switch (barInfo->type()) {
476                case BarInfo::Locationbar:
477                    setHiddenWindowReference(frame, V8DOMWindow::locationbarIndex, result);
478                    break;
479                case BarInfo::Menubar:
480                    setHiddenWindowReference(frame, V8DOMWindow::menubarIndex, result);
481                    break;
482                case BarInfo::Personalbar:
483                    setHiddenWindowReference(frame, V8DOMWindow::personalbarIndex, result);
484                    break;
485                case BarInfo::Scrollbars:
486                    setHiddenWindowReference(frame, V8DOMWindow::scrollbarsIndex, result);
487                    break;
488                case BarInfo::Statusbar:
489                    setHiddenWindowReference(frame, V8DOMWindow::statusbarIndex, result);
490                    break;
491                case BarInfo::Toolbar:
492                    setHiddenWindowReference(frame, V8DOMWindow::toolbarIndex, result);
493                    break;
494                }
495                break;
496            }
497            default:
498                break;
499            }
500        }
501    }
502    return result;
503}
504
505void V8DOMWrapper::setHiddenWindowReference(Frame* frame, const int internalIndex, v8::Handle<v8::Object> jsObject)
506{
507    // Get DOMWindow
508    if (!frame)
509        return; // Object might be detached from window
510    v8::Handle<v8::Context> context = V8Proxy::context(frame);
511    if (context.IsEmpty())
512        return;
513
514    ASSERT(internalIndex < V8DOMWindow::internalFieldCount);
515
516    v8::Handle<v8::Object> global = context->Global();
517    // Look for real DOM wrapper.
518    global = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, global);
519    ASSERT(!global.IsEmpty());
520    ASSERT(global->GetInternalField(internalIndex)->IsUndefined());
521    global->SetInternalField(internalIndex, jsObject);
522}
523
524V8ClassIndex::V8WrapperType V8DOMWrapper::domWrapperType(v8::Handle<v8::Object> object)
525{
526    ASSERT(V8DOMWrapper::maybeDOMWrapper(object));
527    v8::Handle<v8::Value> type = object->GetInternalField(v8DOMWrapperTypeIndex);
528    return V8ClassIndex::FromInt(type->Int32Value());
529}
530
531PassRefPtr<NodeFilter> V8DOMWrapper::wrapNativeNodeFilter(v8::Handle<v8::Value> filter)
532{
533    // A NodeFilter is used when walking through a DOM tree or iterating tree
534    // nodes.
535    // FIXME: we may want to cache NodeFilterCondition and NodeFilter
536    // object, but it is minor.
537    // NodeFilter is passed to NodeIterator that has a ref counted pointer
538    // to NodeFilter. NodeFilter has a ref counted pointer to NodeFilterCondition.
539    // In NodeFilterCondition, filter object is persisted in its constructor,
540    // and disposed in its destructor.
541    if (!filter->IsFunction())
542        return 0;
543
544    NodeFilterCondition* condition = new V8NodeFilterCondition(filter);
545    return NodeFilter::create(condition);
546}
547
548v8::Local<v8::Object> V8DOMWrapper::instantiateV8Object(V8Proxy* proxy, V8ClassIndex::V8WrapperType descriptorType, V8ClassIndex::V8WrapperType cptrType, void* impl)
549{
550    // Make a special case for document.all
551    if (descriptorType == V8ClassIndex::HTMLCOLLECTION && static_cast<HTMLCollection*>(impl)->type() == DocAll)
552        descriptorType = V8ClassIndex::HTMLALLCOLLECTION;
553
554    if (V8IsolatedContext::getEntered()) {
555        // This effectively disables the wrapper cache for isolated worlds.
556        proxy = 0;
557        // FIXME: Do we need a wrapper cache for the isolated world?  We should
558        //        see if the performance gains are worth while.
559        // We'll get one once we give the isolated context a proper window shell.
560    } else if (!proxy)
561        proxy = V8Proxy::retrieve();
562
563    v8::Local<v8::Object> instance;
564    if (proxy)
565        // FIXME: Fix this to work properly with isolated worlds (see above).
566        instance = proxy->windowShell()->createWrapperFromCache(descriptorType);
567    else {
568        v8::Local<v8::Function> function = getTemplate(descriptorType)->GetFunction();
569        instance = SafeAllocation::newInstance(function);
570    }
571    if (!instance.IsEmpty()) {
572        // Avoid setting the DOM wrapper for failed allocations.
573        setDOMWrapper(instance, V8ClassIndex::ToInt(cptrType), impl);
574    }
575    return instance;
576}
577
578#ifndef NDEBUG
579bool V8DOMWrapper::maybeDOMWrapper(v8::Handle<v8::Value> value)
580{
581    if (value.IsEmpty() || !value->IsObject())
582        return false;
583
584    v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value);
585    if (!object->InternalFieldCount())
586        return false;
587
588    ASSERT(object->InternalFieldCount() >= v8DefaultWrapperInternalFieldCount);
589
590    v8::Handle<v8::Value> type = object->GetInternalField(v8DOMWrapperTypeIndex);
591    ASSERT(type->IsInt32());
592    ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() && type->Int32Value() < V8ClassIndex::CLASSINDEX_END);
593
594    v8::Handle<v8::Value> wrapper = object->GetInternalField(v8DOMWrapperObjectIndex);
595    ASSERT(wrapper->IsNumber() || wrapper->IsExternal());
596
597    return true;
598}
599#endif
600
601bool V8DOMWrapper::isDOMEventWrapper(v8::Handle<v8::Value> value)
602{
603    // All kinds of events use EVENT as dom type in JS wrappers.
604    // See EventToV8Object
605    return isWrapperOfType(value, V8ClassIndex::EVENT);
606}
607
608bool V8DOMWrapper::isWrapperOfType(v8::Handle<v8::Value> value, V8ClassIndex::V8WrapperType classType)
609{
610    if (value.IsEmpty() || !value->IsObject())
611        return false;
612
613    v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value);
614    if (!object->InternalFieldCount())
615        return false;
616
617    ASSERT(object->InternalFieldCount() >= v8DefaultWrapperInternalFieldCount);
618
619    v8::Handle<v8::Value> wrapper = object->GetInternalField(v8DOMWrapperObjectIndex);
620    ASSERT(wrapper->IsNumber() || wrapper->IsExternal());
621
622    v8::Handle<v8::Value> type = object->GetInternalField(v8DOMWrapperTypeIndex);
623    ASSERT(type->IsInt32());
624    ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() && type->Int32Value() < V8ClassIndex::CLASSINDEX_END);
625
626    return V8ClassIndex::FromInt(type->Int32Value()) == classType;
627}
628
629#if ENABLE(VIDEO)
630#define FOR_EACH_VIDEO_TAG(macro)                  \
631    macro(audio, AUDIO)                            \
632    macro(source, SOURCE)                          \
633    macro(video, VIDEO)
634#else
635#define FOR_EACH_VIDEO_TAG(macro)
636#endif
637
638#if ENABLE(DATAGRID)
639#define FOR_EACH_DATAGRID_TAG(macro)               \
640    macro(datagrid, DATAGRID)                        \
641    macro(dcell, DATAGRIDCELL)                       \
642    macro(dcol, DATAGRIDCOL)                         \
643    macro(drow, DATAGRIDROW)
644#else
645#define FOR_EACH_DATAGRID_TAG(macro)
646#endif
647
648#define FOR_EACH_TAG(macro)                        \
649    FOR_EACH_DATAGRID_TAG(macro)                   \
650    macro(a, ANCHOR)                               \
651    macro(applet, APPLET)                          \
652    macro(area, AREA)                              \
653    macro(base, BASE)                              \
654    macro(basefont, BASEFONT)                      \
655    macro(blockquote, BLOCKQUOTE)                  \
656    macro(body, BODY)                              \
657    macro(br, BR)                                  \
658    macro(button, BUTTON)                          \
659    macro(caption, TABLECAPTION)                   \
660    macro(col, TABLECOL)                           \
661    macro(colgroup, TABLECOL)                      \
662    macro(del, MOD)                                \
663    macro(canvas, CANVAS)                          \
664    macro(dir, DIRECTORY)                          \
665    macro(div, DIV)                                \
666    macro(dl, DLIST)                               \
667    macro(embed, EMBED)                            \
668    macro(fieldset, FIELDSET)                      \
669    macro(font, FONT)                              \
670    macro(form, FORM)                              \
671    macro(frame, FRAME)                            \
672    macro(frameset, FRAMESET)                      \
673    macro(h1, HEADING)                             \
674    macro(h2, HEADING)                             \
675    macro(h3, HEADING)                             \
676    macro(h4, HEADING)                             \
677    macro(h5, HEADING)                             \
678    macro(h6, HEADING)                             \
679    macro(head, HEAD)                              \
680    macro(hr, HR)                                  \
681    macro(html, HTML)                              \
682    macro(img, IMAGE)                              \
683    macro(iframe, IFRAME)                          \
684    macro(image, IMAGE)                            \
685    macro(input, INPUT)                            \
686    macro(ins, MOD)                                \
687    macro(isindex, ISINDEX)                        \
688    macro(keygen, SELECT)                          \
689    macro(label, LABEL)                            \
690    macro(legend, LEGEND)                          \
691    macro(li, LI)                                  \
692    macro(link, LINK)                              \
693    macro(listing, PRE)                            \
694    macro(map, MAP)                                \
695    macro(marquee, MARQUEE)                        \
696    macro(menu, MENU)                              \
697    macro(meta, META)                              \
698    macro(object, OBJECT)                          \
699    macro(ol, OLIST)                               \
700    macro(optgroup, OPTGROUP)                      \
701    macro(option, OPTION)                          \
702    macro(p, PARAGRAPH)                            \
703    macro(param, PARAM)                            \
704    macro(pre, PRE)                                \
705    macro(q, QUOTE)                                \
706    macro(script, SCRIPT)                          \
707    macro(select, SELECT)                          \
708    macro(style, STYLE)                            \
709    macro(table, TABLE)                            \
710    macro(thead, TABLESECTION)                     \
711    macro(tbody, TABLESECTION)                     \
712    macro(tfoot, TABLESECTION)                     \
713    macro(td, TABLECELL)                           \
714    macro(th, TABLECELL)                           \
715    macro(tr, TABLEROW)                            \
716    macro(textarea, TEXTAREA)                      \
717    macro(title, TITLE)                            \
718    macro(ul, ULIST)                               \
719    macro(xmp, PRE)
720
721V8ClassIndex::V8WrapperType V8DOMWrapper::htmlElementType(HTMLElement* element)
722{
723    typedef HashMap<String, V8ClassIndex::V8WrapperType> WrapperTypeMap;
724    DEFINE_STATIC_LOCAL(WrapperTypeMap, wrapperTypeMap, ());
725    if (wrapperTypeMap.isEmpty()) {
726#define ADD_TO_HASH_MAP(tag, name) \
727        wrapperTypeMap.set(#tag, V8ClassIndex::HTML##name##ELEMENT);
728        FOR_EACH_TAG(ADD_TO_HASH_MAP)
729#if ENABLE(VIDEO)
730        if (MediaPlayer::isAvailable()) {
731            FOR_EACH_VIDEO_TAG(ADD_TO_HASH_MAP)
732        }
733#endif
734#undef ADD_TO_HASH_MAP
735    }
736
737    V8ClassIndex::V8WrapperType type = wrapperTypeMap.get(element->localName().impl());
738    if (!type)
739        return V8ClassIndex::HTMLELEMENT;
740    return type;
741}
742#undef FOR_EACH_TAG
743
744#if ENABLE(SVG)
745
746#if ENABLE(SVG_ANIMATION)
747#define FOR_EACH_ANIMATION_TAG(macro) \
748    macro(animateColor, ANIMATECOLOR) \
749    macro(animate, ANIMATE) \
750    macro(animateTransform, ANIMATETRANSFORM) \
751    macro(set, SET)
752#else
753#define FOR_EACH_ANIMATION_TAG(macro)
754#endif
755
756#if ENABLE(SVG) && ENABLE(FILTERS)
757#define FOR_EACH_FILTERS_TAG(macro) \
758    macro(feBlend, FEBLEND) \
759    macro(feColorMatrix, FECOLORMATRIX) \
760    macro(feComponentTransfer, FECOMPONENTTRANSFER) \
761    macro(feComposite, FECOMPOSITE) \
762    macro(feDiffuseLighting, FEDIFFUSELIGHTING) \
763    macro(feDisplacementMap, FEDISPLACEMENTMAP) \
764    macro(feDistantLight, FEDISTANTLIGHT) \
765    macro(feFlood, FEFLOOD) \
766    macro(feFuncA, FEFUNCA) \
767    macro(feFuncB, FEFUNCB) \
768    macro(feFuncG, FEFUNCG) \
769    macro(feFuncR, FEFUNCR) \
770    macro(feGaussianBlur, FEGAUSSIANBLUR) \
771    macro(feImage, FEIMAGE) \
772    macro(feMerge, FEMERGE) \
773    macro(feMergeNode, FEMERGENODE) \
774    macro(feMorphology, FEMORPHOLOGY) \
775    macro(feOffset, FEOFFSET) \
776    macro(fePointLight, FEPOINTLIGHT) \
777    macro(feSpecularLighting, FESPECULARLIGHTING) \
778    macro(feSpotLight, FESPOTLIGHT) \
779    macro(feTile, FETILE) \
780    macro(feTurbulence, FETURBULENCE) \
781    macro(filter, FILTER)
782#else
783#define FOR_EACH_FILTERS_TAG(macro)
784#endif
785
786#if ENABLE(SVG_FONTS)
787#define FOR_EACH_FONTS_TAG(macro) \
788    macro(font-face, FONTFACE) \
789    macro(font-face-format, FONTFACEFORMAT) \
790    macro(font-face-name, FONTFACENAME) \
791    macro(font-face-src, FONTFACESRC) \
792    macro(font-face-uri, FONTFACEURI)
793#else
794#define FOR_EACH_FONTS_TAG(marco)
795#endif
796
797#if ENABLE(SVG_FOREIGN_OBJECT)
798#define FOR_EACH_FOREIGN_OBJECT_TAG(macro) \
799    macro(foreignObject, FOREIGNOBJECT)
800#else
801#define FOR_EACH_FOREIGN_OBJECT_TAG(macro)
802#endif
803
804#if ENABLE(SVG_USE)
805#define FOR_EACH_USE_TAG(macro) \
806    macro(use, USE)
807#else
808#define FOR_EACH_USE_TAG(macro)
809#endif
810
811#define FOR_EACH_TAG(macro) \
812    FOR_EACH_ANIMATION_TAG(macro) \
813    FOR_EACH_FILTERS_TAG(macro) \
814    FOR_EACH_FONTS_TAG(macro) \
815    FOR_EACH_FOREIGN_OBJECT_TAG(macro) \
816    FOR_EACH_USE_TAG(macro) \
817    macro(a, A) \
818    macro(altGlyph, ALTGLYPH) \
819    macro(circle, CIRCLE) \
820    macro(clipPath, CLIPPATH) \
821    macro(cursor, CURSOR) \
822    macro(defs, DEFS) \
823    macro(desc, DESC) \
824    macro(ellipse, ELLIPSE) \
825    macro(g, G) \
826    macro(glyph, GLYPH) \
827    macro(image, IMAGE) \
828    macro(linearGradient, LINEARGRADIENT) \
829    macro(line, LINE) \
830    macro(marker, MARKER) \
831    macro(mask, MASK) \
832    macro(metadata, METADATA) \
833    macro(path, PATH) \
834    macro(pattern, PATTERN) \
835    macro(polyline, POLYLINE) \
836    macro(polygon, POLYGON) \
837    macro(radialGradient, RADIALGRADIENT) \
838    macro(rect, RECT) \
839    macro(script, SCRIPT) \
840    macro(stop, STOP) \
841    macro(style, STYLE) \
842    macro(svg, SVG) \
843    macro(switch, SWITCH) \
844    macro(symbol, SYMBOL) \
845    macro(text, TEXT) \
846    macro(textPath, TEXTPATH) \
847    macro(title, TITLE) \
848    macro(tref, TREF) \
849    macro(tspan, TSPAN) \
850    macro(view, VIEW) \
851    // end of macro
852
853V8ClassIndex::V8WrapperType V8DOMWrapper::svgElementType(SVGElement* element)
854{
855    typedef HashMap<String, V8ClassIndex::V8WrapperType> WrapperTypeMap;
856    DEFINE_STATIC_LOCAL(WrapperTypeMap, wrapperTypeMap, ());
857    if (wrapperTypeMap.isEmpty()) {
858#define ADD_TO_HASH_MAP(tag, name) \
859        wrapperTypeMap.set(#tag, V8ClassIndex::SVG##name##ELEMENT);
860        FOR_EACH_TAG(ADD_TO_HASH_MAP)
861#undef ADD_TO_HASH_MAP
862    }
863
864    V8ClassIndex::V8WrapperType type = wrapperTypeMap.get(element->localName().impl());
865    if (!type)
866        return V8ClassIndex::SVGELEMENT;
867    return type;
868}
869#undef FOR_EACH_TAG
870
871#endif // ENABLE(SVG)
872
873v8::Handle<v8::Value> V8DOMWrapper::convertEventToV8Object(Event* event)
874{
875    if (!event)
876        return v8::Null();
877
878    v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(event);
879    if (!wrapper.IsEmpty())
880        return wrapper;
881
882    V8ClassIndex::V8WrapperType type = V8ClassIndex::EVENT;
883
884    if (event->isUIEvent()) {
885        if (event->isKeyboardEvent())
886            type = V8ClassIndex::KEYBOARDEVENT;
887        else if (event->isTextEvent())
888            type = V8ClassIndex::TEXTEVENT;
889        else if (event->isMouseEvent())
890            type = V8ClassIndex::MOUSEEVENT;
891        else if (event->isWheelEvent())
892            type = V8ClassIndex::WHEELEVENT;
893// ANDROID: Upstream TOUCH_EVENTS.
894#if ENABLE(TOUCH_EVENTS)
895        else if (event->isTouchEvent())
896            type = V8ClassIndex::TOUCHEVENT;
897#endif
898#if ENABLE(SVG)
899        else if (event->isSVGZoomEvent())
900            type = V8ClassIndex::SVGZOOMEVENT;
901#endif
902        else if (event->isCompositionEvent())
903            type = V8ClassIndex::COMPOSITIONEVENT;
904        else
905            type = V8ClassIndex::UIEVENT;
906    } else if (event->isMutationEvent())
907        type = V8ClassIndex::MUTATIONEVENT;
908    else if (event->isOverflowEvent())
909        type = V8ClassIndex::OVERFLOWEVENT;
910    else if (event->isMessageEvent())
911        type = V8ClassIndex::MESSAGEEVENT;
912    else if (event->isPageTransitionEvent())
913        type = V8ClassIndex::PAGETRANSITIONEVENT;
914    else if (event->isPopStateEvent())
915        type = V8ClassIndex::POPSTATEEVENT;
916    else if (event->isProgressEvent()) {
917        if (event->isXMLHttpRequestProgressEvent())
918            type = V8ClassIndex::XMLHTTPREQUESTPROGRESSEVENT;
919        else
920            type = V8ClassIndex::PROGRESSEVENT;
921    } else if (event->isWebKitAnimationEvent())
922        type = V8ClassIndex::WEBKITANIMATIONEVENT;
923    else if (event->isWebKitTransitionEvent())
924        type = V8ClassIndex::WEBKITTRANSITIONEVENT;
925#if ENABLE(WORKERS)
926    else if (event->isErrorEvent())
927        type = V8ClassIndex::ERROREVENT;
928#endif
929#if ENABLE(DOM_STORAGE)
930    else if (event->isStorageEvent())
931        type = V8ClassIndex::STORAGEEVENT;
932#endif
933    else if (event->isBeforeLoadEvent())
934        type = V8ClassIndex::BEFORELOADEVENT;
935
936
937    v8::Handle<v8::Object> result = instantiateV8Object(type, V8ClassIndex::EVENT, event);
938    if (result.IsEmpty()) {
939        // Instantiation failed. Avoid updating the DOM object map and
940        // return null which is already handled by callers of this function
941        // in case the event is NULL.
942        return v8::Null();
943    }
944
945    event->ref(); // fast ref
946    setJSWrapperForDOMObject(event, v8::Persistent<v8::Object>::New(result));
947
948    return result;
949}
950
951static const V8ClassIndex::V8WrapperType mapping[] = {
952    V8ClassIndex::INVALID_CLASS_INDEX,    // NONE
953    V8ClassIndex::INVALID_CLASS_INDEX,    // ELEMENT_NODE needs special treatment
954    V8ClassIndex::ATTR,                   // ATTRIBUTE_NODE
955    V8ClassIndex::TEXT,                   // TEXT_NODE
956    V8ClassIndex::CDATASECTION,           // CDATA_SECTION_NODE
957    V8ClassIndex::ENTITYREFERENCE,        // ENTITY_REFERENCE_NODE
958    V8ClassIndex::ENTITY,                 // ENTITY_NODE
959    V8ClassIndex::PROCESSINGINSTRUCTION,  // PROCESSING_INSTRUCTION_NODE
960    V8ClassIndex::COMMENT,                // COMMENT_NODE
961    V8ClassIndex::INVALID_CLASS_INDEX,    // DOCUMENT_NODE needs special treatment
962    V8ClassIndex::DOCUMENTTYPE,           // DOCUMENT_TYPE_NODE
963    V8ClassIndex::DOCUMENTFRAGMENT,       // DOCUMENT_FRAGMENT_NODE
964    V8ClassIndex::NOTATION,               // NOTATION_NODE
965    V8ClassIndex::NODE,                   // XPATH_NAMESPACE_NODE
966};
967
968v8::Handle<v8::Value> V8DOMWrapper::convertDocumentToV8Object(Document* document)
969{
970    // Find a proxy for this node.
971    //
972    // Note that if proxy is found, we might initialize the context which can
973    // instantiate a document wrapper.  Therefore, we get the proxy before
974    // checking if the node already has a wrapper.
975    V8Proxy* proxy = V8Proxy::retrieve(document->frame());
976    if (proxy)
977        proxy->windowShell()->initContextIfNeeded();
978
979    DOMNodeMapping& domNodeMap = getDOMNodeMap();
980    v8::Handle<v8::Object> wrapper = domNodeMap.get(document);
981    if (wrapper.IsEmpty())
982        return convertNewNodeToV8Object(document, proxy, domNodeMap);
983
984    return wrapper;
985}
986
987static v8::Handle<v8::Value> getWrapper(Node* node)
988{
989    ASSERT(WTF::isMainThread());
990    V8IsolatedContext* context = V8IsolatedContext::getEntered();
991    if (LIKELY(!context)) {
992        v8::Persistent<v8::Object>* wrapper = node->wrapper();
993        if (!wrapper)
994            return v8::Handle<v8::Value>();
995        return *wrapper;
996    }
997
998    DOMNodeMapping& domNodeMap = context->world()->domDataStore()->domNodeMap();
999    return domNodeMap.get(node);
1000}
1001
1002v8::Handle<v8::Value> V8DOMWrapper::convertNodeToV8Object(Node* node)
1003{
1004    if (!node)
1005        return v8::Null();
1006
1007    v8::Handle<v8::Value> wrapper = getWrapper(node);
1008    if (!wrapper.IsEmpty())
1009        return wrapper;
1010
1011    Document* document = node->document();
1012    if (node == document)
1013        return convertDocumentToV8Object(document);
1014
1015    return convertNewNodeToV8Object(node, 0, getDOMNodeMap());
1016}
1017
1018// Caller checks node is not null.
1019v8::Handle<v8::Value> V8DOMWrapper::convertNewNodeToV8Object(Node* node, V8Proxy* proxy, DOMNodeMapping& domNodeMap)
1020{
1021    if (!proxy && node->document())
1022        proxy = V8Proxy::retrieve(node->document()->frame());
1023
1024    bool isDocument = false; // document type node has special handling
1025    V8ClassIndex::V8WrapperType type;
1026
1027    Node::NodeType nodeType = node->nodeType();
1028    if (nodeType == Node::ELEMENT_NODE) {
1029        if (node->isHTMLElement())
1030            type = htmlElementType(static_cast<HTMLElement*>(node));
1031#if ENABLE(SVG)
1032        else if (node->isSVGElement())
1033            type = svgElementType(static_cast<SVGElement*>(node));
1034#endif
1035        else
1036            type = V8ClassIndex::ELEMENT;
1037    } else if (nodeType == Node::DOCUMENT_NODE) {
1038        isDocument = true;
1039        Document* document = static_cast<Document*>(node);
1040        if (document->isHTMLDocument())
1041            type = V8ClassIndex::HTMLDOCUMENT;
1042#if ENABLE(SVG)
1043        else if (document->isSVGDocument())
1044            type = V8ClassIndex::SVGDOCUMENT;
1045#endif
1046        else
1047            type = V8ClassIndex::DOCUMENT;
1048    } else {
1049        ASSERT(nodeType < static_cast<int>(sizeof(mapping)/sizeof(mapping[0])));
1050        type = mapping[nodeType];
1051        ASSERT(type != V8ClassIndex::INVALID_CLASS_INDEX);
1052    }
1053
1054    v8::Handle<v8::Context> context;
1055    if (proxy)
1056        context = proxy->context();
1057
1058    // Enter the node's context and create the wrapper in that context.
1059    if (!context.IsEmpty())
1060        context->Enter();
1061
1062    v8::Local<v8::Object> result = instantiateV8Object(proxy, type, V8ClassIndex::NODE, node);
1063
1064    // Exit the node's context if it was entered.
1065    if (!context.IsEmpty())
1066        context->Exit();
1067
1068    if (result.IsEmpty()) {
1069        // If instantiation failed it's important not to add the result
1070        // to the DOM node map. Instead we return an empty handle, which
1071        // should already be handled by callers of this function in case
1072        // the node is NULL.
1073        return result;
1074    }
1075
1076    node->ref();
1077    domNodeMap.set(node, v8::Persistent<v8::Object>::New(result));
1078
1079    if (isDocument) {
1080        if (proxy)
1081            proxy->windowShell()->updateDocumentWrapper(result);
1082
1083        if (type == V8ClassIndex::HTMLDOCUMENT) {
1084            // Create marker object and insert it in two internal fields.
1085            // This is used to implement temporary shadowing of
1086            // document.all.
1087            ASSERT(result->InternalFieldCount() == V8HTMLDocument::internalFieldCount);
1088            v8::Local<v8::Object> marker = v8::Object::New();
1089            result->SetInternalField(V8HTMLDocument::markerIndex, marker);
1090            result->SetInternalField(V8HTMLDocument::shadowIndex, marker);
1091        }
1092    }
1093
1094    return result;
1095}
1096
1097// A JS object of type EventTarget is limited to a small number of possible classes.
1098// Check EventTarget.h for new type conversion methods
1099v8::Handle<v8::Value> V8DOMWrapper::convertEventTargetToV8Object(EventTarget* target)
1100{
1101    if (!target)
1102        return v8::Null();
1103
1104#if ENABLE(SVG)
1105    SVGElementInstance* instance = target->toSVGElementInstance();
1106    if (instance)
1107        return convertToV8Object(V8ClassIndex::SVGELEMENTINSTANCE, instance);
1108#endif
1109
1110#if ENABLE(WORKERS)
1111    Worker* worker = target->toWorker();
1112    if (worker)
1113        return convertToV8Object(V8ClassIndex::WORKER, worker);
1114#endif // WORKERS
1115
1116#if ENABLE(SHARED_WORKERS)
1117    SharedWorker* sharedWorker = target->toSharedWorker();
1118    if (sharedWorker)
1119        return convertToV8Object(V8ClassIndex::SHAREDWORKER, sharedWorker);
1120#endif // SHARED_WORKERS
1121
1122#if ENABLE(NOTIFICATIONS)
1123    Notification* notification = target->toNotification();
1124    if (notification)
1125        return convertToV8Object(V8ClassIndex::NOTIFICATION, notification);
1126#endif
1127
1128#if ENABLE(WEB_SOCKETS)
1129    WebSocket* webSocket = target->toWebSocket();
1130    if (webSocket)
1131        return convertToV8Object(V8ClassIndex::WEBSOCKET, webSocket);
1132#endif
1133
1134    Node* node = target->toNode();
1135    if (node)
1136        return convertNodeToV8Object(node);
1137
1138    if (DOMWindow* domWindow = target->toDOMWindow())
1139        return convertToV8Object(V8ClassIndex::DOMWINDOW, domWindow);
1140
1141    // XMLHttpRequest is created within its JS counterpart.
1142    XMLHttpRequest* xmlHttpRequest = target->toXMLHttpRequest();
1143    if (xmlHttpRequest) {
1144        v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(xmlHttpRequest);
1145        ASSERT(!wrapper.IsEmpty());
1146        return wrapper;
1147    }
1148
1149    // MessagePort is created within its JS counterpart
1150    MessagePort* port = target->toMessagePort();
1151    if (port) {
1152        v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(port);
1153        ASSERT(!wrapper.IsEmpty());
1154        return wrapper;
1155    }
1156
1157    XMLHttpRequestUpload* upload = target->toXMLHttpRequestUpload();
1158    if (upload) {
1159        v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(upload);
1160        ASSERT(!wrapper.IsEmpty());
1161        return wrapper;
1162    }
1163
1164#if ENABLE(OFFLINE_WEB_APPLICATIONS)
1165    DOMApplicationCache* domAppCache = target->toDOMApplicationCache();
1166    if (domAppCache)
1167        return convertToV8Object(V8ClassIndex::DOMAPPLICATIONCACHE, domAppCache);
1168#endif
1169
1170#if ENABLE(EVENTSOURCE)
1171    EventSource* eventSource = target->toEventSource();
1172    if (eventSource)
1173        return convertToV8Object(V8ClassIndex::EVENTSOURCE, eventSource);
1174#endif
1175
1176    ASSERT(0);
1177    return notHandledByInterceptor();
1178}
1179
1180v8::Handle<v8::Value> V8DOMWrapper::convertEventListenerToV8Object(ScriptExecutionContext* context, EventListener* listener)
1181{
1182    if (!listener)
1183        return v8::Null();
1184
1185    // FIXME: can a user take a lazy event listener and set to other places?
1186    V8AbstractEventListener* v8listener = static_cast<V8AbstractEventListener*>(listener);
1187    return v8listener->getListenerObject(context);
1188}
1189
1190PassRefPtr<EventListener> V8DOMWrapper::getEventListener(Node* node, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
1191{
1192    return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute);
1193}
1194
1195#if ENABLE(SVG)
1196PassRefPtr<EventListener> V8DOMWrapper::getEventListener(SVGElementInstance* element, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
1197{
1198    return getEventListener(element->correspondingElement(), value, isAttribute, lookup);
1199}
1200#endif
1201
1202PassRefPtr<EventListener> V8DOMWrapper::getEventListener(AbstractWorker* worker, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
1203{
1204    if (worker->scriptExecutionContext()->isWorkerContext()) {
1205        WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve();
1206        ASSERT(workerContextProxy);
1207        return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly);
1208    }
1209
1210    return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute);
1211}
1212
1213#if ENABLE(NOTIFICATIONS)
1214PassRefPtr<EventListener> V8DOMWrapper::getEventListener(Notification* notification, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
1215{
1216    if (notification->scriptExecutionContext()->isWorkerContext()) {
1217        WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve();
1218        ASSERT(workerContextProxy);
1219        return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly);
1220    }
1221
1222    return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute);
1223}
1224#endif
1225
1226PassRefPtr<EventListener> V8DOMWrapper::getEventListener(WorkerContext* workerContext, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
1227{
1228    WorkerContextExecutionProxy* workerContextProxy = workerContext->script()->proxy();
1229    if (workerContextProxy)
1230        return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly);
1231
1232    return 0;
1233}
1234
1235PassRefPtr<EventListener> V8DOMWrapper::getEventListener(XMLHttpRequestUpload* upload, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
1236{
1237    return getEventListener(upload->associatedXMLHttpRequest(), value, isAttribute, lookup);
1238}
1239
1240#if ENABLE(EVENTSOURCE)
1241PassRefPtr<EventListener> V8DOMWrapper::getEventListener(EventSource* eventSource, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
1242{
1243    if (V8Proxy::retrieve(eventSource->scriptExecutionContext()))
1244        return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute);
1245
1246#if ENABLE(WORKERS)
1247    WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve();
1248    if (workerContextProxy)
1249        return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly);
1250#endif
1251
1252    return 0;
1253}
1254#endif
1255
1256PassRefPtr<EventListener> V8DOMWrapper::getEventListener(EventTarget* eventTarget, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
1257{
1258    if (V8Proxy::retrieve(eventTarget->scriptExecutionContext()))
1259        return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute);
1260
1261#if ENABLE(WORKERS)
1262    WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve();
1263    if (workerContextProxy)
1264        return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly);
1265#endif
1266
1267    return 0;
1268}
1269
1270PassRefPtr<EventListener> V8DOMWrapper::getEventListener(V8Proxy* proxy, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
1271{
1272    return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute);
1273}
1274
1275v8::Handle<v8::Value> V8DOMWrapper::convertDOMImplementationToV8Object(DOMImplementation* impl)
1276{
1277    v8::Handle<v8::Object> result = instantiateV8Object(V8ClassIndex::DOMIMPLEMENTATION, V8ClassIndex::DOMIMPLEMENTATION, impl);
1278    if (result.IsEmpty()) {
1279        // If the instantiation failed, we ignore it and return null instead
1280        // of returning an empty handle.
1281        return v8::Null();
1282    }
1283    return result;
1284}
1285
1286v8::Handle<v8::Value> V8DOMWrapper::convertStyleSheetToV8Object(StyleSheet* sheet)
1287{
1288    if (!sheet)
1289        return v8::Null();
1290
1291    v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(sheet);
1292    if (!wrapper.IsEmpty())
1293        return wrapper;
1294
1295    V8ClassIndex::V8WrapperType type = V8ClassIndex::STYLESHEET;
1296    if (sheet->isCSSStyleSheet())
1297        type = V8ClassIndex::CSSSTYLESHEET;
1298
1299    v8::Handle<v8::Object> result = instantiateV8Object(type, V8ClassIndex::STYLESHEET, sheet);
1300    if (!result.IsEmpty()) {
1301        // Only update the DOM object map if the result is non-empty.
1302        sheet->ref();
1303        setJSWrapperForDOMObject(sheet, v8::Persistent<v8::Object>::New(result));
1304    }
1305
1306    // Add a hidden reference from stylesheet object to its owner node.
1307    Node* ownerNode = sheet->ownerNode();
1308    if (ownerNode) {
1309        v8::Handle<v8::Object> owner = v8::Handle<v8::Object>::Cast(convertNodeToV8Object(ownerNode));
1310        result->SetInternalField(V8StyleSheet::ownerNodeIndex, owner);
1311    }
1312
1313    return result;
1314}
1315
1316v8::Handle<v8::Value> V8DOMWrapper::convertCSSValueToV8Object(CSSValue* value)
1317{
1318    if (!value)
1319        return v8::Null();
1320
1321    v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(value);
1322    if (!wrapper.IsEmpty())
1323        return wrapper;
1324
1325    V8ClassIndex::V8WrapperType type;
1326
1327    if (value->isWebKitCSSTransformValue())
1328        type = V8ClassIndex::WEBKITCSSTRANSFORMVALUE;
1329    else if (value->isValueList())
1330        type = V8ClassIndex::CSSVALUELIST;
1331    else if (value->isPrimitiveValue())
1332        type = V8ClassIndex::CSSPRIMITIVEVALUE;
1333#if ENABLE(SVG)
1334    else if (value->isSVGPaint())
1335        type = V8ClassIndex::SVGPAINT;
1336    else if (value->isSVGColor())
1337        type = V8ClassIndex::SVGCOLOR;
1338#endif
1339    else
1340        type = V8ClassIndex::CSSVALUE;
1341
1342    v8::Handle<v8::Object> result = instantiateV8Object(type, V8ClassIndex::CSSVALUE, value);
1343    if (!result.IsEmpty()) {
1344        // Only update the DOM object map if the result is non-empty.
1345        value->ref();
1346        setJSWrapperForDOMObject(value, v8::Persistent<v8::Object>::New(result));
1347    }
1348
1349    return result;
1350}
1351
1352v8::Handle<v8::Value> V8DOMWrapper::convertCSSRuleToV8Object(CSSRule* rule)
1353{
1354    if (!rule)
1355        return v8::Null();
1356
1357    v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(rule);
1358    if (!wrapper.IsEmpty())
1359        return wrapper;
1360
1361    V8ClassIndex::V8WrapperType type;
1362
1363    switch (rule->type()) {
1364    case CSSRule::STYLE_RULE:
1365        type = V8ClassIndex::CSSSTYLERULE;
1366        break;
1367    case CSSRule::CHARSET_RULE:
1368        type = V8ClassIndex::CSSCHARSETRULE;
1369        break;
1370    case CSSRule::IMPORT_RULE:
1371        type = V8ClassIndex::CSSIMPORTRULE;
1372        break;
1373    case CSSRule::MEDIA_RULE:
1374        type = V8ClassIndex::CSSMEDIARULE;
1375        break;
1376    case CSSRule::FONT_FACE_RULE:
1377        type = V8ClassIndex::CSSFONTFACERULE;
1378        break;
1379    case CSSRule::PAGE_RULE:
1380        type = V8ClassIndex::CSSPAGERULE;
1381        break;
1382    case CSSRule::VARIABLES_RULE:
1383        type = V8ClassIndex::CSSVARIABLESRULE;
1384        break;
1385    case CSSRule::WEBKIT_KEYFRAME_RULE:
1386        type = V8ClassIndex::WEBKITCSSKEYFRAMERULE;
1387        break;
1388    case CSSRule::WEBKIT_KEYFRAMES_RULE:
1389        type = V8ClassIndex::WEBKITCSSKEYFRAMESRULE;
1390        break;
1391    default:  // CSSRule::UNKNOWN_RULE
1392        type = V8ClassIndex::CSSRULE;
1393        break;
1394    }
1395
1396    v8::Handle<v8::Object> result = instantiateV8Object(type, V8ClassIndex::CSSRULE, rule);
1397    if (!result.IsEmpty()) {
1398        // Only update the DOM object map if the result is non-empty.
1399        rule->ref();
1400        setJSWrapperForDOMObject(rule, v8::Persistent<v8::Object>::New(result));
1401    }
1402    return result;
1403}
1404
1405v8::Handle<v8::Value> V8DOMWrapper::convertWindowToV8Object(DOMWindow* window)
1406{
1407    if (!window)
1408        return v8::Null();
1409    // Initializes environment of a frame, and return the global object
1410    // of the frame.
1411    Frame* frame = window->frame();
1412    if (!frame)
1413        return v8::Handle<v8::Object>();
1414
1415    // Special case: Because of evaluateInIsolatedWorld() one DOMWindow can have
1416    // multiple contexts and multiple global objects associated with it. When
1417    // code running in one of those contexts accesses the window object, we
1418    // want to return the global object associated with that context, not
1419    // necessarily the first global object associated with that DOMWindow.
1420    v8::Handle<v8::Context> currentContext = v8::Context::GetCurrent();
1421    v8::Handle<v8::Object> currentGlobal = currentContext->Global();
1422    v8::Handle<v8::Object> windowWrapper = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, currentGlobal);
1423    if (!windowWrapper.IsEmpty()) {
1424        if (V8DOMWindow::toNative(windowWrapper) == window)
1425            return currentGlobal;
1426    }
1427
1428    // Otherwise, return the global object associated with this frame.
1429    v8::Handle<v8::Context> context = V8Proxy::context(frame);
1430    if (context.IsEmpty())
1431        return v8::Handle<v8::Object>();
1432
1433    v8::Handle<v8::Object> global = context->Global();
1434    ASSERT(!global.IsEmpty());
1435    return global;
1436}
1437
1438v8::Handle<v8::Value> V8DOMWrapper::convertNamedNodeMapToV8Object(NamedNodeMap* map)
1439{
1440    if (!map)
1441        return v8::Null();
1442
1443    v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(map);
1444    if (!wrapper.IsEmpty())
1445        return wrapper;
1446
1447    v8::Handle<v8::Object> result = instantiateV8Object(V8ClassIndex::NAMEDNODEMAP, V8ClassIndex::NAMEDNODEMAP, map);
1448    if (result.IsEmpty())
1449        return result;
1450
1451    // Only update the DOM object map if the result is non-empty.
1452    map->ref();
1453    setJSWrapperForDOMObject(map, v8::Persistent<v8::Object>::New(result));
1454
1455    // Add a hidden reference from named node map to its owner node.
1456    if (Element* element = map->element()) {
1457        v8::Handle<v8::Object> owner = v8::Handle<v8::Object>::Cast(convertNodeToV8Object(element));
1458        result->SetInternalField(V8NamedNodeMap::ownerNodeIndex, owner);
1459    }
1460
1461    return result;
1462}
1463
1464}  // namespace WebCore
1465