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