|
1 /* |
|
2 * Copyright (C) 2008, 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 "V8DOMWindowShell.h" |
|
33 |
|
34 #include "PlatformBridge.h" |
|
35 #include "CSSMutableStyleDeclaration.h" |
|
36 #include "DateExtension.h" |
|
37 #include "DocumentLoader.h" |
|
38 #include "Frame.h" |
|
39 #include "FrameLoaderClient.h" |
|
40 #include "InspectorTimelineAgent.h" |
|
41 #include "Page.h" |
|
42 #include "PageGroup.h" |
|
43 #include "ScriptController.h" |
|
44 #include "StorageNamespace.h" |
|
45 #include "V8Binding.h" |
|
46 #include "V8BindingState.h" |
|
47 #include "V8Collection.h" |
|
48 #include "V8ConsoleMessage.h" |
|
49 #include "V8DOMMap.h" |
|
50 #include "V8DOMWindow.h" |
|
51 #include "V8Document.h" |
|
52 #include "V8GCForContextDispose.h" |
|
53 #include "V8HiddenPropertyName.h" |
|
54 #include "V8History.h" |
|
55 #include "V8Location.h" |
|
56 #include "V8Proxy.h" |
|
57 #include "WorkerContextExecutionProxy.h" |
|
58 |
|
59 #include <algorithm> |
|
60 #include <stdio.h> |
|
61 #include <utility> |
|
62 #include <v8-debug.h> |
|
63 #include <v8.h> |
|
64 #include <wtf/Assertions.h> |
|
65 #include <wtf/OwnArrayPtr.h> |
|
66 #include <wtf/StdLibExtras.h> |
|
67 #include <wtf/StringExtras.h> |
|
68 #include <wtf/UnusedParam.h> |
|
69 #include <wtf/text/CString.h> |
|
70 |
|
71 namespace WebCore { |
|
72 |
|
73 static void handleFatalErrorInV8() |
|
74 { |
|
75 // FIXME: We temporarily deal with V8 internal error situations |
|
76 // such as out-of-memory by crashing the renderer. |
|
77 CRASH(); |
|
78 } |
|
79 |
|
80 static void reportFatalErrorInV8(const char* location, const char* message) |
|
81 { |
|
82 // V8 is shutdown, we cannot use V8 api. |
|
83 // The only thing we can do is to disable JavaScript. |
|
84 // FIXME: clean up V8Proxy and disable JavaScript. |
|
85 printf("V8 error: %s (%s)\n", message, location); |
|
86 handleFatalErrorInV8(); |
|
87 } |
|
88 |
|
89 // Returns the owner frame pointer of a DOM wrapper object. It only works for |
|
90 // these DOM objects requiring cross-domain access check. |
|
91 static Frame* getTargetFrame(v8::Local<v8::Object> host, v8::Local<v8::Value> data) |
|
92 { |
|
93 Frame* target = 0; |
|
94 WrapperTypeInfo* type = WrapperTypeInfo::unwrap(data); |
|
95 if (V8DOMWindow::info.equals(type)) { |
|
96 v8::Handle<v8::Object> window = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), host); |
|
97 if (window.IsEmpty()) |
|
98 return target; |
|
99 |
|
100 DOMWindow* targetWindow = V8DOMWindow::toNative(window); |
|
101 target = targetWindow->frame(); |
|
102 } else if (V8History::info.equals(type)) { |
|
103 History* history = V8History::toNative(host); |
|
104 target = history->frame(); |
|
105 } else if (V8Location::info.equals(type)) { |
|
106 Location* location = V8Location::toNative(host); |
|
107 target = location->frame(); |
|
108 } |
|
109 return target; |
|
110 } |
|
111 |
|
112 static void reportUnsafeJavaScriptAccess(v8::Local<v8::Object> host, v8::AccessType type, v8::Local<v8::Value> data) |
|
113 { |
|
114 Frame* target = getTargetFrame(host, data); |
|
115 if (target) |
|
116 V8Proxy::reportUnsafeAccessTo(target, V8Proxy::ReportLater); |
|
117 } |
|
118 |
|
119 PassRefPtr<V8DOMWindowShell> V8DOMWindowShell::create(Frame* frame) |
|
120 { |
|
121 return adoptRef(new V8DOMWindowShell(frame)); |
|
122 } |
|
123 |
|
124 V8DOMWindowShell::V8DOMWindowShell(Frame* frame) |
|
125 : m_frame(frame) |
|
126 { |
|
127 } |
|
128 |
|
129 bool V8DOMWindowShell::isContextInitialized() |
|
130 { |
|
131 // m_context, m_global, and m_wrapperBoilerplates should |
|
132 // all be non-empty if if m_context is non-empty. |
|
133 ASSERT(m_context.IsEmpty() || !m_global.IsEmpty()); |
|
134 return !m_context.IsEmpty(); |
|
135 } |
|
136 |
|
137 void V8DOMWindowShell::disposeContextHandles() |
|
138 { |
|
139 if (!m_context.IsEmpty()) { |
|
140 m_frame->loader()->client()->didDestroyScriptContextForFrame(); |
|
141 m_context.Dispose(); |
|
142 m_context.Clear(); |
|
143 |
|
144 // It's likely that disposing the context has created a lot of |
|
145 // garbage. Notify V8 about this so it'll have a chance of cleaning |
|
146 // it up when idle. |
|
147 V8GCForContextDispose::instance().notifyContextDisposed(); |
|
148 } |
|
149 |
|
150 WrapperBoilerplateMap::iterator it = m_wrapperBoilerplates.begin(); |
|
151 for (; it != m_wrapperBoilerplates.end(); ++it) { |
|
152 v8::Persistent<v8::Object> wrapper = it->second; |
|
153 wrapper.Dispose(); |
|
154 wrapper.Clear(); |
|
155 } |
|
156 m_wrapperBoilerplates.clear(); |
|
157 } |
|
158 |
|
159 void V8DOMWindowShell::destroyGlobal() |
|
160 { |
|
161 if (!m_global.IsEmpty()) { |
|
162 #ifndef NDEBUG |
|
163 V8GCController::unregisterGlobalHandle(this, m_global); |
|
164 #endif |
|
165 m_global.Dispose(); |
|
166 m_global.Clear(); |
|
167 } |
|
168 } |
|
169 |
|
170 void V8DOMWindowShell::clearForClose() |
|
171 { |
|
172 if (!m_context.IsEmpty()) { |
|
173 v8::HandleScope handleScope; |
|
174 |
|
175 clearDocumentWrapper(); |
|
176 disposeContextHandles(); |
|
177 } |
|
178 } |
|
179 |
|
180 void V8DOMWindowShell::clearForNavigation() |
|
181 { |
|
182 if (!m_context.IsEmpty()) { |
|
183 v8::HandleScope handle; |
|
184 clearDocumentWrapper(); |
|
185 |
|
186 v8::Context::Scope contextScope(m_context); |
|
187 |
|
188 // Clear the document wrapper cache before turning on access checks on |
|
189 // the old DOMWindow wrapper. This way, access to the document wrapper |
|
190 // will be protected by the security checks on the DOMWindow wrapper. |
|
191 clearDocumentWrapperCache(); |
|
192 |
|
193 // Turn on access check on the old DOMWindow wrapper. |
|
194 v8::Handle<v8::Object> wrapper = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), m_global); |
|
195 ASSERT(!wrapper.IsEmpty()); |
|
196 wrapper->TurnOnAccessCheck(); |
|
197 |
|
198 // Separate the context from its global object. |
|
199 m_context->DetachGlobal(); |
|
200 |
|
201 disposeContextHandles(); |
|
202 } |
|
203 } |
|
204 |
|
205 // Create a new environment and setup the global object. |
|
206 // |
|
207 // The global object corresponds to a DOMWindow instance. However, to |
|
208 // allow properties of the JS DOMWindow instance to be shadowed, we |
|
209 // use a shadow object as the global object and use the JS DOMWindow |
|
210 // instance as the prototype for that shadow object. The JS DOMWindow |
|
211 // instance is undetectable from javascript code because the __proto__ |
|
212 // accessors skip that object. |
|
213 // |
|
214 // The shadow object and the DOMWindow instance are seen as one object |
|
215 // from javascript. The javascript object that corresponds to a |
|
216 // DOMWindow instance is the shadow object. When mapping a DOMWindow |
|
217 // instance to a V8 object, we return the shadow object. |
|
218 // |
|
219 // To implement split-window, see |
|
220 // 1) https://bugs.webkit.org/show_bug.cgi?id=17249 |
|
221 // 2) https://wiki.mozilla.org/Gecko:SplitWindow |
|
222 // 3) https://bugzilla.mozilla.org/show_bug.cgi?id=296639 |
|
223 // we need to split the shadow object further into two objects: |
|
224 // an outer window and an inner window. The inner window is the hidden |
|
225 // prototype of the outer window. The inner window is the default |
|
226 // global object of the context. A variable declared in the global |
|
227 // scope is a property of the inner window. |
|
228 // |
|
229 // The outer window sticks to a Frame, it is exposed to JavaScript |
|
230 // via window.window, window.self, window.parent, etc. The outer window |
|
231 // has a security token which is the domain. The outer window cannot |
|
232 // have its own properties. window.foo = 'x' is delegated to the |
|
233 // inner window. |
|
234 // |
|
235 // When a frame navigates to a new page, the inner window is cut off |
|
236 // the outer window, and the outer window identify is preserved for |
|
237 // the frame. However, a new inner window is created for the new page. |
|
238 // If there are JS code holds a closure to the old inner window, |
|
239 // it won't be able to reach the outer window via its global object. |
|
240 void V8DOMWindowShell::initContextIfNeeded() |
|
241 { |
|
242 // Bail out if the context has already been initialized. |
|
243 if (!m_context.IsEmpty()) |
|
244 return; |
|
245 |
|
246 // Create a handle scope for all local handles. |
|
247 v8::HandleScope handleScope; |
|
248 |
|
249 // Setup the security handlers and message listener. This only has |
|
250 // to be done once. |
|
251 static bool isV8Initialized = false; |
|
252 if (!isV8Initialized) { |
|
253 // Tells V8 not to call the default OOM handler, binding code |
|
254 // will handle it. |
|
255 v8::V8::IgnoreOutOfMemoryException(); |
|
256 v8::V8::SetFatalErrorHandler(reportFatalErrorInV8); |
|
257 |
|
258 v8::V8::SetGlobalGCPrologueCallback(&V8GCController::gcPrologue); |
|
259 v8::V8::SetGlobalGCEpilogueCallback(&V8GCController::gcEpilogue); |
|
260 |
|
261 v8::V8::AddMessageListener(&V8ConsoleMessage::handler); |
|
262 |
|
263 v8::V8::SetFailedAccessCheckCallbackFunction(reportUnsafeJavaScriptAccess); |
|
264 |
|
265 isV8Initialized = true; |
|
266 } |
|
267 |
|
268 |
|
269 m_context = createNewContext(m_global, 0); |
|
270 if (m_context.IsEmpty()) |
|
271 return; |
|
272 |
|
273 v8::Local<v8::Context> v8Context = v8::Local<v8::Context>::New(m_context); |
|
274 v8::Context::Scope contextScope(v8Context); |
|
275 |
|
276 // Store the first global object created so we can reuse it. |
|
277 if (m_global.IsEmpty()) { |
|
278 m_global = v8::Persistent<v8::Object>::New(v8Context->Global()); |
|
279 // Bail out if allocation of the first global objects fails. |
|
280 if (m_global.IsEmpty()) { |
|
281 disposeContextHandles(); |
|
282 return; |
|
283 } |
|
284 #ifndef NDEBUG |
|
285 V8GCController::registerGlobalHandle(PROXY, this, m_global); |
|
286 #endif |
|
287 } |
|
288 |
|
289 if (!installHiddenObjectPrototype(v8Context)) { |
|
290 disposeContextHandles(); |
|
291 return; |
|
292 } |
|
293 |
|
294 if (!installDOMWindow(v8Context, m_frame->domWindow())) { |
|
295 disposeContextHandles(); |
|
296 return; |
|
297 } |
|
298 |
|
299 updateDocument(); |
|
300 |
|
301 setSecurityToken(); |
|
302 |
|
303 m_frame->loader()->client()->didCreateScriptContextForFrame(); |
|
304 |
|
305 // FIXME: This is wrong. We should actually do this for the proper world once |
|
306 // we do isolated worlds the WebCore way. |
|
307 m_frame->loader()->dispatchDidClearWindowObjectInWorld(0); |
|
308 } |
|
309 |
|
310 v8::Persistent<v8::Context> V8DOMWindowShell::createNewContext(v8::Handle<v8::Object> global, int extensionGroup) |
|
311 { |
|
312 v8::Persistent<v8::Context> result; |
|
313 |
|
314 // The activeDocumentLoader pointer could be 0 during frame shutdown. |
|
315 if (!m_frame->loader()->activeDocumentLoader()) |
|
316 return result; |
|
317 |
|
318 // Create a new environment using an empty template for the shadow |
|
319 // object. Reuse the global object if one has been created earlier. |
|
320 v8::Persistent<v8::ObjectTemplate> globalTemplate = V8DOMWindow::GetShadowObjectTemplate(); |
|
321 if (globalTemplate.IsEmpty()) |
|
322 return result; |
|
323 |
|
324 // Used to avoid sleep calls in unload handlers. |
|
325 if (!V8Proxy::registeredExtensionWithV8(DateExtension::get())) |
|
326 V8Proxy::registerExtension(DateExtension::get(), String()); |
|
327 |
|
328 // Dynamically tell v8 about our extensions now. |
|
329 const V8Extensions& extensions = V8Proxy::extensions(); |
|
330 OwnArrayPtr<const char*> extensionNames(new const char*[extensions.size()]); |
|
331 int index = 0; |
|
332 for (size_t i = 0; i < extensions.size(); ++i) { |
|
333 if (extensions[i].group && extensions[i].group != extensionGroup) |
|
334 continue; |
|
335 |
|
336 // Note: we check the loader URL here instead of the document URL |
|
337 // because we might be currently loading an URL into a blank page. |
|
338 // See http://code.google.com/p/chromium/issues/detail?id=10924 |
|
339 if (extensions[i].scheme.length() > 0 && (extensions[i].scheme != m_frame->loader()->activeDocumentLoader()->url().protocol())) |
|
340 continue; |
|
341 |
|
342 extensionNames[index++] = extensions[i].extension->name(); |
|
343 } |
|
344 v8::ExtensionConfiguration extensionConfiguration(index, extensionNames.get()); |
|
345 result = v8::Context::New(&extensionConfiguration, globalTemplate, global); |
|
346 |
|
347 return result; |
|
348 } |
|
349 |
|
350 void V8DOMWindowShell::setContext(v8::Handle<v8::Context> context) |
|
351 { |
|
352 // if we already have a context, clear it before setting the new one. |
|
353 if (!m_context.IsEmpty()) { |
|
354 m_context.Dispose(); |
|
355 m_context.Clear(); |
|
356 } |
|
357 m_context = v8::Persistent<v8::Context>::New(context); |
|
358 } |
|
359 |
|
360 bool V8DOMWindowShell::installDOMWindow(v8::Handle<v8::Context> context, DOMWindow* window) |
|
361 { |
|
362 // Create a new JS window object and use it as the prototype for the shadow global object. |
|
363 v8::Handle<v8::Function> windowConstructor = V8DOMWrapper::getConstructor(&V8DOMWindow::info, getHiddenObjectPrototype(context)); |
|
364 v8::Local<v8::Object> jsWindow = SafeAllocation::newInstance(windowConstructor); |
|
365 // Bail out if allocation failed. |
|
366 if (jsWindow.IsEmpty()) |
|
367 return false; |
|
368 |
|
369 // Wrap the window. |
|
370 V8DOMWrapper::setDOMWrapper(jsWindow, &V8DOMWindow::info, window); |
|
371 V8DOMWrapper::setDOMWrapper(v8::Handle<v8::Object>::Cast(jsWindow->GetPrototype()), &V8DOMWindow::info, window); |
|
372 |
|
373 window->ref(); |
|
374 V8DOMWrapper::setJSWrapperForDOMObject(window, v8::Persistent<v8::Object>::New(jsWindow)); |
|
375 |
|
376 // Insert the window instance as the prototype of the shadow object. |
|
377 v8::Handle<v8::Object> v8RealGlobal = v8::Handle<v8::Object>::Cast(context->Global()->GetPrototype()); |
|
378 V8DOMWrapper::setDOMWrapper(v8RealGlobal, &V8DOMWindow::info, window); |
|
379 v8RealGlobal->SetPrototype(jsWindow); |
|
380 return true; |
|
381 } |
|
382 |
|
383 void V8DOMWindowShell::updateDocumentWrapper(v8::Handle<v8::Object> wrapper) |
|
384 { |
|
385 clearDocumentWrapper(); |
|
386 |
|
387 ASSERT(m_document.IsEmpty()); |
|
388 m_document = v8::Persistent<v8::Object>::New(wrapper); |
|
389 #ifndef NDEBUG |
|
390 V8GCController::registerGlobalHandle(PROXY, this, m_document); |
|
391 #endif |
|
392 } |
|
393 |
|
394 void V8DOMWindowShell::clearDocumentWrapper() |
|
395 { |
|
396 if (!m_document.IsEmpty()) { |
|
397 #ifndef NDEBUG |
|
398 V8GCController::unregisterGlobalHandle(this, m_document); |
|
399 #endif |
|
400 m_document.Dispose(); |
|
401 m_document.Clear(); |
|
402 } |
|
403 } |
|
404 |
|
405 void V8DOMWindowShell::updateDocumentWrapperCache() |
|
406 { |
|
407 v8::HandleScope handleScope; |
|
408 v8::Context::Scope contextScope(m_context); |
|
409 |
|
410 // If the document has no frame, NodeToV8Object might get the |
|
411 // document wrapper for a document that is about to be deleted. |
|
412 // If the ForceSet below causes a garbage collection, the document |
|
413 // might get deleted and the global handle for the document |
|
414 // wrapper cleared. Using the cleared global handle will lead to |
|
415 // crashes. In this case we clear the cache and let the DOMWindow |
|
416 // accessor handle access to the document. |
|
417 if (!m_frame->document()->frame()) { |
|
418 clearDocumentWrapperCache(); |
|
419 return; |
|
420 } |
|
421 |
|
422 v8::Handle<v8::Value> documentWrapper = toV8(m_frame->document()); |
|
423 |
|
424 // If instantiation of the document wrapper fails, clear the cache |
|
425 // and let the DOMWindow accessor handle access to the document. |
|
426 if (documentWrapper.IsEmpty()) { |
|
427 clearDocumentWrapperCache(); |
|
428 return; |
|
429 } |
|
430 ASSERT(documentWrapper->IsObject()); |
|
431 m_context->Global()->ForceSet(v8::String::New("document"), documentWrapper, static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete)); |
|
432 } |
|
433 |
|
434 void V8DOMWindowShell::clearDocumentWrapperCache() |
|
435 { |
|
436 ASSERT(!m_context.IsEmpty()); |
|
437 m_context->Global()->ForceDelete(v8::String::New("document")); |
|
438 } |
|
439 |
|
440 void V8DOMWindowShell::setSecurityToken() |
|
441 { |
|
442 Document* document = m_frame->document(); |
|
443 // Setup security origin and security token. |
|
444 if (!document) { |
|
445 m_context->UseDefaultSecurityToken(); |
|
446 return; |
|
447 } |
|
448 |
|
449 // Ask the document's SecurityOrigin to generate a security token. |
|
450 // If two tokens are equal, then the SecurityOrigins canAccess each other. |
|
451 // If two tokens are not equal, then we have to call canAccess. |
|
452 // Note: we can't use the HTTPOrigin if it was set from the DOM. |
|
453 SecurityOrigin* origin = document->securityOrigin(); |
|
454 String token; |
|
455 if (!origin->domainWasSetInDOM()) |
|
456 token = document->securityOrigin()->toString(); |
|
457 |
|
458 // An empty or "null" token means we always have to call |
|
459 // canAccess. The toString method on securityOrigins returns the |
|
460 // string "null" for empty security origins and for security |
|
461 // origins that should only allow access to themselves. In this |
|
462 // case, we use the global object as the security token to avoid |
|
463 // calling canAccess when a script accesses its own objects. |
|
464 if (token.isEmpty() || token == "null") { |
|
465 m_context->UseDefaultSecurityToken(); |
|
466 return; |
|
467 } |
|
468 |
|
469 CString utf8Token = token.utf8(); |
|
470 // NOTE: V8 does identity comparison in fast path, must use a symbol |
|
471 // as the security token. |
|
472 m_context->SetSecurityToken(v8::String::NewSymbol(utf8Token.data(), utf8Token.length())); |
|
473 } |
|
474 |
|
475 void V8DOMWindowShell::updateDocument() |
|
476 { |
|
477 if (!m_frame->document()) |
|
478 return; |
|
479 |
|
480 if (m_global.IsEmpty()) |
|
481 return; |
|
482 |
|
483 // There is an existing JavaScript wrapper for the global object |
|
484 // of this frame. JavaScript code in other frames might hold a |
|
485 // reference to this wrapper. We eagerly initialize the JavaScript |
|
486 // context for the new document to make property access on the |
|
487 // global object wrapper succeed. |
|
488 initContextIfNeeded(); |
|
489 |
|
490 // Bail out if context initialization failed. |
|
491 if (m_context.IsEmpty()) |
|
492 return; |
|
493 |
|
494 // We have a new document and we need to update the cache. |
|
495 updateDocumentWrapperCache(); |
|
496 |
|
497 updateSecurityOrigin(); |
|
498 } |
|
499 |
|
500 void V8DOMWindowShell::updateSecurityOrigin() |
|
501 { |
|
502 v8::HandleScope scope; |
|
503 setSecurityToken(); |
|
504 } |
|
505 |
|
506 v8::Handle<v8::Value> V8DOMWindowShell::getHiddenObjectPrototype(v8::Handle<v8::Context> context) |
|
507 { |
|
508 return context->Global()->GetHiddenValue(V8HiddenPropertyName::objectPrototype()); |
|
509 } |
|
510 |
|
511 bool V8DOMWindowShell::installHiddenObjectPrototype(v8::Handle<v8::Context> context) |
|
512 { |
|
513 v8::Handle<v8::String> objectString = v8::String::New("Object"); |
|
514 v8::Handle<v8::String> prototypeString = v8::String::New("prototype"); |
|
515 v8::Handle<v8::String> hiddenObjectPrototypeString = V8HiddenPropertyName::objectPrototype(); |
|
516 // Bail out if allocation failed. |
|
517 if (objectString.IsEmpty() || prototypeString.IsEmpty() || hiddenObjectPrototypeString.IsEmpty()) |
|
518 return false; |
|
519 |
|
520 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(context->Global()->Get(objectString)); |
|
521 // Bail out if fetching failed. |
|
522 if (object.IsEmpty()) |
|
523 return false; |
|
524 v8::Handle<v8::Value> objectPrototype = object->Get(prototypeString); |
|
525 // Bail out if fetching failed. |
|
526 if (objectPrototype.IsEmpty()) |
|
527 return false; |
|
528 |
|
529 context->Global()->SetHiddenValue(hiddenObjectPrototypeString, objectPrototype); |
|
530 |
|
531 return true; |
|
532 } |
|
533 |
|
534 v8::Local<v8::Object> V8DOMWindowShell::createWrapperFromCacheSlowCase(WrapperTypeInfo* type) |
|
535 { |
|
536 // Not in cache. |
|
537 initContextIfNeeded(); |
|
538 v8::Context::Scope scope(m_context); |
|
539 v8::Local<v8::Function> function = V8DOMWrapper::getConstructor(type, getHiddenObjectPrototype(m_context)); |
|
540 v8::Local<v8::Object> instance = SafeAllocation::newInstance(function); |
|
541 if (!instance.IsEmpty()) { |
|
542 m_wrapperBoilerplates.set(type, v8::Persistent<v8::Object>::New(instance)); |
|
543 return instance->Clone(); |
|
544 } |
|
545 return notHandledByInterceptor(); |
|
546 } |
|
547 |
|
548 void V8DOMWindowShell::setLocation(DOMWindow* window, const String& relativeURL) |
|
549 { |
|
550 Frame* frame = window->frame(); |
|
551 if (!frame) |
|
552 return; |
|
553 |
|
554 KURL url = completeURL(relativeURL); |
|
555 if (url.isNull()) |
|
556 return; |
|
557 |
|
558 if (!shouldAllowNavigation(frame)) |
|
559 return; |
|
560 |
|
561 navigateIfAllowed(frame, url, false, false); |
|
562 } |
|
563 |
|
564 } // WebCore |