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