OLD | NEW |
1 // Copyright (c) 2008, Google Inc. | 1 // Copyright (c) 2008, Google Inc. |
2 // All rights reserved. | 2 // All rights reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
6 // met: | 6 // met: |
7 // | 7 // |
8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
(...skipping 12 matching lines...) Expand all Loading... |
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | 29 |
30 #include "config.h" | 30 #include "config.h" |
31 #include "ScriptController.h" | 31 #include "ScriptController.h" |
32 | 32 |
33 #include "CString.h" | 33 #include "bindings/npruntime.h" |
34 #include "Document.h" | 34 #include "c_instance.h" |
35 #include "DOMWindow.h" | |
36 #include "Event.h" | |
37 #include "EventListener.h" | |
38 #include "EventNames.h" | |
39 #include "Frame.h" | |
40 #include "Node.h" | |
41 #include "NotImplemented.h" | |
42 #include "npruntime_priv.h" | |
43 #include "np_v8object.h" | |
44 #include "PausedTimeouts.h" | |
45 #include "Widget.h" | |
46 | 35 |
47 #include "v8_proxy.h" | |
48 #include "v8_binding.h" | |
49 #include "v8_npobject.h" | |
50 | |
51 //TODO(eseidel): We should remove this glue dependency | |
52 #undef LOG // glue defines its own LOG macro | 36 #undef LOG // glue defines its own LOG macro |
53 #include "webkit/glue/webplugin_impl.h" | 37 #include "webkit/glue/webplugin_impl.h" |
54 | 38 |
55 NPRuntimeFunctions npruntime_functions = { | |
56 NPN_GetStringIdentifier, | |
57 NPN_GetStringIdentifiers, | |
58 NPN_GetIntIdentifier, | |
59 NPN_IdentifierIsString, | |
60 NPN_UTF8FromIdentifier, | |
61 NPN_IntFromIdentifier, | |
62 NPN_CreateObject, | |
63 NPN_RetainObject, | |
64 NPN_ReleaseObject, | |
65 NPN_Invoke, | |
66 NPN_InvokeDefault, | |
67 NPN_Evaluate, | |
68 NPN_GetProperty, | |
69 NPN_SetProperty, | |
70 NPN_RemoveProperty, | |
71 NPN_HasProperty, | |
72 NPN_HasMethod, | |
73 NPN_ReleaseVariantValue, | |
74 NPN_SetException | |
75 }; | |
76 | |
77 | |
78 namespace WebCore { | 39 namespace WebCore { |
79 | 40 |
80 bool ScriptController::m_recordPlaybackMode = false; | |
81 | |
82 void ScriptController::setFlags(const char* str, int length) | |
83 { | |
84 v8::V8::SetFlagsFromString(str, length); | |
85 } | |
86 | |
87 void ScriptController::setDomain(Frame* frame, const String&) | |
88 { | |
89 V8Proxy::DomainChanged(frame); | |
90 } | |
91 | |
92 Frame* ScriptController::retrieveActiveFrame() | |
93 { | |
94 return V8Proxy::retrieveActiveFrame(); | |
95 } | |
96 | |
97 bool ScriptController::isSafeScript(Frame* target) | |
98 { | |
99 return V8Proxy::CanAccessFrame(target, true); | |
100 } | |
101 | |
102 void ScriptController::gcProtectJSWrapper(void* dom_object) | |
103 { | |
104 V8Proxy::GCProtect(static_cast<Peerable*>(dom_object)); | |
105 } | |
106 | |
107 void ScriptController::gcUnprotectJSWrapper(void* dom_object) | |
108 { | |
109 V8Proxy::GCUnprotect(static_cast<Peerable*>(dom_object)); | |
110 } | |
111 | |
112 void ScriptController::pauseTimeouts(OwnPtr<PausedTimeouts>& result) | |
113 { | |
114 DOMWindow* window = m_frame->domWindow(); | |
115 if (!window) { | |
116 result.clear(); | |
117 return; | |
118 } | |
119 window->pauseTimeouts(result); | |
120 } | |
121 | |
122 void ScriptController::resumeTimeouts(OwnPtr<PausedTimeouts>& timeouts) | |
123 { | |
124 DOMWindow* window = m_frame->domWindow(); | |
125 if (!window) { | |
126 timeouts.clear(); | |
127 return; | |
128 } | |
129 window->resumeTimeouts(timeouts); | |
130 } | |
131 | |
132 ScriptController::ScriptController(Frame* frame) | |
133 : m_frame(frame) | |
134 , m_sourceURL(0) | |
135 , m_processingTimerCallback(false) | |
136 , m_paused(false) | |
137 , m_proxy(new V8Proxy(frame)) | |
138 #if ENABLE(NETSCAPE_PLUGIN_API) | |
139 , m_windowScriptNPObject(0) | |
140 #endif | |
141 { | |
142 } | |
143 | |
144 ScriptController::~ScriptController() | |
145 { | |
146 } | |
147 | |
148 void ScriptController::clearScriptObjects() | |
149 { | |
150 // TODO(eseidel): JSC handles binding root objects here, why don't we? | |
151 | |
152 #if ENABLE(NETSCAPE_PLUGIN_API) | |
153 if (m_windowScriptNPObject) { | |
154 // Call _NPN_DeallocateObject() instead of _NPN_ReleaseObject() so that
we don't leak if a plugin fails to release the window | |
155 // script object properly. | |
156 // This shouldn't cause any problems for plugins since they should have
already been stopped and destroyed at this point. | |
157 _NPN_DeallocateObject(m_windowScriptNPObject); | |
158 m_windowScriptNPObject = 0; | |
159 } | |
160 #endif | |
161 } | |
162 | |
163 void ScriptController::clearPluginObjects() | |
164 { | |
165 PluginObjectMap::iterator it = m_pluginObjects.begin(); | |
166 for (; it != m_pluginObjects.end(); ++it) { | |
167 _NPN_UnregisterObject(it->second); | |
168 NPN_ReleaseObject(it->second); | |
169 } | |
170 m_pluginObjects.clear(); | |
171 } | |
172 | |
173 // Disconnect the proxy from its owner frame; | |
174 void ScriptController::disconnectFrame() | |
175 { | |
176 m_proxy->disconnectFrame(); | |
177 } | |
178 | |
179 bool ScriptController::processingUserGesture() const | |
180 { | |
181 Frame* active_frame = V8Proxy::retrieveActiveFrame(); | |
182 // No script is running, must be run by users. | |
183 if (!active_frame) | |
184 return true; | |
185 | |
186 V8Proxy* active_proxy = active_frame->script()->proxy(); | |
187 | |
188 v8::HandleScope handle_scope; | |
189 v8::Handle<v8::Context> context = V8Proxy::GetContext(active_frame); | |
190 // TODO(fqian): find all cases context can be empty: | |
191 // 1) JS is disabled; | |
192 // 2) page is NULL; | |
193 if (context.IsEmpty()) | |
194 return true; | |
195 | |
196 v8::Context::Scope scope(context); | |
197 | |
198 v8::Handle<v8::Object> global = context->Global(); | |
199 v8::Handle<v8::Value> jsevent = global->Get(v8::String::NewSymbol("event")); | |
200 Event* event = V8Proxy::ToNativeEvent(jsevent); | |
201 | |
202 // Based on code from kjs_bindings.cpp. | |
203 // Note: This is more liberal than Firefox's implementation. | |
204 if (event) { | |
205 const AtomicString& type = event->type(); | |
206 bool event_ok = | |
207 // mouse events | |
208 type == EventNames::clickEvent || | |
209 type == EventNames::mousedownEvent || | |
210 type == EventNames::mouseupEvent || | |
211 type == EventNames::dblclickEvent || | |
212 // keyboard events | |
213 type == EventNames::keydownEvent || | |
214 type == EventNames::keypressEvent || | |
215 type == EventNames::keyupEvent || | |
216 // other accepted events | |
217 type == EventNames::selectEvent || | |
218 type == EventNames::changeEvent || | |
219 type == EventNames::focusEvent || | |
220 type == EventNames::blurEvent || | |
221 type == EventNames::submitEvent; | |
222 | |
223 if (event_ok) | |
224 return true; | |
225 } else if (active_proxy->inlineCode() && !active_proxy->timerCallback()) | |
226 // This is the <a href="javascript:window.open('...')> case -> we let it | |
227 // through | |
228 return true; | |
229 | |
230 // This is the <script>window.open(...)</script> case or a timer callback -> | |
231 // block it | |
232 return false; | |
233 } | |
234 | |
235 | |
236 // Evaluate a script file in the environment of this proxy. | |
237 String ScriptController::evaluate(const String& filename, int baseLine, | |
238 const String& code, Node* node, bool* succ) | |
239 { | |
240 if (succ) | |
241 *succ = false; | |
242 String result; | |
243 | |
244 v8::HandleScope hs; | |
245 v8::Handle<v8::Context> context = V8Proxy::GetContext(m_proxy->frame()); | |
246 if (context.IsEmpty()) | |
247 return result; | |
248 | |
249 v8::Context::Scope scope(context); | |
250 | |
251 // HTMLTokenizer used to use base zero line numbers for scripts, now it | |
252 // uses base 1. This confuses v8, which uses line offsets from the | |
253 // first line. | |
254 v8::Local<v8::Value> obj = m_proxy->Evaluate(filename, baseLine - 1, code, | |
255 node); | |
256 | |
257 if (obj.IsEmpty() || obj->IsUndefined()) | |
258 return result; | |
259 | |
260 // If the return value is not a string, return 0 (what KJS does). | |
261 if (!obj->IsString()) { | |
262 v8::TryCatch exception_block; | |
263 obj = obj->ToString(); | |
264 if (exception_block.HasCaught()) | |
265 obj = v8::String::New(""); | |
266 } | |
267 | |
268 result = ToWebCoreString(obj); | |
269 if (succ) | |
270 *succ = true; | |
271 | |
272 return result; | |
273 } | |
274 | |
275 v8::Persistent<v8::Value> ScriptController::evaluate(const String& filename, | |
276 int baseLine, | |
277 const String& code, | |
278 Node* node) | |
279 { | |
280 v8::HandleScope hs; | |
281 v8::Handle<v8::Context> context = V8Proxy::GetContext(m_proxy->frame()); | |
282 if (context.IsEmpty()) | |
283 return v8::Persistent<v8::Value>(); | |
284 | |
285 v8::Context::Scope scope(context); | |
286 | |
287 v8::Local<v8::Value> obj = m_proxy->Evaluate(filename, baseLine, code, node)
; | |
288 | |
289 if (obj.IsEmpty()) | |
290 return v8::Persistent<v8::Value>(); | |
291 | |
292 // TODO(fqian): keep track the global handle created. | |
293 return v8::Persistent<v8::Value>::New(obj); | |
294 } | |
295 | |
296 void ScriptController::disposeJSResult(v8::Persistent<v8::Value> result) | |
297 { | |
298 result.Dispose(); | |
299 result.Clear(); | |
300 } | |
301 | |
302 PassRefPtr<EventListener> ScriptController::createHTMLEventHandler( | |
303 const String& functionName, const String& code, Node* node) | |
304 { | |
305 return m_proxy->createHTMLEventHandler(functionName, code, node); | |
306 } | |
307 | |
308 #if ENABLE(SVG) | |
309 PassRefPtr<EventListener> ScriptController::createSVGEventHandler( | |
310 const String& functionName, const String& code, Node* node) | |
311 { | |
312 return m_proxy->createSVGEventHandler(functionName, code, node); | |
313 } | |
314 #endif | |
315 | |
316 void ScriptController::setEventHandlerLineno(int lineno) | |
317 { | |
318 m_proxy->setEventHandlerLineno(lineno); | |
319 } | |
320 | |
321 void ScriptController::finishedWithEvent(Event* evt) | |
322 { | |
323 m_proxy->finishedWithEvent(evt); | |
324 } | |
325 | |
326 void ScriptController::clearDocumentWrapper() | |
327 { | |
328 m_proxy->clearDocumentWrapper(); | |
329 } | |
330 | |
331 // Create a V8 object with an interceptor of NPObjectPropertyGetter | |
332 void ScriptController::BindToWindowObject(Frame* frame, const String& key, NPObj
ect* object) | |
333 { | |
334 v8::HandleScope handle_scope; | |
335 | |
336 v8::Handle<v8::Context> context = V8Proxy::GetContext(frame); | |
337 if (context.IsEmpty()) | |
338 return; | |
339 | |
340 v8::Context::Scope scope(context); | |
341 | |
342 v8::Handle<v8::Object> value = CreateV8ObjectForNPObject(object, NULL); | |
343 | |
344 // Attach to the global object | |
345 v8::Handle<v8::Object> global = context->Global(); | |
346 global->Set(v8String(key), value); | |
347 } | |
348 | |
349 void ScriptController::collectGarbage() | |
350 { | |
351 v8::HandleScope hs; | |
352 v8::Handle<v8::Context> context = V8Proxy::GetContext(m_proxy->frame()); | |
353 if (context.IsEmpty()) | |
354 return; | |
355 | |
356 v8::Context::Scope scope(context); | |
357 | |
358 m_proxy->Evaluate("", 0, "if (window.gc) void(gc());", NULL); | |
359 } | |
360 | |
361 NPRuntimeFunctions* ScriptController::functions() | |
362 { | |
363 return &npruntime_functions; | |
364 } | |
365 | |
366 | |
367 bool ScriptController::haveInterpreter() const | |
368 { | |
369 return m_proxy->ContextInitialized(); | |
370 } | |
371 | |
372 bool ScriptController::isEnabled() const | |
373 { | |
374 return m_proxy->isEnabled(); | |
375 } | |
376 | |
377 JSInstanceHandle ScriptController::createScriptInstanceForWidget(Widget* widget) | 41 JSInstanceHandle ScriptController::createScriptInstanceForWidget(Widget* widget) |
378 { | 42 { |
379 ASSERT(widget != 0); | 43 ASSERT(widget != 0); |
380 | 44 |
381 if (widget->isFrameView()) | 45 if (widget->isFrameView()) |
382 return JSInstanceHolder::EmptyInstance(); | 46 return JSInstanceHolder::EmptyInstance(); |
383 | 47 |
384 // Note: We have to trust that the widget passed to us here | 48 // Note: We have to trust that the widget passed to us here |
385 // is a WebPluginImpl. There isn't a way to dynamically verify | 49 // is a WebPluginImpl. There isn't a way to dynamically verify |
386 // it, since the derived class (Widget) has no identifier. | 50 // it, since the derived class (Widget) has no identifier. |
387 WebPluginContainer* container = static_cast<WebPluginContainer*>(widget); | 51 WebPluginContainer* container = static_cast<WebPluginContainer*>(widget); |
388 if (!container) | 52 if (!container) |
389 return JSInstanceHolder::EmptyInstance(); | 53 return JSInstanceHolder::EmptyInstance(); |
390 | 54 |
391 NPObject* npObject = container->GetPluginScriptableObject(); | 55 NPObject* npObject = container->GetPluginScriptableObject(); |
392 if (!npObject) | 56 if (!npObject) |
393 return JSInstanceHolder::EmptyInstance(); | 57 return JSInstanceHolder::EmptyInstance(); |
394 | 58 |
395 #if USE(JSC) | |
396 // Register 'widget' with the frame so that we can teardown | 59 // Register 'widget' with the frame so that we can teardown |
397 // subobjects when the container goes away. | 60 // subobjects when the container goes away. |
398 RefPtr<KJS::Bindings::RootObject> root = script()->createRootObject(widget); | 61 RefPtr<JSC::Bindings::RootObject> root = createRootObject(widget); |
399 KJS::Bindings::Instance* instance = | 62 RefPtr<JSC::Bindings::Instance> instance = |
400 KJS::Bindings::Instance::createBindingForLanguageInstance( | 63 JSC::Bindings::CInstance::create(npObject, root.release()); |
401 KJS::Bindings::Instance::CLanguage, npObject, | |
402 root.release()); | |
403 // GetPluginScriptableObject returns a retained NPObject. | 64 // GetPluginScriptableObject returns a retained NPObject. |
404 // The caller is expected to release it. | 65 // The caller is expected to release it. |
405 NPN_ReleaseObject(npObject); | 66 NPN_ReleaseObject(npObject); |
406 return instance; | 67 return instance.release(); |
407 #elif USE(V8) | |
408 // Frame Memory Management for NPObjects | |
409 // ------------------------------------- | |
410 // NPObjects are treated differently than other objects wrapped by JS. | |
411 // NPObjects are not Peerable, and cannot be made peerable, since NPObjects | |
412 // can be created either by the browser (e.g. the main window object) or by | |
413 // the plugin (the main plugin object for a HTMLEmbedElement). Further, | |
414 // unlike most DOM Objects, the frame is especially careful to ensure | |
415 // NPObjects terminate at frame teardown because if a plugin leaks a | |
416 // reference, it could leak its objects (or the browser's objects). | |
417 // | |
418 // The Frame maintains a list of plugin objects (m_pluginObjects) | |
419 // which it can use to quickly find the wrapped embed object. | |
420 // | |
421 // Inside the NPRuntime, we've added a few methods for registering | |
422 // wrapped NPObjects. The purpose of the registration is because | |
423 // javascript garbage collection is non-deterministic, yet we need to | |
424 // be able to tear down the plugin objects immediately. When an object | |
425 // is registered, javascript can use it. When the object is destroyed, | |
426 // or when the object's "owning" object is destroyed, the object will | |
427 // be un-registered, and the javascript engine must not use it. | |
428 // | |
429 // Inside the javascript engine, the engine can keep a reference to the | |
430 // NPObject as part of its wrapper. However, before accessing the object | |
431 // it must consult the NPN_Registry. | |
432 | |
433 v8::Local<v8::Object> wrapper = CreateV8ObjectForNPObject(npObject, NULL); | |
434 | |
435 // Track the plugin object. We've been given a reference to the object. | |
436 m_pluginObjects.set(widget, npObject); | |
437 | |
438 JSInstance instance = wrapper; | |
439 return instance; | |
440 #endif | |
441 } | |
442 | |
443 void ScriptController::cleanupScriptObjectsForPlugin(void* nativeHandle) | |
444 { | |
445 PluginObjectMap::iterator it = m_pluginObjects.find(nativeHandle); | |
446 if (it == m_pluginObjects.end()) | |
447 return; | |
448 _NPN_UnregisterObject(it->second); | |
449 NPN_ReleaseObject(it->second); | |
450 m_pluginObjects.remove(it); | |
451 } | |
452 | |
453 static NPObject* createNoScriptObject() | |
454 { | |
455 notImplemented(); | |
456 return 0; | |
457 } | |
458 | |
459 static NPObject* createScriptObject(Frame* frame) | |
460 { | |
461 v8::HandleScope handleScope; | |
462 v8::Handle<v8::Context> context = V8Proxy::GetContext(frame); | |
463 if (context.IsEmpty()) | |
464 return createNoScriptObject(); | |
465 | |
466 v8::Context::Scope scope(context); | |
467 DOMWindow* window = frame->domWindow(); | |
468 v8::Handle<v8::Value> global = V8Proxy::ToV8Object(V8ClassIndex::DOMWINDOW,
window); | |
469 ASSERT(global->IsObject()); | |
470 return NPN_CreateScriptObject(0, v8::Handle<v8::Object>::Cast(global), windo
w); | |
471 } | |
472 | |
473 NPObject* ScriptController::windowScriptNPObject() | |
474 { | |
475 if (m_windowScriptNPObject) | |
476 return m_windowScriptNPObject; | |
477 | |
478 if (isEnabled()) { | |
479 // JavaScript is enabled, so there is a JavaScript window object. | |
480 // Return an NPObject bound to the window object. | |
481 m_windowScriptNPObject = createScriptObject(m_frame); | |
482 _NPN_RegisterObject(m_windowScriptNPObject, NULL); | |
483 } else { | |
484 // JavaScript is not enabled, so we cannot bind the NPObject to the | |
485 // JavaScript window object. Instead, we create an NPObject of a | |
486 // different class, one which is not bound to a JavaScript object. | |
487 m_windowScriptNPObject = createNoScriptObject(); | |
488 } | |
489 return m_windowScriptNPObject; | |
490 } | |
491 | |
492 NPObject* ScriptController::createScriptObjectForPluginElement(HTMLPlugInElement
* plugin) | |
493 { | |
494 // Can't create NPObjects when JavaScript is disabled | |
495 if (!isEnabled()) | |
496 return createNoScriptObject(); | |
497 | |
498 v8::HandleScope handleScope; | |
499 v8::Handle<v8::Context> context = V8Proxy::GetContext(m_frame); | |
500 if (context.IsEmpty()) | |
501 return createNoScriptObject(); | |
502 v8::Context::Scope scope(context); | |
503 | |
504 DOMWindow* window = m_frame->domWindow(); | |
505 v8::Handle<v8::Value> v8plugin = V8Proxy::ToV8Object(V8ClassIndex::HTMLEMBED
ELEMENT, plugin); | |
506 if (!v8plugin->IsObject()) | |
507 return createNoScriptObject(); | |
508 | |
509 return NPN_CreateScriptObject(0, v8::Handle<v8::Object>::Cast(v8plugin), win
dow); | |
510 } | |
511 | |
512 | |
513 void ScriptController::clearWindowShell() | |
514 { | |
515 m_proxy->clearForNavigation(); | |
516 } | |
517 | |
518 void ScriptController::attachDebugger(void*) | |
519 { | |
520 notImplemented(); | |
521 } | |
522 | |
523 void ScriptController::updateDocument() | |
524 { | |
525 // TODO(eseidel): Should update document property on current window object | |
526 // and all previous window objects which may still be alive. | |
527 notImplemented(); | |
528 } | |
529 | |
530 | |
531 JSInstanceHolder::JSInstanceHolder() | |
532 { | |
533 } | |
534 | |
535 JSInstanceHolder::JSInstanceHolder(JSInstanceHandle instance) | |
536 { | |
537 *this = instance; | |
538 } | |
539 | |
540 JSInstanceHolder::~JSInstanceHolder() | |
541 { | |
542 Clear(); | |
543 } | |
544 | |
545 bool JSInstanceHolder::IsEmpty() | |
546 { | |
547 return m_instance.IsEmpty(); | |
548 } | |
549 | |
550 JSInstance JSInstanceHolder::Get() | |
551 { | |
552 return v8::Local<v8::Object>::New(m_instance); | |
553 } | |
554 | |
555 void JSInstanceHolder::Clear() | |
556 { | |
557 if (m_instance.IsEmpty()) | |
558 return; | |
559 v8::HandleScope scope; | |
560 v8::Persistent<v8::Object> handle(m_instance); | |
561 #ifndef NDEBUG | |
562 V8Proxy::UnregisterGlobalHandle(this, handle); | |
563 #endif | |
564 handle.Dispose(); | |
565 m_instance.Clear(); | |
566 } | |
567 | |
568 JSInstance JSInstanceHolder::EmptyInstance() | |
569 { | |
570 return v8::Local<v8::Object>(); | |
571 } | |
572 | |
573 JSInstanceHolder& JSInstanceHolder::operator=(JSInstanceHandle instance) | |
574 { | |
575 Clear(); | |
576 if (instance.IsEmpty()) | |
577 return *this; | |
578 | |
579 v8::Persistent<v8::Object> handle = | |
580 v8::Persistent<v8::Object>::New(instance); | |
581 m_instance = handle; | |
582 #ifndef NDEBUG | |
583 V8Proxy::RegisterGlobalHandle(JSINSTANCE, this, handle); | |
584 #endif | |
585 return *this; | |
586 } | 68 } |
587 | 69 |
588 } // namespace WebCpre | 70 } // namespace WebCpre |
OLD | NEW |