1 /*
2 * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "config.h"
31 #include "InspectorController.h"
32
33 #if ENABLE(INSPECTOR)
34
35 #include "CString.h"
36 #include "CachedResource.h"
37 #include "Chrome.h"
38 #include "Console.h"
39 #include "ConsoleMessage.h"
40 #include "Cookie.h"
41 #include "CookieJar.h"
42 #include "DOMWindow.h"
43 #include "Document.h"
44 #include "DocumentLoader.h"
45 #include "Element.h"
46 #include "FloatConversion.h"
47 #include "FloatQuad.h"
48 #include "FloatRect.h"
49 #include "Frame.h"
50 #include "FrameLoader.h"
51 #include "FrameTree.h"
52 #include "FrameView.h"
53 #include "GraphicsContext.h"
54 #include "HTMLFrameOwnerElement.h"
55 #include "HitTestResult.h"
56 #include "InjectedScript.h"
57 #include "InjectedScriptHost.h"
58 #include "InspectorBackend.h"
59 #include "InspectorClient.h"
60 #include "InspectorDOMAgent.h"
61 #include "InspectorDOMStorageResource.h"
62 #include "InspectorDatabaseResource.h"
63 #include "InspectorFrontend.h"
64 #include "InspectorFrontendHost.h"
65 #include "InspectorResource.h"
66 #include "InspectorTimelineAgent.h"
67 #include "JavaScriptProfile.h"
68 #include "Page.h"
69 #include "ProgressTracker.h"
70 #include "Range.h"
71 #include "RenderInline.h"
72 #include "ResourceRequest.h"
73 #include "ResourceResponse.h"
74 #include "ScriptCallStack.h"
75 #include "ScriptDebugServer.h"
76 #include "ScriptFunctionCall.h"
77 #include "ScriptObject.h"
78 #include "ScriptProfile.h"
79 #include "ScriptProfiler.h"
80 #include "ScriptString.h"
81 #include "SecurityOrigin.h"
82 #include "Settings.h"
83 #include "SharedBuffer.h"
84 #include "TextEncoding.h"
85 #include "TextIterator.h"
86 #include <wtf/CurrentTime.h>
87 #include <wtf/ListHashSet.h>
88 #include <wtf/RefCounted.h>
89 #include <wtf/StdLibExtras.h>
90
91 #if ENABLE(DATABASE)
92 #include "Database.h"
93 #endif
94
95 #if ENABLE(DOM_STORAGE)
96 #include "Storage.h"
97 #include "StorageArea.h"
98 #endif
99
100 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
101 #include "JSJavaScriptCallFrame.h"
102 #include "JavaScriptCallFrame.h"
103 #include "JavaScriptDebugServer.h"
104
105 #include <runtime/JSLock.h>
106 #include <runtime/UString.h>
107
108 using namespace JSC;
109 #endif
110 using namespace std;
111
112 namespace WebCore {
113
114 static const char* const UserInitiatedProfileName = "org.webkit.profiles.user-initiated";
115 static const char* const CPUProfileType = "CPU";
116 static const char* const resourceTrackingEnabledSettingName = "resourceTrackingEnabled";
117 static const char* const debuggerEnabledSettingName = "debuggerEnabled";
118 static const char* const profilerEnabledSettingName = "profilerEnabled";
119 static const char* const inspectorAttachedHeightName = "inspectorAttachedHeight";
120 static const char* const lastActivePanelSettingName = "lastActivePanel";
121 const char* const InspectorController::FrontendSettingsSettingName = "frontendSettings";
122
123 static const unsigned defaultAttachedHeight = 300;
124 static const float minimumAttachedHeight = 250.0f;
125 static const float maximumAttachedHeightRatio = 0.75f;
126 static const unsigned maximumConsoleMessages = 1000;
127 static const unsigned expireConsoleMessagesStep = 100;
128
129 static unsigned s_inspectorControllerCount;
130
InspectorController(Page * page,InspectorClient * client)131 InspectorController::InspectorController(Page* page, InspectorClient* client)
132 : m_inspectedPage(page)
133 , m_client(client)
134 , m_page(0)
135 , m_expiredConsoleMessageCount(0)
136 , m_frontendScriptState(0)
137 , m_windowVisible(false)
138 , m_showAfterVisible(CurrentPanel)
139 , m_groupLevel(0)
140 , m_searchingForNode(false)
141 , m_previousMessage(0)
142 , m_resourceTrackingEnabled(false)
143 , m_resourceTrackingSettingsLoaded(false)
144 , m_inspectorBackend(InspectorBackend::create(this))
145 , m_inspectorFrontendHost(InspectorFrontendHost::create(this, client))
146 , m_injectedScriptHost(InjectedScriptHost::create(this))
147 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
148 , m_debuggerEnabled(false)
149 , m_attachDebuggerWhenShown(false)
150 #endif
151 #if ENABLE(JAVASCRIPT_DEBUGGER)
152 , m_profilerEnabled(!WTF_USE_JSC)
153 , m_recordingUserInitiatedProfile(false)
154 , m_currentUserInitiatedProfileNumber(-1)
155 , m_nextUserInitiatedProfileNumber(1)
156 , m_startProfiling(this, &InspectorController::startUserInitiatedProfiling)
157 #endif
158 {
159 ASSERT_ARG(page, page);
160 ASSERT_ARG(client, client);
161 ++s_inspectorControllerCount;
162 }
163
~InspectorController()164 InspectorController::~InspectorController()
165 {
166 // These should have been cleared in inspectedPageDestroyed().
167 ASSERT(!m_client);
168 ASSERT(!m_frontendScriptState);
169 ASSERT(!m_inspectedPage);
170 ASSERT(!m_page || (m_page && !m_page->parentInspectorController()));
171
172 deleteAllValues(m_frameResources);
173 deleteAllValues(m_consoleMessages);
174
175 ASSERT(s_inspectorControllerCount);
176 --s_inspectorControllerCount;
177
178 releaseDOMAgent();
179
180 m_inspectorBackend->disconnectController();
181 m_inspectorFrontendHost->disconnectController();
182 m_injectedScriptHost->disconnectController();
183 }
184
inspectedPageDestroyed()185 void InspectorController::inspectedPageDestroyed()
186 {
187 close();
188
189 if (m_frontendScriptState) {
190 ScriptGlobalObject::remove(m_frontendScriptState, "InspectorBackend");
191 ScriptGlobalObject::remove(m_frontendScriptState, "InspectorFrontendHost");
192 }
193 ASSERT(m_inspectedPage);
194 m_inspectedPage = 0;
195
196 m_client->inspectorDestroyed();
197 m_client = 0;
198 }
199
enabled() const200 bool InspectorController::enabled() const
201 {
202 if (!m_inspectedPage)
203 return false;
204 return m_inspectedPage->settings()->developerExtrasEnabled();
205 }
206
setting(const String & key) const207 String InspectorController::setting(const String& key) const
208 {
209 Settings::iterator it = m_settings.find(key);
210 if (it != m_settings.end())
211 return it->second;
212
213 String value;
214 m_client->populateSetting(key, &value);
215 m_settings.set(key, value);
216 return value;
217 }
218
setSetting(const String & key,const String & value)219 void InspectorController::setSetting(const String& key, const String& value)
220 {
221 m_settings.set(key, value);
222 m_client->storeSetting(key, value);
223 }
224
225 // Trying to inspect something in a frame with JavaScript disabled would later lead to
226 // crashes trying to create JavaScript wrappers. Some day we could fix this issue, but
227 // for now prevent crashes here by never targeting a node in such a frame.
canPassNodeToJavaScript(Node * node)228 static bool canPassNodeToJavaScript(Node* node)
229 {
230 if (!node)
231 return false;
232 Frame* frame = node->document()->frame();
233 return frame && frame->script()->canExecuteScripts();
234 }
235
inspect(Node * node)236 void InspectorController::inspect(Node* node)
237 {
238 if (!canPassNodeToJavaScript(node) || !enabled())
239 return;
240
241 show();
242
243 if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
244 node = node->parentNode();
245 m_nodeToFocus = node;
246
247 if (!m_frontend) {
248 m_showAfterVisible = ElementsPanel;
249 return;
250 }
251
252 focusNode();
253 }
254
focusNode()255 void InspectorController::focusNode()
256 {
257 if (!enabled())
258 return;
259
260 ASSERT(m_frontend);
261 ASSERT(m_nodeToFocus);
262
263 long id = m_domAgent->pushNodePathToFrontend(m_nodeToFocus.get());
264 m_frontend->updateFocusedNode(id);
265 m_nodeToFocus = 0;
266 }
267
highlight(Node * node)268 void InspectorController::highlight(Node* node)
269 {
270 if (!enabled())
271 return;
272 ASSERT_ARG(node, node);
273 m_highlightedNode = node;
274 m_client->highlight(node);
275 }
276
hideHighlight()277 void InspectorController::hideHighlight()
278 {
279 if (!enabled())
280 return;
281 m_highlightedNode = 0;
282 m_client->hideHighlight();
283 }
284
windowVisible()285 bool InspectorController::windowVisible()
286 {
287 return m_windowVisible;
288 }
289
setWindowVisible(bool visible,bool attached)290 void InspectorController::setWindowVisible(bool visible, bool attached)
291 {
292 if (visible == m_windowVisible || !m_frontend)
293 return;
294
295 m_windowVisible = visible;
296
297 if (m_windowVisible) {
298 setAttachedWindow(attached);
299 populateScriptObjects();
300
301 if (m_showAfterVisible == CurrentPanel) {
302 String lastActivePanelSetting = setting(lastActivePanelSettingName);
303 m_showAfterVisible = specialPanelForJSName(lastActivePanelSetting);
304 }
305
306 if (m_nodeToFocus)
307 focusNode();
308 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
309 if (m_attachDebuggerWhenShown)
310 enableDebugger();
311 #endif
312 showPanel(m_showAfterVisible);
313 } else {
314 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
315 // If the window is being closed with the debugger enabled,
316 // remember this state to re-enable debugger on the next window
317 // opening.
318 bool debuggerWasEnabled = m_debuggerEnabled;
319 disableDebugger();
320 if (debuggerWasEnabled)
321 m_attachDebuggerWhenShown = true;
322 #endif
323 if (m_searchingForNode)
324 toggleSearchForNodeInPage();
325 resetScriptObjects();
326 stopTimelineProfiler();
327 }
328 m_showAfterVisible = CurrentPanel;
329 }
330
addMessageToConsole(MessageSource source,MessageType type,MessageLevel level,ScriptCallStack * callStack)331 void InspectorController::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, ScriptCallStack* callStack)
332 {
333 if (!enabled())
334 return;
335
336 addConsoleMessage(callStack->state(), new ConsoleMessage(source, type, level, callStack, m_groupLevel, type == TraceMessageType));
337 }
338
addMessageToConsole(MessageSource source,MessageType type,MessageLevel level,const String & message,unsigned lineNumber,const String & sourceID)339 void InspectorController::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceID)
340 {
341 if (!enabled())
342 return;
343
344 addConsoleMessage(0, new ConsoleMessage(source, type, level, message, lineNumber, sourceID, m_groupLevel));
345 }
346
addConsoleMessage(ScriptState * scriptState,ConsoleMessage * consoleMessage)347 void InspectorController::addConsoleMessage(ScriptState* scriptState, ConsoleMessage* consoleMessage)
348 {
349 ASSERT(enabled());
350 ASSERT_ARG(consoleMessage, consoleMessage);
351
352 if (m_previousMessage && m_previousMessage->isEqual(scriptState, consoleMessage)) {
353 m_previousMessage->incrementCount();
354 delete consoleMessage;
355 if (windowVisible())
356 m_previousMessage->updateRepeatCountInConsole(m_frontend.get());
357 } else {
358 m_previousMessage = consoleMessage;
359 m_consoleMessages.append(consoleMessage);
360 if (windowVisible())
361 m_previousMessage->addToConsole(m_frontend.get());
362 }
363
364 if (!windowVisible() && m_consoleMessages.size() >= maximumConsoleMessages) {
365 m_expiredConsoleMessageCount += expireConsoleMessagesStep;
366 for (size_t i = 0; i < expireConsoleMessagesStep; ++i)
367 delete m_consoleMessages[i];
368 m_consoleMessages.remove(0, expireConsoleMessagesStep);
369 }
370 }
371
clearConsoleMessages()372 void InspectorController::clearConsoleMessages()
373 {
374 deleteAllValues(m_consoleMessages);
375 m_consoleMessages.clear();
376 m_expiredConsoleMessageCount = 0;
377 m_previousMessage = 0;
378 m_groupLevel = 0;
379 m_injectedScriptHost->releaseWrapperObjectGroup(0 /* release the group in all scripts */, "console");
380 if (m_domAgent)
381 m_domAgent->releaseDanglingNodes();
382 if (m_frontend)
383 m_frontend->clearConsoleMessages();
384 }
385
startGroup(MessageSource source,ScriptCallStack * callStack)386 void InspectorController::startGroup(MessageSource source, ScriptCallStack* callStack)
387 {
388 ++m_groupLevel;
389
390 addConsoleMessage(callStack->state(), new ConsoleMessage(source, StartGroupMessageType, LogMessageLevel, callStack, m_groupLevel));
391 }
392
endGroup(MessageSource source,unsigned lineNumber,const String & sourceURL)393 void InspectorController::endGroup(MessageSource source, unsigned lineNumber, const String& sourceURL)
394 {
395 if (!m_groupLevel)
396 return;
397
398 --m_groupLevel;
399
400 addConsoleMessage(0, new ConsoleMessage(source, EndGroupMessageType, LogMessageLevel, String(), lineNumber, sourceURL, m_groupLevel));
401 }
402
markTimeline(const String & message)403 void InspectorController::markTimeline(const String& message)
404 {
405 if (timelineAgent())
406 timelineAgent()->didMarkTimeline(message);
407 }
408
constrainedAttachedWindowHeight(unsigned preferredHeight,unsigned totalWindowHeight)409 static unsigned constrainedAttachedWindowHeight(unsigned preferredHeight, unsigned totalWindowHeight)
410 {
411 return roundf(max(minimumAttachedHeight, min<float>(preferredHeight, totalWindowHeight * maximumAttachedHeightRatio)));
412 }
413
attachWindow()414 void InspectorController::attachWindow()
415 {
416 if (!enabled())
417 return;
418
419 unsigned inspectedPageHeight = m_inspectedPage->mainFrame()->view()->visibleHeight();
420
421 m_client->attachWindow();
422
423 String attachedHeight = setting(inspectorAttachedHeightName);
424 bool success = true;
425 int height = attachedHeight.toInt(&success);
426 unsigned preferredHeight = success ? height : defaultAttachedHeight;
427
428 // We need to constrain the window height here in case the user has resized the inspected page's window so that
429 // the user's preferred height would be too big to display.
430 m_client->setAttachedWindowHeight(constrainedAttachedWindowHeight(preferredHeight, inspectedPageHeight));
431 }
432
detachWindow()433 void InspectorController::detachWindow()
434 {
435 if (!enabled())
436 return;
437 m_client->detachWindow();
438 }
439
setAttachedWindow(bool attached)440 void InspectorController::setAttachedWindow(bool attached)
441 {
442 if (!enabled() || !m_frontend)
443 return;
444
445 m_frontend->setAttachedWindow(attached);
446 }
447
setAttachedWindowHeight(unsigned height)448 void InspectorController::setAttachedWindowHeight(unsigned height)
449 {
450 if (!enabled())
451 return;
452
453 unsigned totalHeight = m_page->mainFrame()->view()->visibleHeight() + m_inspectedPage->mainFrame()->view()->visibleHeight();
454 unsigned attachedHeight = constrainedAttachedWindowHeight(height, totalHeight);
455
456 setSetting(inspectorAttachedHeightName, String::number(attachedHeight));
457
458 m_client->setAttachedWindowHeight(attachedHeight);
459 }
460
storeLastActivePanel(const String & panelName)461 void InspectorController::storeLastActivePanel(const String& panelName)
462 {
463 setSetting(lastActivePanelSettingName, panelName);
464 }
465
toggleSearchForNodeInPage()466 void InspectorController::toggleSearchForNodeInPage()
467 {
468 if (!enabled())
469 return;
470
471 m_searchingForNode = !m_searchingForNode;
472 if (!m_searchingForNode)
473 hideHighlight();
474 }
475
mouseDidMoveOverElement(const HitTestResult & result,unsigned)476 void InspectorController::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
477 {
478 if (!enabled() || !m_searchingForNode)
479 return;
480
481 Node* node = result.innerNode();
482 if (node)
483 highlight(node);
484 }
485
handleMousePressOnNode(Node * node)486 void InspectorController::handleMousePressOnNode(Node* node)
487 {
488 if (!enabled())
489 return;
490
491 ASSERT(m_searchingForNode);
492 ASSERT(node);
493 if (!node)
494 return;
495
496 // inspect() will implicitly call ElementsPanel's focusedNodeChanged() and the hover feedback will be stopped there.
497 inspect(node);
498 }
499
inspectedWindowScriptObjectCleared(Frame * frame)500 void InspectorController::inspectedWindowScriptObjectCleared(Frame* frame)
501 {
502 if (!enabled() || !m_frontend || frame != m_inspectedPage->mainFrame())
503 return;
504 m_injectedScriptHost->discardInjectedScripts();
505 }
506
windowScriptObjectAvailable()507 void InspectorController::windowScriptObjectAvailable()
508 {
509 if (!m_page || !enabled())
510 return;
511
512 // Grant the inspector the ability to script the inspected page.
513 m_page->mainFrame()->document()->securityOrigin()->grantUniversalAccess();
514 m_frontendScriptState = scriptStateFromPage(debuggerWorld(), m_page);
515 ScriptGlobalObject::set(m_frontendScriptState, "InspectorBackend", m_inspectorBackend.get());
516 ScriptGlobalObject::set(m_frontendScriptState, "InspectorFrontendHost", m_inspectorFrontendHost.get());
517 }
518
scriptObjectReady()519 void InspectorController::scriptObjectReady()
520 {
521 ASSERT(m_frontendScriptState);
522 if (!m_frontendScriptState)
523 return;
524
525 ScriptObject webInspectorObj;
526 if (!ScriptGlobalObject::get(m_frontendScriptState, "WebInspector", webInspectorObj))
527 return;
528 setFrontendProxyObject(m_frontendScriptState, webInspectorObj);
529
530 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
531 String debuggerEnabled = setting(debuggerEnabledSettingName);
532 if (debuggerEnabled == "true")
533 enableDebugger();
534 String profilerEnabled = setting(profilerEnabledSettingName);
535 if (profilerEnabled == "true")
536 enableProfiler();
537 #endif
538
539 // Make sure our window is visible now that the page loaded
540 showWindow();
541
542 m_client->inspectorWindowObjectCleared();
543 }
544
setFrontendProxyObject(ScriptState * scriptState,ScriptObject webInspectorObj,ScriptObject)545 void InspectorController::setFrontendProxyObject(ScriptState* scriptState, ScriptObject webInspectorObj, ScriptObject)
546 {
547 m_frontendScriptState = scriptState;
548 m_frontend.set(new InspectorFrontend(this, webInspectorObj));
549 releaseDOMAgent();
550 m_domAgent = InspectorDOMAgent::create(m_frontend.get());
551 if (m_timelineAgent)
552 m_timelineAgent->resetFrontendProxyObject(m_frontend.get());
553 }
554
show()555 void InspectorController::show()
556 {
557 if (!enabled())
558 return;
559
560 if (!m_page) {
561 if (m_frontend)
562 return; // We are using custom frontend - no need to create page.
563
564 m_page = m_client->createPage();
565 if (!m_page)
566 return;
567 m_page->setParentInspectorController(this);
568
569 // showWindow() will be called after the page loads in scriptObjectReady()
570 return;
571 }
572
573 showWindow();
574 }
575
showPanel(SpecialPanels panel)576 void InspectorController::showPanel(SpecialPanels panel)
577 {
578 if (!enabled())
579 return;
580
581 show();
582
583 if (!m_frontend) {
584 m_showAfterVisible = panel;
585 return;
586 }
587
588 if (panel == CurrentPanel)
589 return;
590
591 m_frontend->showPanel(panel);
592 }
593
close()594 void InspectorController::close()
595 {
596 if (!enabled())
597 return;
598
599 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
600 stopUserInitiatedProfiling();
601 disableDebugger();
602 #endif
603 closeWindow();
604
605 releaseDOMAgent();
606 m_frontend.set(0);
607 m_timelineAgent = 0;
608 m_frontendScriptState = 0;
609 if (m_page) {
610 if (!m_page->mainFrame() || !m_page->mainFrame()->loader() || !m_page->mainFrame()->loader()->isLoading()) {
611 m_page->setParentInspectorController(0);
612 m_page = 0;
613 }
614 }
615 }
616
showWindow()617 void InspectorController::showWindow()
618 {
619 ASSERT(enabled());
620
621 unsigned inspectedPageHeight = m_inspectedPage->mainFrame()->view()->visibleHeight();
622
623 m_client->showWindow();
624
625 String attachedHeight = setting(inspectorAttachedHeightName);
626 bool success = true;
627 int height = attachedHeight.toInt(&success);
628 unsigned preferredHeight = success ? height : defaultAttachedHeight;
629
630 // This call might not go through (if the window starts out detached), but if the window is initially created attached,
631 // InspectorController::attachWindow is never called, so we need to make sure to set the attachedWindowHeight.
632 // FIXME: Clean up code so we only have to call setAttachedWindowHeight in InspectorController::attachWindow
633 m_client->setAttachedWindowHeight(constrainedAttachedWindowHeight(preferredHeight, inspectedPageHeight));
634 }
635
closeWindow()636 void InspectorController::closeWindow()
637 {
638 m_client->closeWindow();
639 }
640
releaseDOMAgent()641 void InspectorController::releaseDOMAgent()
642 {
643 // m_domAgent is RefPtr. Remove DOM listeners first to ensure that there are
644 // no references to the DOM agent from the DOM tree.
645 if (m_domAgent)
646 m_domAgent->reset();
647 m_domAgent = 0;
648 }
649
populateScriptObjects()650 void InspectorController::populateScriptObjects()
651 {
652 ASSERT(m_frontend);
653 if (!m_frontend)
654 return;
655
656 m_frontend->populateFrontendSettings(setting(FrontendSettingsSettingName));
657 m_domAgent->setDocument(m_inspectedPage->mainFrame()->document());
658
659 ResourcesMap::iterator resourcesEnd = m_resources.end();
660 for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it)
661 it->second->updateScriptObject(m_frontend.get());
662
663 if (m_expiredConsoleMessageCount)
664 m_frontend->updateConsoleMessageExpiredCount(m_expiredConsoleMessageCount);
665 unsigned messageCount = m_consoleMessages.size();
666 for (unsigned i = 0; i < messageCount; ++i)
667 m_consoleMessages[i]->addToConsole(m_frontend.get());
668
669 #if ENABLE(DATABASE)
670 DatabaseResourcesMap::iterator databasesEnd = m_databaseResources.end();
671 for (DatabaseResourcesMap::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it)
672 it->second->bind(m_frontend.get());
673 #endif
674 #if ENABLE(DOM_STORAGE)
675 DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
676 for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it)
677 it->second->bind(m_frontend.get());
678 #endif
679
680 m_frontend->populateInterface();
681
682 // Dispatch pending frontend commands
683 for (Vector<pair<long, String> >::iterator it = m_pendingEvaluateTestCommands.begin(); it != m_pendingEvaluateTestCommands.end(); ++it)
684 m_frontend->evaluateForTestInFrontend((*it).first, (*it).second);
685 m_pendingEvaluateTestCommands.clear();
686 }
687
resetScriptObjects()688 void InspectorController::resetScriptObjects()
689 {
690 if (!m_frontend)
691 return;
692
693 ResourcesMap::iterator resourcesEnd = m_resources.end();
694 for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it)
695 it->second->releaseScriptObject(m_frontend.get(), false);
696
697 #if ENABLE(DATABASE)
698 DatabaseResourcesMap::iterator databasesEnd = m_databaseResources.end();
699 for (DatabaseResourcesMap::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it)
700 it->second->unbind();
701 #endif
702 #if ENABLE(DOM_STORAGE)
703 DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
704 for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it)
705 it->second->unbind();
706 #endif
707
708 if (m_timelineAgent)
709 m_timelineAgent->reset();
710
711 m_frontend->reset();
712 m_domAgent->reset();
713 }
714
pruneResources(ResourcesMap * resourceMap,DocumentLoader * loaderToKeep)715 void InspectorController::pruneResources(ResourcesMap* resourceMap, DocumentLoader* loaderToKeep)
716 {
717 ASSERT_ARG(resourceMap, resourceMap);
718
719 ResourcesMap mapCopy(*resourceMap);
720 ResourcesMap::iterator end = mapCopy.end();
721 for (ResourcesMap::iterator it = mapCopy.begin(); it != end; ++it) {
722 InspectorResource* resource = (*it).second.get();
723 if (resource == m_mainResource)
724 continue;
725
726 if (!loaderToKeep || !resource->isSameLoader(loaderToKeep)) {
727 removeResource(resource);
728 if (windowVisible())
729 resource->releaseScriptObject(m_frontend.get(), true);
730 }
731 }
732 }
733
didCommitLoad(DocumentLoader * loader)734 void InspectorController::didCommitLoad(DocumentLoader* loader)
735 {
736 if (!enabled())
737 return;
738
739 ASSERT(m_inspectedPage);
740
741 if (loader->frame() == m_inspectedPage->mainFrame()) {
742 m_client->inspectedURLChanged(loader->url().string());
743
744 m_injectedScriptHost->discardInjectedScripts();
745 clearConsoleMessages();
746
747 m_times.clear();
748 m_counts.clear();
749 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
750 m_profiles.clear();
751 m_currentUserInitiatedProfileNumber = 1;
752 m_nextUserInitiatedProfileNumber = 1;
753 #endif
754 // resetScriptObjects should be called before database and DOM storage
755 // resources are cleared so that it has a chance to unbind them.
756 resetScriptObjects();
757
758 #if ENABLE(DATABASE)
759 m_databaseResources.clear();
760 #endif
761 #if ENABLE(DOM_STORAGE)
762 m_domStorageResources.clear();
763 #endif
764
765 if (m_frontend) {
766 if (!loader->frameLoader()->isLoadingFromCachedPage()) {
767 ASSERT(m_mainResource && m_mainResource->isSameLoader(loader));
768 // We don't add the main resource until its load is committed. This is
769 // needed to keep the load for a user-entered URL from showing up in the
770 // list of resources for the page they are navigating away from.
771 if (windowVisible())
772 m_mainResource->updateScriptObject(m_frontend.get());
773 } else {
774 // Pages loaded from the page cache are committed before
775 // m_mainResource is the right resource for this load, so we
776 // clear it here. It will be re-assigned in
777 // identifierForInitialRequest.
778 m_mainResource = 0;
779 }
780 if (windowVisible()) {
781 m_frontend->didCommitLoad();
782 m_domAgent->setDocument(m_inspectedPage->mainFrame()->document());
783 }
784 }
785 }
786
787 for (Frame* frame = loader->frame(); frame; frame = frame->tree()->traverseNext(loader->frame()))
788 if (ResourcesMap* resourceMap = m_frameResources.get(frame))
789 pruneResources(resourceMap, loader);
790 }
791
frameDetachedFromParent(Frame * frame)792 void InspectorController::frameDetachedFromParent(Frame* frame)
793 {
794 if (!enabled())
795 return;
796 if (ResourcesMap* resourceMap = m_frameResources.get(frame))
797 removeAllResources(resourceMap);
798 }
799
addResource(InspectorResource * resource)800 void InspectorController::addResource(InspectorResource* resource)
801 {
802 m_resources.set(resource->identifier(), resource);
803 m_knownResources.add(resource->requestURL());
804
805 Frame* frame = resource->frame();
806 ResourcesMap* resourceMap = m_frameResources.get(frame);
807 if (resourceMap)
808 resourceMap->set(resource->identifier(), resource);
809 else {
810 resourceMap = new ResourcesMap;
811 resourceMap->set(resource->identifier(), resource);
812 m_frameResources.set(frame, resourceMap);
813 }
814 }
815
removeResource(InspectorResource * resource)816 void InspectorController::removeResource(InspectorResource* resource)
817 {
818 m_resources.remove(resource->identifier());
819 String requestURL = resource->requestURL();
820 if (!requestURL.isNull())
821 m_knownResources.remove(requestURL);
822
823 Frame* frame = resource->frame();
824 ResourcesMap* resourceMap = m_frameResources.get(frame);
825 if (!resourceMap) {
826 ASSERT_NOT_REACHED();
827 return;
828 }
829
830 resourceMap->remove(resource->identifier());
831 if (resourceMap->isEmpty()) {
832 m_frameResources.remove(frame);
833 delete resourceMap;
834 }
835 }
836
getTrackedResource(unsigned long identifier)837 InspectorResource* InspectorController::getTrackedResource(unsigned long identifier)
838 {
839 if (!enabled())
840 return 0;
841
842 if (m_resourceTrackingEnabled)
843 return m_resources.get(identifier).get();
844
845 bool isMainResource = m_mainResource && m_mainResource->identifier() == identifier;
846 if (isMainResource)
847 return m_mainResource.get();
848
849 return 0;
850 }
851
didLoadResourceFromMemoryCache(DocumentLoader * loader,const CachedResource * cachedResource)852 void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader* loader, const CachedResource* cachedResource)
853 {
854 if (!enabled())
855 return;
856
857 // If the resource URL is already known, we don't need to add it again since this is just a cached load.
858 if (m_knownResources.contains(cachedResource->url()))
859 return;
860
861 ASSERT(m_inspectedPage);
862 bool isMainResource = isMainResourceLoader(loader, KURL(ParsedURLString, cachedResource->url()));
863 ensureResourceTrackingSettingsLoaded();
864 if (!isMainResource && !m_resourceTrackingEnabled)
865 return;
866
867 RefPtr<InspectorResource> resource = InspectorResource::createCached(m_inspectedPage->progress()->createUniqueIdentifier(), loader, cachedResource);
868
869 if (isMainResource) {
870 m_mainResource = resource;
871 resource->markMainResource();
872 }
873
874 addResource(resource.get());
875
876 if (windowVisible())
877 resource->updateScriptObject(m_frontend.get());
878 }
879
identifierForInitialRequest(unsigned long identifier,DocumentLoader * loader,const ResourceRequest & request)880 void InspectorController::identifierForInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request)
881 {
882 if (!enabled())
883 return;
884 ASSERT(m_inspectedPage);
885
886 bool isMainResource = isMainResourceLoader(loader, request.url());
887 ensureResourceTrackingSettingsLoaded();
888 if (!isMainResource && !m_resourceTrackingEnabled)
889 return;
890
891 RefPtr<InspectorResource> resource = InspectorResource::create(identifier, loader, request.url());
892
893 if (isMainResource) {
894 m_mainResource = resource;
895 resource->markMainResource();
896 }
897
898 addResource(resource.get());
899
900 if (windowVisible() && loader->frameLoader()->isLoadingFromCachedPage() && resource == m_mainResource)
901 resource->updateScriptObject(m_frontend.get());
902 }
903
mainResourceFiredDOMContentEvent(DocumentLoader * loader,const KURL & url)904 void InspectorController::mainResourceFiredDOMContentEvent(DocumentLoader* loader, const KURL& url)
905 {
906 if (!enabled() || !isMainResourceLoader(loader, url))
907 return;
908
909 if (m_mainResource) {
910 m_mainResource->markDOMContentEventTime();
911 if (windowVisible())
912 m_mainResource->updateScriptObject(m_frontend.get());
913 }
914 }
915
mainResourceFiredLoadEvent(DocumentLoader * loader,const KURL & url)916 void InspectorController::mainResourceFiredLoadEvent(DocumentLoader* loader, const KURL& url)
917 {
918 if (!enabled() || !isMainResourceLoader(loader, url))
919 return;
920
921 if (m_mainResource) {
922 m_mainResource->markLoadEventTime();
923 if (windowVisible())
924 m_mainResource->updateScriptObject(m_frontend.get());
925 }
926 }
927
isMainResourceLoader(DocumentLoader * loader,const KURL & requestUrl)928 bool InspectorController::isMainResourceLoader(DocumentLoader* loader, const KURL& requestUrl)
929 {
930 return loader->frame() == m_inspectedPage->mainFrame() && requestUrl == loader->requestURL();
931 }
932
willSendRequest(unsigned long identifier,const ResourceRequest & request,const ResourceResponse & redirectResponse)933 void InspectorController::willSendRequest(unsigned long identifier, const ResourceRequest& request, const ResourceResponse& redirectResponse)
934 {
935 bool isMainResource = (m_mainResource && m_mainResource->identifier() == identifier);
936 if (m_timelineAgent)
937 m_timelineAgent->willSendResourceRequest(identifier, isMainResource, request);
938
939 RefPtr<InspectorResource> resource = getTrackedResource(identifier);
940 if (!resource)
941 return;
942
943 if (!redirectResponse.isNull()) {
944 resource->markResponseReceivedTime();
945 resource->endTiming();
946 resource->updateResponse(redirectResponse);
947
948 // We always store last redirect by the original id key. Rest of the redirects are stored within the last one.
949 unsigned long id = m_inspectedPage->progress()->createUniqueIdentifier();
950 RefPtr<InspectorResource> withRedirect = resource->appendRedirect(id, request.url());
951 removeResource(resource.get());
952 addResource(withRedirect.get());
953 if (isMainResource) {
954 m_mainResource = withRedirect;
955 withRedirect->markMainResource();
956 }
957 resource = withRedirect;
958 }
959
960 resource->startTiming();
961 resource->updateRequest(request);
962
963 if (resource != m_mainResource && windowVisible())
964 resource->updateScriptObject(m_frontend.get());
965 }
966
didReceiveResponse(unsigned long identifier,const ResourceResponse & response)967 void InspectorController::didReceiveResponse(unsigned long identifier, const ResourceResponse& response)
968 {
969 if (m_timelineAgent)
970 m_timelineAgent->didReceiveResourceResponse(identifier, response);
971
972 RefPtr<InspectorResource> resource = getTrackedResource(identifier);
973 if (!resource)
974 return;
975
976 resource->updateResponse(response);
977 resource->markResponseReceivedTime();
978
979 if (resource != m_mainResource && windowVisible())
980 resource->updateScriptObject(m_frontend.get());
981 }
982
didReceiveContentLength(unsigned long identifier,int lengthReceived)983 void InspectorController::didReceiveContentLength(unsigned long identifier, int lengthReceived)
984 {
985 RefPtr<InspectorResource> resource = getTrackedResource(identifier);
986 if (!resource)
987 return;
988
989 resource->addLength(lengthReceived);
990
991 if (resource != m_mainResource && windowVisible())
992 resource->updateScriptObject(m_frontend.get());
993 }
994
didFinishLoading(unsigned long identifier)995 void InspectorController::didFinishLoading(unsigned long identifier)
996 {
997 if (m_timelineAgent)
998 m_timelineAgent->didFinishLoadingResource(identifier, false);
999
1000 RefPtr<InspectorResource> resource = getTrackedResource(identifier);
1001 if (!resource)
1002 return;
1003
1004 resource->endTiming();
1005
1006 if (resource != m_mainResource && windowVisible())
1007 resource->updateScriptObject(m_frontend.get());
1008 }
1009
didFailLoading(unsigned long identifier,const ResourceError &)1010 void InspectorController::didFailLoading(unsigned long identifier, const ResourceError& /*error*/)
1011 {
1012 if (m_timelineAgent)
1013 m_timelineAgent->didFinishLoadingResource(identifier, true);
1014
1015 RefPtr<InspectorResource> resource = getTrackedResource(identifier);
1016 if (!resource)
1017 return;
1018
1019 resource->markFailed();
1020 resource->endTiming();
1021
1022 if (resource != m_mainResource && windowVisible())
1023 resource->updateScriptObject(m_frontend.get());
1024 }
1025
resourceRetrievedByXMLHttpRequest(unsigned long identifier,const ScriptString & sourceString)1026 void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString)
1027 {
1028 if (!enabled() || !m_resourceTrackingEnabled)
1029 return;
1030
1031 InspectorResource* resource = m_resources.get(identifier).get();
1032 if (!resource)
1033 return;
1034
1035 resource->setXMLHttpResponseText(sourceString);
1036
1037 if (windowVisible())
1038 resource->updateScriptObject(m_frontend.get());
1039 }
1040
scriptImported(unsigned long identifier,const String & sourceString)1041 void InspectorController::scriptImported(unsigned long identifier, const String& sourceString)
1042 {
1043 if (!enabled() || !m_resourceTrackingEnabled)
1044 return;
1045
1046 InspectorResource* resource = m_resources.get(identifier).get();
1047 if (!resource)
1048 return;
1049
1050 // FIXME: imported script and XHR response are currently viewed as the same
1051 // thing by the Inspector. They should be made into distinct types.
1052 resource->setXMLHttpResponseText(ScriptString(sourceString));
1053
1054 if (windowVisible())
1055 resource->updateScriptObject(m_frontend.get());
1056 }
1057
enableResourceTracking(bool always,bool reload)1058 void InspectorController::enableResourceTracking(bool always, bool reload)
1059 {
1060 if (!enabled())
1061 return;
1062
1063 if (always)
1064 setSetting(resourceTrackingEnabledSettingName, "true");
1065
1066 if (m_resourceTrackingEnabled)
1067 return;
1068
1069 ASSERT(m_inspectedPage);
1070 m_resourceTrackingEnabled = true;
1071 if (m_frontend)
1072 m_frontend->resourceTrackingWasEnabled();
1073
1074 if (reload)
1075 m_inspectedPage->mainFrame()->loader()->reload();
1076 }
1077
disableResourceTracking(bool always)1078 void InspectorController::disableResourceTracking(bool always)
1079 {
1080 if (!enabled())
1081 return;
1082
1083 if (always)
1084 setSetting(resourceTrackingEnabledSettingName, "false");
1085
1086 ASSERT(m_inspectedPage);
1087 m_resourceTrackingEnabled = false;
1088 if (m_frontend)
1089 m_frontend->resourceTrackingWasDisabled();
1090 }
1091
ensureResourceTrackingSettingsLoaded()1092 void InspectorController::ensureResourceTrackingSettingsLoaded()
1093 {
1094 if (m_resourceTrackingSettingsLoaded)
1095 return;
1096 m_resourceTrackingSettingsLoaded = true;
1097
1098 String resourceTracking = setting(resourceTrackingEnabledSettingName);
1099 if (resourceTracking == "true")
1100 m_resourceTrackingEnabled = true;
1101 }
1102
startTimelineProfiler()1103 void InspectorController::startTimelineProfiler()
1104 {
1105 if (!enabled())
1106 return;
1107
1108 if (m_timelineAgent)
1109 return;
1110
1111 m_timelineAgent = new InspectorTimelineAgent(m_frontend.get());
1112 if (m_frontend)
1113 m_frontend->timelineProfilerWasStarted();
1114 }
1115
stopTimelineProfiler()1116 void InspectorController::stopTimelineProfiler()
1117 {
1118 if (!enabled())
1119 return;
1120
1121 if (!m_timelineAgent)
1122 return;
1123
1124 m_timelineAgent = 0;
1125 if (m_frontend)
1126 m_frontend->timelineProfilerWasStopped();
1127 }
1128
1129 #if ENABLE(DATABASE)
selectDatabase(Database * database)1130 void InspectorController::selectDatabase(Database* database)
1131 {
1132 if (!m_frontend)
1133 return;
1134
1135 for (DatabaseResourcesMap::iterator it = m_databaseResources.begin(); it != m_databaseResources.end(); ++it) {
1136 if (it->second->database() == database) {
1137 m_frontend->selectDatabase(it->first);
1138 break;
1139 }
1140 }
1141 }
1142
databaseForId(int databaseId)1143 Database* InspectorController::databaseForId(int databaseId)
1144 {
1145 DatabaseResourcesMap::iterator it = m_databaseResources.find(databaseId);
1146 if (it == m_databaseResources.end())
1147 return 0;
1148 return it->second->database();
1149 }
1150
didOpenDatabase(Database * database,const String & domain,const String & name,const String & version)1151 void InspectorController::didOpenDatabase(Database* database, const String& domain, const String& name, const String& version)
1152 {
1153 if (!enabled())
1154 return;
1155
1156 RefPtr<InspectorDatabaseResource> resource = InspectorDatabaseResource::create(database, domain, name, version);
1157
1158 m_databaseResources.set(resource->id(), resource);
1159
1160 // Resources are only bound while visible.
1161 if (windowVisible())
1162 resource->bind(m_frontend.get());
1163 }
1164 #endif
1165
getCookies(long callId)1166 void InspectorController::getCookies(long callId)
1167 {
1168 if (!m_frontend)
1169 return;
1170
1171 // If we can get raw cookies.
1172 ListHashSet<Cookie> rawCookiesList;
1173
1174 // If we can't get raw cookies - fall back to String representation
1175 String stringCookiesList;
1176
1177 // Return value to getRawCookies should be the same for every call because
1178 // the return value is platform/network backend specific, and the call will
1179 // always return the same true/false value.
1180 bool rawCookiesImplemented = false;
1181
1182 ResourcesMap::iterator resourcesEnd = m_resources.end();
1183 for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it) {
1184 Document* document = it->second->frame()->document();
1185 Vector<Cookie> docCookiesList;
1186 rawCookiesImplemented = getRawCookies(document, it->second->requestURL(), docCookiesList);
1187
1188 if (!rawCookiesImplemented) {
1189 // FIXME: We need duplication checking for the String representation of cookies.
1190 ExceptionCode ec = 0;
1191 stringCookiesList += document->cookie(ec);
1192 // Exceptions are thrown by cookie() in sandboxed frames. That won't happen here
1193 // because "document" is the document of the main frame of the page.
1194 ASSERT(!ec);
1195 } else {
1196 int cookiesSize = docCookiesList.size();
1197 for (int i = 0; i < cookiesSize; i++) {
1198 if (!rawCookiesList.contains(docCookiesList[i]))
1199 rawCookiesList.add(docCookiesList[i]);
1200 }
1201 }
1202 }
1203
1204 if (!rawCookiesImplemented)
1205 m_frontend->didGetCookies(callId, m_frontend->newScriptArray(), stringCookiesList);
1206 else
1207 m_frontend->didGetCookies(callId, buildArrayForCookies(rawCookiesList), String());
1208 }
1209
buildArrayForCookies(ListHashSet<Cookie> & cookiesList)1210 ScriptArray InspectorController::buildArrayForCookies(ListHashSet<Cookie>& cookiesList)
1211 {
1212 ScriptArray cookies = m_frontend->newScriptArray();
1213
1214 ListHashSet<Cookie>::iterator end = cookiesList.end();
1215 ListHashSet<Cookie>::iterator it = cookiesList.begin();
1216 for (int i = 0; it != end; ++it, i++)
1217 cookies.set(i, buildObjectForCookie(*it));
1218
1219 return cookies;
1220 }
1221
buildObjectForCookie(const Cookie & cookie)1222 ScriptObject InspectorController::buildObjectForCookie(const Cookie& cookie)
1223 {
1224 ScriptObject value = m_frontend->newScriptObject();
1225 value.set("name", cookie.name);
1226 value.set("value", cookie.value);
1227 value.set("domain", cookie.domain);
1228 value.set("path", cookie.path);
1229 value.set("expires", cookie.expires);
1230 value.set("size", (cookie.name.length() + cookie.value.length()));
1231 value.set("httpOnly", cookie.httpOnly);
1232 value.set("secure", cookie.secure);
1233 value.set("session", cookie.session);
1234 return value;
1235 }
1236
1237 #if ENABLE(DOM_STORAGE)
didUseDOMStorage(StorageArea * storageArea,bool isLocalStorage,Frame * frame)1238 void InspectorController::didUseDOMStorage(StorageArea* storageArea, bool isLocalStorage, Frame* frame)
1239 {
1240 if (!enabled())
1241 return;
1242
1243 DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
1244 for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it)
1245 if (it->second->isSameHostAndType(frame, isLocalStorage))
1246 return;
1247
1248 RefPtr<Storage> domStorage = Storage::create(frame, storageArea);
1249 RefPtr<InspectorDOMStorageResource> resource = InspectorDOMStorageResource::create(domStorage.get(), isLocalStorage, frame);
1250
1251 m_domStorageResources.set(resource->id(), resource);
1252
1253 // Resources are only bound while visible.
1254 if (windowVisible())
1255 resource->bind(m_frontend.get());
1256 }
1257
selectDOMStorage(Storage * storage)1258 void InspectorController::selectDOMStorage(Storage* storage)
1259 {
1260 ASSERT(storage);
1261 if (!m_frontend)
1262 return;
1263
1264 Frame* frame = storage->frame();
1265 bool isLocalStorage = (frame->domWindow()->localStorage() == storage);
1266 int storageResourceId = 0;
1267 DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
1268 for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it) {
1269 if (it->second->isSameHostAndType(frame, isLocalStorage)) {
1270 storageResourceId = it->first;
1271 break;
1272 }
1273 }
1274 if (storageResourceId)
1275 m_frontend->selectDOMStorage(storageResourceId);
1276 }
1277
getDOMStorageEntries(int callId,int storageId)1278 void InspectorController::getDOMStorageEntries(int callId, int storageId)
1279 {
1280 if (!m_frontend)
1281 return;
1282
1283 ScriptArray jsonArray = m_frontend->newScriptArray();
1284 InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId);
1285 if (storageResource) {
1286 storageResource->startReportingChangesToFrontend();
1287 Storage* domStorage = storageResource->domStorage();
1288 for (unsigned i = 0; i < domStorage->length(); ++i) {
1289 String name(domStorage->key(i));
1290 String value(domStorage->getItem(name));
1291 ScriptArray entry = m_frontend->newScriptArray();
1292 entry.set(0, name);
1293 entry.set(1, value);
1294 jsonArray.set(i, entry);
1295 }
1296 }
1297 m_frontend->didGetDOMStorageEntries(callId, jsonArray);
1298 }
1299
setDOMStorageItem(long callId,long storageId,const String & key,const String & value)1300 void InspectorController::setDOMStorageItem(long callId, long storageId, const String& key, const String& value)
1301 {
1302 if (!m_frontend)
1303 return;
1304
1305 bool success = false;
1306 InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId);
1307 if (storageResource) {
1308 ExceptionCode exception = 0;
1309 storageResource->domStorage()->setItem(key, value, exception);
1310 success = !exception;
1311 }
1312 m_frontend->didSetDOMStorageItem(callId, success);
1313 }
1314
removeDOMStorageItem(long callId,long storageId,const String & key)1315 void InspectorController::removeDOMStorageItem(long callId, long storageId, const String& key)
1316 {
1317 if (!m_frontend)
1318 return;
1319
1320 bool success = false;
1321 InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId);
1322 if (storageResource) {
1323 storageResource->domStorage()->removeItem(key);
1324 success = true;
1325 }
1326 m_frontend->didRemoveDOMStorageItem(callId, success);
1327 }
1328
getDOMStorageResourceForId(int storageId)1329 InspectorDOMStorageResource* InspectorController::getDOMStorageResourceForId(int storageId)
1330 {
1331 DOMStorageResourcesMap::iterator it = m_domStorageResources.find(storageId);
1332 if (it == m_domStorageResources.end())
1333 return 0;
1334 return it->second.get();
1335 }
1336 #endif
1337
moveWindowBy(float x,float y) const1338 void InspectorController::moveWindowBy(float x, float y) const
1339 {
1340 if (!m_page || !enabled())
1341 return;
1342
1343 FloatRect frameRect = m_page->chrome()->windowRect();
1344 frameRect.move(x, y);
1345 m_page->chrome()->setWindowRect(frameRect);
1346 }
1347
1348 #if ENABLE(JAVASCRIPT_DEBUGGER)
addProfile(PassRefPtr<ScriptProfile> prpProfile,unsigned lineNumber,const String & sourceURL)1349 void InspectorController::addProfile(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL)
1350 {
1351 if (!enabled())
1352 return;
1353
1354 RefPtr<ScriptProfile> profile = prpProfile;
1355 m_profiles.add(profile->uid(), profile);
1356
1357 if (m_frontend) {
1358 #if USE(JSC)
1359 JSLock lock(SilenceAssertionsOnly);
1360 #endif
1361 m_frontend->addProfileHeader(createProfileHeader(*profile));
1362 }
1363
1364 addProfileFinishedMessageToConsole(profile, lineNumber, sourceURL);
1365 }
1366
addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile> prpProfile,unsigned lineNumber,const String & sourceURL)1367 void InspectorController::addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL)
1368 {
1369 RefPtr<ScriptProfile> profile = prpProfile;
1370
1371 String message = String::format("Profile \"webkit-profile://%s/%s#%d\" finished.", CPUProfileType, encodeWithURLEscapeSequences(profile->title()).utf8().data(), profile->uid());
1372 addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceURL);
1373 }
1374
addStartProfilingMessageToConsole(const String & title,unsigned lineNumber,const String & sourceURL)1375 void InspectorController::addStartProfilingMessageToConsole(const String& title, unsigned lineNumber, const String& sourceURL)
1376 {
1377 String message = String::format("Profile \"webkit-profile://%s/%s#0\" started.", CPUProfileType, encodeWithURLEscapeSequences(title).utf8().data());
1378 addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceURL);
1379 }
1380
getProfileHeaders(long callId)1381 void InspectorController::getProfileHeaders(long callId)
1382 {
1383 if (!m_frontend)
1384 return;
1385 ScriptArray result = m_frontend->newScriptArray();
1386 ProfilesMap::iterator profilesEnd = m_profiles.end();
1387 int i = 0;
1388 for (ProfilesMap::iterator it = m_profiles.begin(); it != profilesEnd; ++it)
1389 result.set(i++, createProfileHeader(*it->second));
1390 m_frontend->didGetProfileHeaders(callId, result);
1391 }
1392
getProfile(long callId,unsigned uid)1393 void InspectorController::getProfile(long callId, unsigned uid)
1394 {
1395 if (!m_frontend)
1396 return;
1397 ProfilesMap::iterator it = m_profiles.find(uid);
1398 #if USE(JSC)
1399 if (it != m_profiles.end())
1400 m_frontend->didGetProfile(callId, toJS(m_frontendScriptState, it->second.get()));
1401 #endif
1402 }
1403
createProfileHeader(const ScriptProfile & profile)1404 ScriptObject InspectorController::createProfileHeader(const ScriptProfile& profile)
1405 {
1406 ScriptObject header = m_frontend->newScriptObject();
1407 header.set("title", profile.title());
1408 header.set("uid", profile.uid());
1409 header.set("typeId", String(CPUProfileType));
1410 return header;
1411 }
1412
getCurrentUserInitiatedProfileName(bool incrementProfileNumber=false)1413 String InspectorController::getCurrentUserInitiatedProfileName(bool incrementProfileNumber = false)
1414 {
1415 if (incrementProfileNumber)
1416 m_currentUserInitiatedProfileNumber = m_nextUserInitiatedProfileNumber++;
1417
1418 return String::format("%s.%d", UserInitiatedProfileName, m_currentUserInitiatedProfileNumber);
1419 }
1420
startUserInitiatedProfilingSoon()1421 void InspectorController::startUserInitiatedProfilingSoon()
1422 {
1423 m_startProfiling.startOneShot(0);
1424 }
1425
startUserInitiatedProfiling(Timer<InspectorController> *)1426 void InspectorController::startUserInitiatedProfiling(Timer<InspectorController>*)
1427 {
1428 if (!enabled())
1429 return;
1430
1431 if (!profilerEnabled()) {
1432 enableProfiler(false, true);
1433 ScriptDebugServer::recompileAllJSFunctions();
1434 }
1435
1436 m_recordingUserInitiatedProfile = true;
1437
1438 String title = getCurrentUserInitiatedProfileName(true);
1439
1440 #if USE(JSC)
1441 ExecState* scriptState = toJSDOMWindow(m_inspectedPage->mainFrame(), debuggerWorld())->globalExec();
1442 #else
1443 ScriptState* scriptState = 0;
1444 #endif
1445 ScriptProfiler::start(scriptState, title);
1446
1447 addStartProfilingMessageToConsole(title, 0, String());
1448
1449 toggleRecordButton(true);
1450 }
1451
stopUserInitiatedProfiling()1452 void InspectorController::stopUserInitiatedProfiling()
1453 {
1454 if (!enabled())
1455 return;
1456
1457 m_recordingUserInitiatedProfile = false;
1458
1459 String title = getCurrentUserInitiatedProfileName();
1460
1461 #if USE(JSC)
1462 ExecState* scriptState = toJSDOMWindow(m_inspectedPage->mainFrame(), debuggerWorld())->globalExec();
1463 #else
1464 ScriptState* scriptState = 0;
1465 #endif
1466 RefPtr<ScriptProfile> profile = ScriptProfiler::stop(scriptState, title);
1467 if (profile)
1468 addProfile(profile, 0, String());
1469
1470 toggleRecordButton(false);
1471 }
1472
toggleRecordButton(bool isProfiling)1473 void InspectorController::toggleRecordButton(bool isProfiling)
1474 {
1475 if (!m_frontend)
1476 return;
1477 m_frontend->setRecordingProfile(isProfiling);
1478 }
1479
enableProfiler(bool always,bool skipRecompile)1480 void InspectorController::enableProfiler(bool always, bool skipRecompile)
1481 {
1482 if (always)
1483 setSetting(profilerEnabledSettingName, "true");
1484
1485 if (m_profilerEnabled)
1486 return;
1487
1488 m_profilerEnabled = true;
1489
1490 if (!skipRecompile)
1491 ScriptDebugServer::recompileAllJSFunctionsSoon();
1492
1493 if (m_frontend)
1494 m_frontend->profilerWasEnabled();
1495 }
1496
disableProfiler(bool always)1497 void InspectorController::disableProfiler(bool always)
1498 {
1499 if (always)
1500 setSetting(profilerEnabledSettingName, "false");
1501
1502 if (!m_profilerEnabled)
1503 return;
1504
1505 m_profilerEnabled = false;
1506
1507 ScriptDebugServer::recompileAllJSFunctionsSoon();
1508
1509 if (m_frontend)
1510 m_frontend->profilerWasDisabled();
1511 }
1512 #endif
1513
1514 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
enableDebuggerFromFrontend(bool always)1515 void InspectorController::enableDebuggerFromFrontend(bool always)
1516 {
1517 if (always)
1518 setSetting(debuggerEnabledSettingName, "true");
1519
1520 ASSERT(m_inspectedPage);
1521
1522 JavaScriptDebugServer::shared().addListener(this, m_inspectedPage);
1523 JavaScriptDebugServer::shared().clearBreakpoints();
1524
1525 m_debuggerEnabled = true;
1526 m_frontend->debuggerWasEnabled();
1527 }
1528
enableDebugger()1529 void InspectorController::enableDebugger()
1530 {
1531 if (!enabled())
1532 return;
1533
1534 if (m_debuggerEnabled)
1535 return;
1536
1537 if (!m_frontendScriptState || !m_frontend)
1538 m_attachDebuggerWhenShown = true;
1539 else {
1540 m_frontend->attachDebuggerWhenShown();
1541 m_attachDebuggerWhenShown = false;
1542 }
1543 }
1544
disableDebugger(bool always)1545 void InspectorController::disableDebugger(bool always)
1546 {
1547 if (!enabled())
1548 return;
1549
1550 if (always)
1551 setSetting(debuggerEnabledSettingName, "false");
1552
1553 ASSERT(m_inspectedPage);
1554
1555 JavaScriptDebugServer::shared().removeListener(this, m_inspectedPage);
1556
1557 m_debuggerEnabled = false;
1558 m_attachDebuggerWhenShown = false;
1559
1560 if (m_frontend)
1561 m_frontend->debuggerWasDisabled();
1562 }
1563
resumeDebugger()1564 void InspectorController::resumeDebugger()
1565 {
1566 if (!m_debuggerEnabled)
1567 return;
1568 JavaScriptDebugServer::shared().continueProgram();
1569 }
1570
1571 // JavaScriptDebugListener functions
1572
didParseSource(ExecState *,const SourceCode & source)1573 void InspectorController::didParseSource(ExecState*, const SourceCode& source)
1574 {
1575 m_frontend->parsedScriptSource(source);
1576 }
1577
failedToParseSource(ExecState *,const SourceCode & source,int errorLine,const UString & errorMessage)1578 void InspectorController::failedToParseSource(ExecState*, const SourceCode& source, int errorLine, const UString& errorMessage)
1579 {
1580 m_frontend->failedToParseScriptSource(source, errorLine, errorMessage);
1581 }
1582
didPause()1583 void InspectorController::didPause()
1584 {
1585 JavaScriptCallFrame* callFrame = m_injectedScriptHost->currentCallFrame();
1586 ScriptState* scriptState = callFrame->scopeChain()->globalObject->globalExec();
1587 ASSERT(scriptState);
1588 InjectedScript injectedScript = m_injectedScriptHost->injectedScriptFor(scriptState);
1589 RefPtr<SerializedScriptValue> callFrames = injectedScript.callFrames();
1590 m_frontend->pausedScript(callFrames.get());
1591 }
1592
didContinue()1593 void InspectorController::didContinue()
1594 {
1595 m_frontend->resumedScript();
1596 }
1597
1598 #endif
1599
evaluateForTestInFrontend(long callId,const String & script)1600 void InspectorController::evaluateForTestInFrontend(long callId, const String& script)
1601 {
1602 if (m_frontend)
1603 m_frontend->evaluateForTestInFrontend(callId, script);
1604 else
1605 m_pendingEvaluateTestCommands.append(pair<long, String>(callId, script));
1606 }
1607
didEvaluateForTestInFrontend(long callId,const String & jsonResult)1608 void InspectorController::didEvaluateForTestInFrontend(long callId, const String& jsonResult)
1609 {
1610 ScriptState* scriptState = scriptStateFromPage(debuggerWorld(), m_inspectedPage);
1611 ScriptObject window;
1612 ScriptGlobalObject::get(scriptState, "window", window);
1613 ScriptFunctionCall function(window, "didEvaluateForTestInFrontend");
1614 function.appendArgument(callId);
1615 function.appendArgument(jsonResult);
1616 function.call();
1617 }
1618
quadToPath(const FloatQuad & quad)1619 static Path quadToPath(const FloatQuad& quad)
1620 {
1621 Path quadPath;
1622 quadPath.moveTo(quad.p1());
1623 quadPath.addLineTo(quad.p2());
1624 quadPath.addLineTo(quad.p3());
1625 quadPath.addLineTo(quad.p4());
1626 quadPath.closeSubpath();
1627 return quadPath;
1628 }
1629
drawOutlinedQuad(GraphicsContext & context,const FloatQuad & quad,const Color & fillColor)1630 static void drawOutlinedQuad(GraphicsContext& context, const FloatQuad& quad, const Color& fillColor)
1631 {
1632 static const int outlineThickness = 2;
1633 static const Color outlineColor(62, 86, 180, 228);
1634
1635 Path quadPath = quadToPath(quad);
1636
1637 // Clip out the quad, then draw with a 2px stroke to get a pixel
1638 // of outline (because inflating a quad is hard)
1639 {
1640 context.save();
1641 context.addPath(quadPath);
1642 context.clipOut(quadPath);
1643
1644 context.addPath(quadPath);
1645 context.setStrokeThickness(outlineThickness);
1646 context.setStrokeColor(outlineColor, DeviceColorSpace);
1647 context.strokePath();
1648
1649 context.restore();
1650 }
1651
1652 // Now do the fill
1653 context.addPath(quadPath);
1654 context.setFillColor(fillColor, DeviceColorSpace);
1655 context.fillPath();
1656 }
1657
drawOutlinedQuadWithClip(GraphicsContext & context,const FloatQuad & quad,const FloatQuad & clipQuad,const Color & fillColor)1658 static void drawOutlinedQuadWithClip(GraphicsContext& context, const FloatQuad& quad, const FloatQuad& clipQuad, const Color& fillColor)
1659 {
1660 context.save();
1661 Path clipQuadPath = quadToPath(clipQuad);
1662 context.clipOut(clipQuadPath);
1663 drawOutlinedQuad(context, quad, fillColor);
1664 context.restore();
1665 }
1666
drawHighlightForBox(GraphicsContext & context,const FloatQuad & contentQuad,const FloatQuad & paddingQuad,const FloatQuad & borderQuad,const FloatQuad & marginQuad)1667 static void drawHighlightForBox(GraphicsContext& context, const FloatQuad& contentQuad, const FloatQuad& paddingQuad, const FloatQuad& borderQuad, const FloatQuad& marginQuad)
1668 {
1669 static const Color contentBoxColor(125, 173, 217, 128);
1670 static const Color paddingBoxColor(125, 173, 217, 160);
1671 static const Color borderBoxColor(125, 173, 217, 192);
1672 static const Color marginBoxColor(125, 173, 217, 228);
1673
1674 if (marginQuad != borderQuad)
1675 drawOutlinedQuadWithClip(context, marginQuad, borderQuad, marginBoxColor);
1676 if (borderQuad != paddingQuad)
1677 drawOutlinedQuadWithClip(context, borderQuad, paddingQuad, borderBoxColor);
1678 if (paddingQuad != contentQuad)
1679 drawOutlinedQuadWithClip(context, paddingQuad, contentQuad, paddingBoxColor);
1680
1681 drawOutlinedQuad(context, contentQuad, contentBoxColor);
1682 }
1683
drawHighlightForLineBoxes(GraphicsContext & context,const Vector<FloatQuad> & lineBoxQuads)1684 static void drawHighlightForLineBoxes(GraphicsContext& context, const Vector<FloatQuad>& lineBoxQuads)
1685 {
1686 static const Color lineBoxColor(125, 173, 217, 128);
1687
1688 for (size_t i = 0; i < lineBoxQuads.size(); ++i)
1689 drawOutlinedQuad(context, lineBoxQuads[i], lineBoxColor);
1690 }
1691
convertFromFrameToMainFrame(Frame * frame,IntRect & rect)1692 static inline void convertFromFrameToMainFrame(Frame* frame, IntRect& rect)
1693 {
1694 rect = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(rect));
1695 }
1696
frameToMainFrameOffset(Frame * frame)1697 static inline IntSize frameToMainFrameOffset(Frame* frame)
1698 {
1699 IntPoint mainFramePoint = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint()));
1700 return mainFramePoint - IntPoint();
1701 }
1702
drawNodeHighlight(GraphicsContext & context) const1703 void InspectorController::drawNodeHighlight(GraphicsContext& context) const
1704 {
1705 if (!m_highlightedNode)
1706 return;
1707
1708 RenderObject* renderer = m_highlightedNode->renderer();
1709 Frame* containingFrame = m_highlightedNode->document()->frame();
1710 if (!renderer || !containingFrame)
1711 return;
1712
1713 IntSize mainFrameOffset = frameToMainFrameOffset(containingFrame);
1714 IntRect boundingBox = renderer->absoluteBoundingBoxRect(true);
1715 boundingBox.move(mainFrameOffset);
1716
1717 ASSERT(m_inspectedPage);
1718
1719 FrameView* view = m_inspectedPage->mainFrame()->view();
1720 FloatRect overlayRect = view->visibleContentRect();
1721 if (!overlayRect.contains(boundingBox) && !boundingBox.contains(enclosingIntRect(overlayRect)))
1722 overlayRect = view->visibleContentRect();
1723 context.translate(-overlayRect.x(), -overlayRect.y());
1724
1725 if (renderer->isBox()) {
1726 RenderBox* renderBox = toRenderBox(renderer);
1727
1728 IntRect contentBox = renderBox->contentBoxRect();
1729
1730 IntRect paddingBox(contentBox.x() - renderBox->paddingLeft(), contentBox.y() - renderBox->paddingTop(),
1731 contentBox.width() + renderBox->paddingLeft() + renderBox->paddingRight(), contentBox.height() + renderBox->paddingTop() + renderBox->paddingBottom());
1732 IntRect borderBox(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(),
1733 paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom());
1734 IntRect marginBox(borderBox.x() - renderBox->marginLeft(), borderBox.y() - renderBox->marginTop(),
1735 borderBox.width() + renderBox->marginLeft() + renderBox->marginRight(), borderBox.height() + renderBox->marginTop() + renderBox->marginBottom());
1736
1737 FloatQuad absContentQuad = renderBox->localToAbsoluteQuad(FloatRect(contentBox));
1738 FloatQuad absPaddingQuad = renderBox->localToAbsoluteQuad(FloatRect(paddingBox));
1739 FloatQuad absBorderQuad = renderBox->localToAbsoluteQuad(FloatRect(borderBox));
1740 FloatQuad absMarginQuad = renderBox->localToAbsoluteQuad(FloatRect(marginBox));
1741
1742 absContentQuad.move(mainFrameOffset);
1743 absPaddingQuad.move(mainFrameOffset);
1744 absBorderQuad.move(mainFrameOffset);
1745 absMarginQuad.move(mainFrameOffset);
1746
1747 drawHighlightForBox(context, absContentQuad, absPaddingQuad, absBorderQuad, absMarginQuad);
1748 } else if (renderer->isRenderInline()) {
1749 RenderInline* renderInline = toRenderInline(renderer);
1750
1751 // FIXME: We should show margins/padding/border for inlines.
1752 Vector<FloatQuad> lineBoxQuads;
1753 renderInline->absoluteQuads(lineBoxQuads);
1754 for (unsigned i = 0; i < lineBoxQuads.size(); ++i)
1755 lineBoxQuads[i] += mainFrameOffset;
1756
1757 drawHighlightForLineBoxes(context, lineBoxQuads);
1758 }
1759 }
1760
count(const String & title,unsigned lineNumber,const String & sourceID)1761 void InspectorController::count(const String& title, unsigned lineNumber, const String& sourceID)
1762 {
1763 String identifier = title + String::format("@%s:%d", sourceID.utf8().data(), lineNumber);
1764 HashMap<String, unsigned>::iterator it = m_counts.find(identifier);
1765 int count;
1766 if (it == m_counts.end())
1767 count = 1;
1768 else {
1769 count = it->second + 1;
1770 m_counts.remove(it);
1771 }
1772
1773 m_counts.add(identifier, count);
1774
1775 String message = String::format("%s: %d", title.utf8().data(), count);
1776 addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceID);
1777 }
1778
startTiming(const String & title)1779 void InspectorController::startTiming(const String& title)
1780 {
1781 m_times.add(title, currentTime() * 1000);
1782 }
1783
stopTiming(const String & title,double & elapsed)1784 bool InspectorController::stopTiming(const String& title, double& elapsed)
1785 {
1786 HashMap<String, double>::iterator it = m_times.find(title);
1787 if (it == m_times.end())
1788 return false;
1789
1790 double startTime = it->second;
1791 m_times.remove(it);
1792
1793 elapsed = currentTime() * 1000 - startTime;
1794 return true;
1795 }
1796
specialPanelForJSName(const String & panelName)1797 InspectorController::SpecialPanels InspectorController::specialPanelForJSName(const String& panelName)
1798 {
1799 if (panelName == "elements")
1800 return ElementsPanel;
1801 if (panelName == "resources")
1802 return ResourcesPanel;
1803 if (panelName == "scripts")
1804 return ScriptsPanel;
1805 if (panelName == "timeline")
1806 return TimelinePanel;
1807 if (panelName == "profiles")
1808 return ProfilesPanel;
1809 if (panelName == "storage" || panelName == "databases")
1810 return StoragePanel;
1811 if (panelName == "console")
1812 return ConsolePanel;
1813 return ElementsPanel;
1814 }
1815
deleteCookie(const String & cookieName,const String & domain)1816 void InspectorController::deleteCookie(const String& cookieName, const String& domain)
1817 {
1818 ResourcesMap::iterator resourcesEnd = m_resources.end();
1819 for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it) {
1820 Document* document = it->second->frame()->document();
1821 if (document->url().host() == domain)
1822 WebCore::deleteCookie(document, it->second->requestURL(), cookieName);
1823 }
1824 }
1825
injectedScriptForNodeId(long id)1826 InjectedScript InspectorController::injectedScriptForNodeId(long id)
1827 {
1828
1829 Frame* frame = 0;
1830 if (id) {
1831 ASSERT(m_domAgent);
1832 Node* node = m_domAgent->nodeForId(id);
1833 if (node) {
1834 Document* document = node->ownerDocument();
1835 if (document)
1836 frame = document->frame();
1837 }
1838 } else
1839 frame = m_inspectedPage->mainFrame();
1840
1841 if (frame)
1842 return m_injectedScriptHost->injectedScriptFor(mainWorldScriptState(frame));
1843
1844 return InjectedScript();
1845 }
1846
1847 } // namespace WebCore
1848
1849 #endif // ENABLE(INSPECTOR)
1850