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