2008-11-04 Anders Carlsson <andersca@apple.com>
[webkit/qt.git] / WebCore / inspector / InspectorController.cpp
blob8476b9884f0d109bf47bcf2493b086c33dda6159
1 /*
2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
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.
30 #include "config.h"
31 #include "InspectorController.h"
33 #include "CString.h"
34 #include "CachedResource.h"
35 #include "Console.h"
36 #include "DOMWindow.h"
37 #include "DocLoader.h"
38 #include "Document.h"
39 #include "DocumentLoader.h"
40 #include "Element.h"
41 #include "FloatConversion.h"
42 #include "FloatRect.h"
43 #include "Frame.h"
44 #include "FrameLoader.h"
45 #include "FrameTree.h"
46 #include "FrameView.h"
47 #include "GraphicsContext.h"
48 #include "HitTestResult.h"
49 #include "HTMLFrameOwnerElement.h"
50 #include "InspectorClient.h"
51 #include "JSDOMWindow.h"
52 #include "JSInspectedObjectWrapper.h"
53 #include "JSInspectorCallbackWrapper.h"
54 #include "JSNode.h"
55 #include "JSRange.h"
56 #include "JavaScriptProfile.h"
57 #include "Page.h"
58 #include "Range.h"
59 #include "ResourceRequest.h"
60 #include "ResourceResponse.h"
61 #include "Settings.h"
62 #include "SharedBuffer.h"
63 #include "SystemTime.h"
64 #include "TextEncoding.h"
65 #include "TextIterator.h"
66 #include "ScriptController.h"
67 #include <JavaScriptCore/APICast.h>
68 #include <JavaScriptCore/JSRetainPtr.h>
69 #include <JavaScriptCore/JSStringRef.h>
70 #include <JavaScriptCore/OpaqueJSString.h>
71 #include <runtime/JSLock.h>
72 #include <kjs/ustring.h>
73 #include <runtime/CollectorHeapIterator.h>
74 #include <profiler/Profile.h>
75 #include <profiler/Profiler.h>
76 #include <wtf/RefCounted.h>
78 #if ENABLE(DATABASE)
79 #include "Database.h"
80 #include "JSDatabase.h"
81 #endif
83 #if ENABLE(JAVASCRIPT_DEBUGGER)
84 #include "JavaScriptCallFrame.h"
85 #include "JavaScriptDebugServer.h"
86 #include "JSJavaScriptCallFrame.h"
87 #endif
89 using namespace JSC;
90 using namespace std;
92 namespace WebCore {
94 static const char* const UserInitiatedProfileName = "org.webkit.profiles.user-initiated";
96 static JSRetainPtr<JSStringRef> jsStringRef(const char* str)
98 return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString(str));
101 static JSRetainPtr<JSStringRef> jsStringRef(const SourceCode& str)
103 return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithCharacters(str.data(), str.length()));
106 static JSRetainPtr<JSStringRef> jsStringRef(const String& str)
108 return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithCharacters(str.characters(), str.length()));
111 static JSRetainPtr<JSStringRef> jsStringRef(const UString& str)
113 return JSRetainPtr<JSStringRef>(Adopt, OpaqueJSString::create(str).releaseRef());
116 static String toString(JSContextRef context, JSValueRef value, JSValueRef* exception)
118 ASSERT_ARG(value, value);
119 if (!value)
120 return String();
121 JSRetainPtr<JSStringRef> scriptString(Adopt, JSValueToStringCopy(context, value, exception));
122 if (exception && *exception)
123 return String();
124 return String(JSStringGetCharactersPtr(scriptString.get()), JSStringGetLength(scriptString.get()));
127 #define HANDLE_EXCEPTION(context, exception) handleException((context), (exception), __LINE__)
129 JSValueRef InspectorController::callSimpleFunction(JSContextRef context, JSObjectRef thisObject, const char* functionName) const
131 JSValueRef exception = 0;
132 return callFunction(context, thisObject, functionName, 0, 0, exception);
135 JSValueRef InspectorController::callFunction(JSContextRef context, JSObjectRef thisObject, const char* functionName, size_t argumentCount, const JSValueRef arguments[], JSValueRef& exception) const
137 ASSERT_ARG(context, context);
138 ASSERT_ARG(thisObject, thisObject);
140 if (exception)
141 return JSValueMakeUndefined(context);
143 JSValueRef functionProperty = JSObjectGetProperty(context, thisObject, jsStringRef(functionName).get(), &exception);
144 if (HANDLE_EXCEPTION(context, exception))
145 return JSValueMakeUndefined(context);
147 JSObjectRef function = JSValueToObject(context, functionProperty, &exception);
148 if (HANDLE_EXCEPTION(context, exception))
149 return JSValueMakeUndefined(context);
151 JSValueRef result = JSObjectCallAsFunction(context, function, thisObject, argumentCount, arguments, &exception);
152 if (HANDLE_EXCEPTION(context, exception))
153 return JSValueMakeUndefined(context);
155 return result;
158 // ConsoleMessage Struct
160 struct ConsoleMessage {
161 ConsoleMessage(MessageSource s, MessageLevel l, const String& m, unsigned li, const String& u, unsigned g)
162 : source(s)
163 , level(l)
164 , message(m)
165 , line(li)
166 , url(u)
167 , groupLevel(g)
168 , repeatCount(1)
172 ConsoleMessage(MessageSource s, MessageLevel l, ExecState* exec, const ArgList& args, unsigned li, const String& u, unsigned g)
173 : source(s)
174 , level(l)
175 , wrappedArguments(args.size())
176 , line(li)
177 , url(u)
178 , groupLevel(g)
179 , repeatCount(1)
181 JSLock lock(false);
182 for (unsigned i = 0; i < args.size(); ++i)
183 wrappedArguments[i] = JSInspectedObjectWrapper::wrap(exec, args.at(exec, i));
186 bool isEqual(ExecState* exec, ConsoleMessage* msg) const
188 if (msg->wrappedArguments.size() != this->wrappedArguments.size() ||
189 (!exec && msg->wrappedArguments.size()))
190 return false;
192 for (size_t i = 0; i < msg->wrappedArguments.size(); ++i) {
193 ASSERT_ARG(exec, exec);
194 if (!JSValueIsEqual(toRef(exec), toRef(msg->wrappedArguments[i].get()), toRef(this->wrappedArguments[i].get()), 0))
195 return false;
198 return msg->source == this->source
199 && msg->level == this->level
200 && msg->message == this->message
201 && msg->line == this->line
202 && msg->url == this->url
203 && msg->groupLevel == this->groupLevel;
206 MessageSource source;
207 MessageLevel level;
208 String message;
209 Vector<ProtectedPtr<JSValue> > wrappedArguments;
210 unsigned line;
211 String url;
212 unsigned groupLevel;
213 unsigned repeatCount;
216 // XMLHttpRequestResource Class
218 struct XMLHttpRequestResource {
219 XMLHttpRequestResource(JSC::UString& sourceString)
221 JSC::JSLock lock(false);
222 this->sourceString = sourceString.rep();
225 ~XMLHttpRequestResource()
227 JSC::JSLock lock(false);
228 sourceString.clear();
231 RefPtr<JSC::UString::Rep> sourceString;
234 // InspectorResource Struct
236 struct InspectorResource : public RefCounted<InspectorResource> {
237 // Keep these in sync with WebInspector.Resource.Type
238 enum Type {
239 Doc,
240 Stylesheet,
241 Image,
242 Font,
243 Script,
244 XHR,
245 Media,
246 Other
249 static PassRefPtr<InspectorResource> create(long long identifier, DocumentLoader* documentLoader, Frame* frame)
251 return adoptRef(new InspectorResource(identifier, documentLoader, frame));
254 ~InspectorResource()
256 setScriptObject(0, 0);
259 Type type() const
261 if (xmlHttpRequestResource)
262 return XHR;
264 if (requestURL == loader->requestURL())
265 return Doc;
267 if (loader->frameLoader() && requestURL == loader->frameLoader()->iconURL())
268 return Image;
270 CachedResource* cachedResource = frame->document()->docLoader()->cachedResource(requestURL.string());
271 if (!cachedResource)
272 return Other;
274 switch (cachedResource->type()) {
275 case CachedResource::ImageResource:
276 return Image;
277 case CachedResource::FontResource:
278 return Font;
279 case CachedResource::CSSStyleSheet:
280 #if ENABLE(XSLT)
281 case CachedResource::XSLStyleSheet:
282 #endif
283 return Stylesheet;
284 case CachedResource::Script:
285 return Script;
286 default:
287 return Other;
291 void setScriptObject(JSContextRef context, JSObjectRef newScriptObject)
293 if (scriptContext && scriptObject)
294 JSValueUnprotect(scriptContext, scriptObject);
296 scriptObject = newScriptObject;
297 scriptContext = context;
299 ASSERT((context && newScriptObject) || (!context && !newScriptObject));
300 if (context && newScriptObject)
301 JSValueProtect(context, newScriptObject);
304 void setXMLHttpRequestProperties(JSC::UString& data)
306 xmlHttpRequestResource.set(new XMLHttpRequestResource(data));
309 String sourceString() const
311 if (xmlHttpRequestResource)
312 return JSC::UString(xmlHttpRequestResource->sourceString);
314 RefPtr<SharedBuffer> buffer;
315 String textEncodingName;
317 if (requestURL == loader->requestURL()) {
318 buffer = loader->mainResourceData();
319 textEncodingName = frame->document()->inputEncoding();
320 } else {
321 CachedResource* cachedResource = frame->document()->docLoader()->cachedResource(requestURL.string());
322 if (!cachedResource)
323 return String();
325 buffer = cachedResource->data();
326 textEncodingName = cachedResource->encoding();
329 if (!buffer)
330 return String();
332 TextEncoding encoding(textEncodingName);
333 if (!encoding.isValid())
334 encoding = WindowsLatin1Encoding();
335 return encoding.decode(buffer->data(), buffer->size());
338 long long identifier;
339 RefPtr<DocumentLoader> loader;
340 RefPtr<Frame> frame;
341 OwnPtr<XMLHttpRequestResource> xmlHttpRequestResource;
342 KURL requestURL;
343 HTTPHeaderMap requestHeaderFields;
344 HTTPHeaderMap responseHeaderFields;
345 String mimeType;
346 String suggestedFilename;
347 JSContextRef scriptContext;
348 JSObjectRef scriptObject;
349 long long expectedContentLength;
350 bool cached;
351 bool finished;
352 bool failed;
353 int length;
354 int responseStatusCode;
355 double startTime;
356 double responseReceivedTime;
357 double endTime;
359 protected:
360 InspectorResource(long long identifier, DocumentLoader* documentLoader, Frame* frame)
361 : identifier(identifier)
362 , loader(documentLoader)
363 , frame(frame)
364 , xmlHttpRequestResource(0)
365 , scriptContext(0)
366 , scriptObject(0)
367 , expectedContentLength(0)
368 , cached(false)
369 , finished(false)
370 , failed(false)
371 , length(0)
372 , responseStatusCode(0)
373 , startTime(-1.0)
374 , responseReceivedTime(-1.0)
375 , endTime(-1.0)
380 // InspectorDatabaseResource Struct
382 #if ENABLE(DATABASE)
383 struct InspectorDatabaseResource : public RefCounted<InspectorDatabaseResource> {
384 static PassRefPtr<InspectorDatabaseResource> create(Database* database, const String& domain, const String& name, const String& version)
386 return adoptRef(new InspectorDatabaseResource(database, domain, name, version));
389 void setScriptObject(JSContextRef context, JSObjectRef newScriptObject)
391 if (scriptContext && scriptObject)
392 JSValueUnprotect(scriptContext, scriptObject);
394 scriptObject = newScriptObject;
395 scriptContext = context;
397 ASSERT((context && newScriptObject) || (!context && !newScriptObject));
398 if (context && newScriptObject)
399 JSValueProtect(context, newScriptObject);
402 RefPtr<Database> database;
403 String domain;
404 String name;
405 String version;
406 JSContextRef scriptContext;
407 JSObjectRef scriptObject;
409 private:
410 InspectorDatabaseResource(Database* database, const String& domain, const String& name, const String& version)
411 : database(database)
412 , domain(domain)
413 , name(name)
414 , version(version)
415 , scriptContext(0)
416 , scriptObject(0)
420 #endif
422 // JavaScript Callbacks
424 #define SIMPLE_INSPECTOR_CALLBACK(jsFunction, inspectorControllerMethod) \
425 static JSValueRef jsFunction(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*) \
427 if (InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject))) \
428 controller->inspectorControllerMethod(); \
429 return JSValueMakeUndefined(ctx); \
432 SIMPLE_INSPECTOR_CALLBACK(hideDOMNodeHighlight, hideHighlight);
433 SIMPLE_INSPECTOR_CALLBACK(loaded, scriptObjectReady);
434 SIMPLE_INSPECTOR_CALLBACK(unloading, close);
435 SIMPLE_INSPECTOR_CALLBACK(attach, attachWindow);
436 SIMPLE_INSPECTOR_CALLBACK(detach, detachWindow);
437 #if ENABLE(JAVASCRIPT_DEBUGGER)
438 SIMPLE_INSPECTOR_CALLBACK(enableDebugger, enableDebugger);
439 SIMPLE_INSPECTOR_CALLBACK(disableDebugger, disableDebugger);
440 SIMPLE_INSPECTOR_CALLBACK(pauseInDebugger, pauseInDebugger);
441 SIMPLE_INSPECTOR_CALLBACK(resumeDebugger, resumeDebugger);
442 SIMPLE_INSPECTOR_CALLBACK(stepOverStatementInDebugger, stepOverStatementInDebugger);
443 SIMPLE_INSPECTOR_CALLBACK(stepIntoStatementInDebugger, stepIntoStatementInDebugger);
444 SIMPLE_INSPECTOR_CALLBACK(stepOutOfFunctionInDebugger, stepOutOfFunctionInDebugger);
445 #endif
446 SIMPLE_INSPECTOR_CALLBACK(closeWindow, closeWindow);
447 SIMPLE_INSPECTOR_CALLBACK(clearMessages, clearConsoleMessages);
448 SIMPLE_INSPECTOR_CALLBACK(startProfiling, startUserInitiatedProfilingSoon);
449 SIMPLE_INSPECTOR_CALLBACK(stopProfiling, stopUserInitiatedProfiling);
450 SIMPLE_INSPECTOR_CALLBACK(enableProfiler, enableProfiler);
451 SIMPLE_INSPECTOR_CALLBACK(disableProfiler, disableProfiler);
452 SIMPLE_INSPECTOR_CALLBACK(toggleNodeSearch, toggleSearchForNodeInPage);
454 #define BOOL_INSPECTOR_CALLBACK(jsFunction, inspectorControllerMethod) \
455 static JSValueRef jsFunction(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*) \
457 if (InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject))) \
458 return JSValueMakeBoolean(ctx, controller->inspectorControllerMethod()); \
459 return JSValueMakeUndefined(ctx); \
462 #if ENABLE(JAVASCRIPT_DEBUGGER)
463 BOOL_INSPECTOR_CALLBACK(debuggerEnabled, debuggerEnabled);
464 BOOL_INSPECTOR_CALLBACK(pauseOnExceptions, pauseOnExceptions);
465 #endif
466 BOOL_INSPECTOR_CALLBACK(profilerEnabled, profilerEnabled);
467 BOOL_INSPECTOR_CALLBACK(isWindowVisible, windowVisible);
468 BOOL_INSPECTOR_CALLBACK(searchingForNode, searchingForNodeInPage);
470 static bool addSourceToFrame(const String& mimeType, const String& source, Node* frameNode)
472 ASSERT_ARG(frameNode, frameNode);
474 if (!frameNode)
475 return false;
477 if (!frameNode->attached()) {
478 ASSERT_NOT_REACHED();
479 return false;
482 ASSERT(frameNode->isElementNode());
483 if (!frameNode->isElementNode())
484 return false;
486 Element* element = static_cast<Element*>(frameNode);
487 ASSERT(element->isFrameOwnerElement());
488 if (!element->isFrameOwnerElement())
489 return false;
491 HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(element);
492 ASSERT(frameOwner->contentFrame());
493 if (!frameOwner->contentFrame())
494 return false;
496 FrameLoader* loader = frameOwner->contentFrame()->loader();
498 loader->setResponseMIMEType(mimeType);
499 loader->begin();
500 loader->write(source);
501 loader->end();
503 return true;
506 static JSValueRef addResourceSourceToFrame(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
508 JSValueRef undefined = JSValueMakeUndefined(ctx);
510 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
511 if (argumentCount < 2 || !controller)
512 return undefined;
514 JSValueRef identifierValue = arguments[0];
515 if (!JSValueIsNumber(ctx, identifierValue))
516 return undefined;
518 long long identifier = static_cast<long long>(JSValueToNumber(ctx, identifierValue, exception));
519 if (exception && *exception)
520 return undefined;
522 RefPtr<InspectorResource> resource = controller->resources().get(identifier);
523 ASSERT(resource);
524 if (!resource)
525 return undefined;
527 String sourceString = resource->sourceString();
528 if (sourceString.isEmpty())
529 return undefined;
531 bool successfullyAddedSource = addSourceToFrame(resource->mimeType, sourceString, toNode(toJS(arguments[1])));
532 return JSValueMakeBoolean(ctx, successfullyAddedSource);
535 static JSValueRef addSourceToFrame(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
537 JSValueRef undefined = JSValueMakeUndefined(ctx);
539 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
540 if (argumentCount < 3 || !controller)
541 return undefined;
543 JSValueRef mimeTypeValue = arguments[0];
544 if (!JSValueIsString(ctx, mimeTypeValue))
545 return undefined;
547 JSValueRef sourceValue = arguments[1];
548 if (!JSValueIsString(ctx, sourceValue))
549 return undefined;
551 String mimeType = toString(ctx, mimeTypeValue, exception);
552 if (mimeType.isEmpty())
553 return undefined;
555 String source = toString(ctx, sourceValue, exception);
556 if (source.isEmpty())
557 return undefined;
559 bool successfullyAddedSource = addSourceToFrame(mimeType, source, toNode(toJS(arguments[2])));
560 return JSValueMakeBoolean(ctx, successfullyAddedSource);
563 static JSValueRef getResourceDocumentNode(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
565 JSValueRef undefined = JSValueMakeUndefined(ctx);
567 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
568 if (!argumentCount || argumentCount > 1 || !controller)
569 return undefined;
571 JSValueRef identifierValue = arguments[0];
572 if (!JSValueIsNumber(ctx, identifierValue))
573 return undefined;
575 long long identifier = static_cast<long long>(JSValueToNumber(ctx, identifierValue, exception));
576 if (exception && *exception)
577 return undefined;
579 RefPtr<InspectorResource> resource = controller->resources().get(identifier);
580 ASSERT(resource);
581 if (!resource)
582 return undefined;
584 Frame* frame = resource->frame.get();
586 Document* document = frame->document();
587 if (!document)
588 return undefined;
590 if (document->isPluginDocument() || document->isImageDocument() || document->isMediaDocument())
591 return undefined;
593 ExecState* exec = toJSDOMWindowShell(resource->frame.get())->window()->globalExec();
595 JSC::JSLock lock(false);
596 JSValueRef documentValue = toRef(JSInspectedObjectWrapper::wrap(exec, toJS(exec, document)));
597 return documentValue;
600 static JSValueRef highlightDOMNode(JSContextRef context, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
602 JSValueRef undefined = JSValueMakeUndefined(context);
604 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
605 if (argumentCount < 1 || !controller)
606 return undefined;
608 JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(toJS(arguments[0]));
609 if (!wrapper)
610 return undefined;
611 Node* node = toNode(wrapper->unwrappedObject());
612 if (!node)
613 return undefined;
615 controller->highlight(node);
617 return undefined;
620 static JSValueRef search(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
622 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
623 if (!controller)
624 return JSValueMakeUndefined(ctx);
626 if (argumentCount < 2 || !JSValueIsString(ctx, arguments[1]))
627 return JSValueMakeUndefined(ctx);
629 Node* node = toNode(toJS(arguments[0]));
630 if (!node)
631 return JSValueMakeUndefined(ctx);
633 String target = toString(ctx, arguments[1], exception);
635 JSObjectRef global = JSContextGetGlobalObject(ctx);
637 JSValueRef arrayProperty = JSObjectGetProperty(ctx, global, jsStringRef("Array").get(), exception);
638 if (exception && *exception)
639 return JSValueMakeUndefined(ctx);
641 JSObjectRef arrayConstructor = JSValueToObject(ctx, arrayProperty, exception);
642 if (exception && *exception)
643 return JSValueMakeUndefined(ctx);
645 JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, exception);
646 if (exception && *exception)
647 return JSValueMakeUndefined(ctx);
649 JSValueRef pushProperty = JSObjectGetProperty(ctx, result, jsStringRef("push").get(), exception);
650 if (exception && *exception)
651 return JSValueMakeUndefined(ctx);
653 JSObjectRef pushFunction = JSValueToObject(ctx, pushProperty, exception);
654 if (exception && *exception)
655 return JSValueMakeUndefined(ctx);
657 RefPtr<Range> searchRange(rangeOfContents(node));
659 ExceptionCode ec = 0;
660 do {
661 RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, false));
662 if (resultRange->collapsed(ec))
663 break;
665 // A non-collapsed result range can in some funky whitespace cases still not
666 // advance the range's start position (4509328). Break to avoid infinite loop.
667 VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
668 if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
669 break;
671 JSC::JSLock lock(false);
672 JSValueRef arg0 = toRef(toJS(toJS(ctx), resultRange.get()));
673 JSObjectCallAsFunction(ctx, pushFunction, result, 1, &arg0, exception);
674 if (exception && *exception)
675 return JSValueMakeUndefined(ctx);
677 setStart(searchRange.get(), newStart);
678 } while (true);
680 return result;
683 #if ENABLE(DATABASE)
684 static JSValueRef databaseTableNames(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
686 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
687 if (!controller)
688 return JSValueMakeUndefined(ctx);
690 if (argumentCount < 1)
691 return JSValueMakeUndefined(ctx);
693 JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(toJS(arguments[0]));
694 if (!wrapper)
695 return JSValueMakeUndefined(ctx);
697 Database* database = toDatabase(wrapper->unwrappedObject());
698 if (!database)
699 return JSValueMakeUndefined(ctx);
701 JSObjectRef global = JSContextGetGlobalObject(ctx);
703 JSValueRef arrayProperty = JSObjectGetProperty(ctx, global, jsStringRef("Array").get(), exception);
704 if (exception && *exception)
705 return JSValueMakeUndefined(ctx);
707 JSObjectRef arrayConstructor = JSValueToObject(ctx, arrayProperty, exception);
708 if (exception && *exception)
709 return JSValueMakeUndefined(ctx);
711 JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, exception);
712 if (exception && *exception)
713 return JSValueMakeUndefined(ctx);
715 JSValueRef pushProperty = JSObjectGetProperty(ctx, result, jsStringRef("push").get(), exception);
716 if (exception && *exception)
717 return JSValueMakeUndefined(ctx);
719 JSObjectRef pushFunction = JSValueToObject(ctx, pushProperty, exception);
720 if (exception && *exception)
721 return JSValueMakeUndefined(ctx);
723 Vector<String> tableNames = database->tableNames();
724 unsigned length = tableNames.size();
725 for (unsigned i = 0; i < length; ++i) {
726 String tableName = tableNames[i];
727 JSValueRef tableNameValue = JSValueMakeString(ctx, jsStringRef(tableName).get());
729 JSValueRef pushArguments[] = { tableNameValue };
730 JSObjectCallAsFunction(ctx, pushFunction, result, 1, pushArguments, exception);
731 if (exception && *exception)
732 return JSValueMakeUndefined(ctx);
735 return result;
737 #endif
739 static JSValueRef inspectedWindow(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
741 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
742 if (!controller)
743 return JSValueMakeUndefined(ctx);
745 JSDOMWindow* inspectedWindow = toJSDOMWindow(controller->inspectedPage()->mainFrame());
746 JSLock lock(false);
747 return toRef(JSInspectedObjectWrapper::wrap(inspectedWindow->globalExec(), inspectedWindow));
750 static JSValueRef setting(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef arguments[], JSValueRef* exception)
752 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
753 if (!controller)
754 return JSValueMakeUndefined(ctx);
756 JSValueRef keyValue = arguments[0];
757 if (!JSValueIsString(ctx, keyValue))
758 return JSValueMakeUndefined(ctx);
760 const InspectorController::Setting& setting = controller->setting(toString(ctx, keyValue, exception));
762 switch (setting.type()) {
763 default:
764 case InspectorController::Setting::NoType:
765 return JSValueMakeUndefined(ctx);
766 case InspectorController::Setting::StringType:
767 return JSValueMakeString(ctx, jsStringRef(setting.string()).get());
768 case InspectorController::Setting::DoubleType:
769 return JSValueMakeNumber(ctx, setting.doubleValue());
770 case InspectorController::Setting::IntegerType:
771 return JSValueMakeNumber(ctx, setting.integerValue());
772 case InspectorController::Setting::BooleanType:
773 return JSValueMakeBoolean(ctx, setting.booleanValue());
774 case InspectorController::Setting::StringVectorType: {
775 Vector<JSValueRef> stringValues;
776 const Vector<String>& strings = setting.stringVector();
777 const unsigned length = strings.size();
778 for (unsigned i = 0; i < length; ++i)
779 stringValues.append(JSValueMakeString(ctx, jsStringRef(strings[i]).get()));
781 JSObjectRef stringsArray = JSObjectMakeArray(ctx, stringValues.size(), stringValues.data(), exception);
782 if (exception && *exception)
783 return JSValueMakeUndefined(ctx);
784 return stringsArray;
789 static JSValueRef setSetting(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef arguments[], JSValueRef* exception)
791 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
792 if (!controller)
793 return JSValueMakeUndefined(ctx);
795 JSValueRef keyValue = arguments[0];
796 if (!JSValueIsString(ctx, keyValue))
797 return JSValueMakeUndefined(ctx);
799 InspectorController::Setting setting;
801 JSValueRef value = arguments[1];
802 switch (JSValueGetType(ctx, value)) {
803 default:
804 case kJSTypeUndefined:
805 case kJSTypeNull:
806 // Do nothing. The setting is already NoType.
807 ASSERT(setting.type() == InspectorController::Setting::NoType);
808 break;
809 case kJSTypeString:
810 setting.set(toString(ctx, value, exception));
811 break;
812 case kJSTypeNumber:
813 setting.set(JSValueToNumber(ctx, value, exception));
814 break;
815 case kJSTypeBoolean:
816 setting.set(JSValueToBoolean(ctx, value));
817 break;
818 case kJSTypeObject: {
819 JSObjectRef object = JSValueToObject(ctx, value, 0);
820 JSValueRef lengthValue = JSObjectGetProperty(ctx, object, jsStringRef("length").get(), exception);
821 if (exception && *exception)
822 return JSValueMakeUndefined(ctx);
824 Vector<String> strings;
825 const unsigned length = static_cast<unsigned>(JSValueToNumber(ctx, lengthValue, 0));
826 for (unsigned i = 0; i < length; ++i) {
827 JSValueRef itemValue = JSObjectGetPropertyAtIndex(ctx, object, i, exception);
828 if (exception && *exception)
829 return JSValueMakeUndefined(ctx);
830 strings.append(toString(ctx, itemValue, exception));
831 if (exception && *exception)
832 return JSValueMakeUndefined(ctx);
835 setting.set(strings);
836 break;
840 if (exception && *exception)
841 return JSValueMakeUndefined(ctx);
843 controller->setSetting(toString(ctx, keyValue, exception), setting);
845 return JSValueMakeUndefined(ctx);
848 static JSValueRef localizedStrings(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
850 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
851 if (!controller)
852 return JSValueMakeUndefined(ctx);
854 String url = controller->localizedStringsURL();
855 if (url.isNull())
856 return JSValueMakeNull(ctx);
858 return JSValueMakeString(ctx, jsStringRef(url).get());
861 static JSValueRef platform(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
863 #if PLATFORM(MAC)
864 #ifdef BUILDING_ON_TIGER
865 static const String platform = "mac-tiger";
866 #else
867 static const String platform = "mac-leopard";
868 #endif
869 #elif PLATFORM(WIN_OS)
870 static const String platform = "windows";
871 #elif PLATFORM(QT)
872 static const String platform = "qt";
873 #elif PLATFORM(GTK)
874 static const String platform = "gtk";
875 #elif PLATFORM(WX)
876 static const String platform = "wx";
877 #else
878 static const String platform = "unknown";
879 #endif
881 JSValueRef platformValue = JSValueMakeString(ctx, jsStringRef(platform).get());
883 return platformValue;
886 static JSValueRef moveByUnrestricted(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
888 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
889 if (!controller)
890 return JSValueMakeUndefined(ctx);
892 if (argumentCount < 2)
893 return JSValueMakeUndefined(ctx);
895 double x = JSValueToNumber(ctx, arguments[0], exception);
896 if (exception && *exception)
897 return JSValueMakeUndefined(ctx);
899 double y = JSValueToNumber(ctx, arguments[1], exception);
900 if (exception && *exception)
901 return JSValueMakeUndefined(ctx);
903 controller->moveWindowBy(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y));
905 return JSValueMakeUndefined(ctx);
908 static JSValueRef setAttachedWindowHeight(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
910 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
911 if (!controller)
912 return JSValueMakeUndefined(ctx);
914 if (argumentCount < 1)
915 return JSValueMakeUndefined(ctx);
917 unsigned height = static_cast<unsigned>(JSValueToNumber(ctx, arguments[0], exception));
918 if (exception && *exception)
919 return JSValueMakeUndefined(ctx);
921 controller->setAttachedWindowHeight(height);
923 return JSValueMakeUndefined(ctx);
926 static JSValueRef wrapCallback(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
928 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
929 if (!controller)
930 return JSValueMakeUndefined(ctx);
932 if (argumentCount < 1)
933 return JSValueMakeUndefined(ctx);
935 JSLock lock(false);
936 return toRef(JSInspectorCallbackWrapper::wrap(toJS(ctx), toJS(arguments[0])));
939 #if ENABLE(JAVASCRIPT_DEBUGGER)
940 static JSValueRef currentCallFrame(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* /*exception*/)
942 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
943 if (!controller)
944 return JSValueMakeUndefined(ctx);
946 JavaScriptCallFrame* callFrame = controller->currentCallFrame();
947 if (!callFrame || !callFrame->isValid())
948 return JSValueMakeNull(ctx);
950 ExecState* globalExec = callFrame->scopeChain()->globalObject()->globalExec();
952 JSLock lock(false);
953 return toRef(JSInspectedObjectWrapper::wrap(globalExec, toJS(toJS(ctx), callFrame)));
956 static JSValueRef setPauseOnExceptions(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
958 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
959 if (!controller)
960 return JSValueMakeUndefined(ctx);
962 if (argumentCount < 1)
963 return JSValueMakeUndefined(ctx);
965 controller->setPauseOnExceptions(JSValueToBoolean(ctx, arguments[0]));
967 return JSValueMakeUndefined(ctx);
970 static JSValueRef addBreakpoint(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
972 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
973 if (!controller)
974 return JSValueMakeUndefined(ctx);
976 if (argumentCount < 2)
977 return JSValueMakeUndefined(ctx);
979 double sourceID = JSValueToNumber(ctx, arguments[0], exception);
980 if (exception && *exception)
981 return JSValueMakeUndefined(ctx);
983 double lineNumber = JSValueToNumber(ctx, arguments[1], exception);
984 if (exception && *exception)
985 return JSValueMakeUndefined(ctx);
987 controller->addBreakpoint(static_cast<int>(sourceID), static_cast<unsigned>(lineNumber));
989 return JSValueMakeUndefined(ctx);
992 static JSValueRef removeBreakpoint(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
994 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
995 if (!controller)
996 return JSValueMakeUndefined(ctx);
998 if (argumentCount < 2)
999 return JSValueMakeUndefined(ctx);
1001 double sourceID = JSValueToNumber(ctx, arguments[0], exception);
1002 if (exception && *exception)
1003 return JSValueMakeUndefined(ctx);
1005 double lineNumber = JSValueToNumber(ctx, arguments[1], exception);
1006 if (exception && *exception)
1007 return JSValueMakeUndefined(ctx);
1009 controller->removeBreakpoint(static_cast<int>(sourceID), static_cast<unsigned>(lineNumber));
1011 return JSValueMakeUndefined(ctx);
1013 #endif
1015 static JSValueRef profiles(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* exception)
1017 InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
1018 if (!controller)
1019 return JSValueMakeUndefined(ctx);
1021 JSLock lock(false);
1023 const Vector<RefPtr<Profile> >& profiles = controller->profiles();
1025 JSObjectRef global = JSContextGetGlobalObject(ctx);
1027 JSValueRef arrayProperty = JSObjectGetProperty(ctx, global, jsStringRef("Array").get(), exception);
1028 if (exception && *exception)
1029 return JSValueMakeUndefined(ctx);
1031 JSObjectRef arrayConstructor = JSValueToObject(ctx, arrayProperty, exception);
1032 if (exception && *exception)
1033 return JSValueMakeUndefined(ctx);
1035 JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, exception);
1036 if (exception && *exception)
1037 return JSValueMakeUndefined(ctx);
1039 JSValueRef pushProperty = JSObjectGetProperty(ctx, result, jsStringRef("push").get(), exception);
1040 if (exception && *exception)
1041 return JSValueMakeUndefined(ctx);
1043 JSObjectRef pushFunction = JSValueToObject(ctx, pushProperty, exception);
1044 if (exception && *exception)
1045 return JSValueMakeUndefined(ctx);
1047 for (size_t i = 0; i < profiles.size(); ++i) {
1048 JSValueRef arg0 = toRef(toJS(toJS(ctx), profiles[i].get()));
1049 JSObjectCallAsFunction(ctx, pushFunction, result, 1, &arg0, exception);
1050 if (exception && *exception)
1051 return JSValueMakeUndefined(ctx);
1054 return result;
1057 // InspectorController Class
1059 static unsigned s_inspectorControllerCount;
1060 static HashMap<String, InspectorController::Setting*>* s_settingCache;
1062 InspectorController::InspectorController(Page* page, InspectorClient* client)
1063 : m_inspectedPage(page)
1064 , m_client(client)
1065 , m_page(0)
1066 , m_scriptObject(0)
1067 , m_controllerScriptObject(0)
1068 , m_scriptContext(0)
1069 , m_windowVisible(false)
1070 #if ENABLE(JAVASCRIPT_DEBUGGER)
1071 , m_debuggerEnabled(false)
1072 , m_attachDebuggerWhenShown(false)
1073 #endif
1074 , m_profilerEnabled(false)
1075 , m_recordingUserInitiatedProfile(false)
1076 , m_showAfterVisible(ElementsPanel)
1077 , m_nextIdentifier(-2)
1078 , m_groupLevel(0)
1079 , m_searchingForNode(false)
1080 , m_currentUserInitiatedProfileNumber(-1)
1081 , m_nextUserInitiatedProfileNumber(1)
1082 , m_previousMessage(0)
1083 , m_startProfiling(this, &InspectorController::startUserInitiatedProfiling)
1085 ASSERT_ARG(page, page);
1086 ASSERT_ARG(client, client);
1087 ++s_inspectorControllerCount;
1090 InspectorController::~InspectorController()
1092 m_client->inspectorDestroyed();
1094 if (m_scriptContext) {
1095 JSValueRef exception = 0;
1097 JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
1098 JSValueRef controllerProperty = JSObjectGetProperty(m_scriptContext, global, jsStringRef("InspectorController").get(), &exception);
1099 if (!HANDLE_EXCEPTION(m_scriptContext, exception)) {
1100 if (JSObjectRef controller = JSValueToObject(m_scriptContext, controllerProperty, &exception)) {
1101 if (!HANDLE_EXCEPTION(m_scriptContext, exception))
1102 JSObjectSetPrivate(controller, 0);
1107 if (m_page)
1108 m_page->setParentInspectorController(0);
1110 // m_inspectedPage should have been cleared in inspectedPageDestroyed().
1111 ASSERT(!m_inspectedPage);
1113 deleteAllValues(m_frameResources);
1114 deleteAllValues(m_consoleMessages);
1116 ASSERT(s_inspectorControllerCount);
1117 --s_inspectorControllerCount;
1119 if (!s_inspectorControllerCount && s_settingCache) {
1120 deleteAllValues(*s_settingCache);
1121 delete s_settingCache;
1122 s_settingCache = 0;
1126 void InspectorController::inspectedPageDestroyed()
1128 close();
1130 ASSERT(m_inspectedPage);
1131 m_inspectedPage = 0;
1134 bool InspectorController::enabled() const
1136 if (!m_inspectedPage)
1137 return false;
1138 return m_inspectedPage->settings()->developerExtrasEnabled();
1141 const InspectorController::Setting& InspectorController::setting(const String& key) const
1143 if (!s_settingCache)
1144 s_settingCache = new HashMap<String, Setting*>;
1146 if (Setting* cachedSetting = s_settingCache->get(key))
1147 return *cachedSetting;
1149 Setting* newSetting = new Setting;
1150 s_settingCache->set(key, newSetting);
1152 m_client->populateSetting(key, *newSetting);
1154 return *newSetting;
1157 void InspectorController::setSetting(const String& key, const Setting& setting)
1159 if (setting.type() == Setting::NoType) {
1160 if (s_settingCache) {
1161 Setting* cachedSetting = s_settingCache->get(key);
1162 if (cachedSetting) {
1163 s_settingCache->remove(key);
1164 delete cachedSetting;
1168 m_client->removeSetting(key);
1169 return;
1172 if (!s_settingCache)
1173 s_settingCache = new HashMap<String, Setting*>;
1175 if (Setting* cachedSetting = s_settingCache->get(key))
1176 *cachedSetting = setting;
1177 else
1178 s_settingCache->set(key, new Setting(setting));
1180 m_client->storeSetting(key, setting);
1183 String InspectorController::localizedStringsURL()
1185 if (!enabled())
1186 return String();
1187 return m_client->localizedStringsURL();
1190 // Trying to inspect something in a frame with JavaScript disabled would later lead to
1191 // crashes trying to create JavaScript wrappers. Some day we could fix this issue, but
1192 // for now prevent crashes here by never targeting a node in such a frame.
1193 static bool canPassNodeToJavaScript(Node* node)
1195 if (!node)
1196 return false;
1197 Frame* frame = node->document()->frame();
1198 return frame && frame->script()->isEnabled();
1201 void InspectorController::inspect(Node* node)
1203 if (!canPassNodeToJavaScript(node) || !enabled())
1204 return;
1206 show();
1208 if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
1209 node = node->parentNode();
1210 m_nodeToFocus = node;
1212 if (!m_scriptObject) {
1213 m_showAfterVisible = ElementsPanel;
1214 return;
1217 if (windowVisible())
1218 focusNode();
1221 void InspectorController::focusNode()
1223 if (!enabled())
1224 return;
1226 ASSERT(m_scriptContext);
1227 ASSERT(m_scriptObject);
1228 ASSERT(m_nodeToFocus);
1230 Frame* frame = m_nodeToFocus->document()->frame();
1231 if (!frame)
1232 return;
1234 ExecState* exec = toJSDOMWindow(frame)->globalExec();
1236 JSValueRef arg0;
1239 JSC::JSLock lock(false);
1240 arg0 = toRef(JSInspectedObjectWrapper::wrap(exec, toJS(exec, m_nodeToFocus.get())));
1243 m_nodeToFocus = 0;
1245 JSValueRef exception = 0;
1246 callFunction(m_scriptContext, m_scriptObject, "updateFocusedNode", 1, &arg0, exception);
1249 void InspectorController::highlight(Node* node)
1251 if (!enabled())
1252 return;
1253 ASSERT_ARG(node, node);
1254 m_highlightedNode = node;
1255 m_client->highlight(node);
1258 void InspectorController::hideHighlight()
1260 if (!enabled())
1261 return;
1262 m_client->hideHighlight();
1265 bool InspectorController::windowVisible()
1267 return m_windowVisible;
1270 void InspectorController::setWindowVisible(bool visible, bool attached)
1272 if (visible == m_windowVisible)
1273 return;
1275 m_windowVisible = visible;
1277 if (!m_scriptContext || !m_scriptObject)
1278 return;
1280 if (m_windowVisible) {
1281 setAttachedWindow(attached);
1282 populateScriptObjects();
1283 if (m_nodeToFocus)
1284 focusNode();
1285 #if ENABLE(JAVASCRIPT_DEBUGGER)
1286 if (m_attachDebuggerWhenShown)
1287 enableDebugger();
1288 #endif
1289 if (m_showAfterVisible != CurrentPanel)
1290 showPanel(m_showAfterVisible);
1291 } else {
1292 #if ENABLE(JAVASCRIPT_DEBUGGER)
1293 disableDebugger();
1294 #endif
1295 resetScriptObjects();
1298 m_showAfterVisible = CurrentPanel;
1301 void InspectorController::addMessageToConsole(MessageSource source, MessageLevel level, ExecState* exec, const ArgList& arguments, unsigned lineNumber, const String& sourceURL)
1303 if (!enabled())
1304 return;
1306 addConsoleMessage(exec, new ConsoleMessage(source, level, exec, arguments, lineNumber, sourceURL, m_groupLevel));
1309 void InspectorController::addMessageToConsole(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceID)
1311 if (!enabled())
1312 return;
1314 addConsoleMessage(0, new ConsoleMessage(source, level, message, lineNumber, sourceID, m_groupLevel));
1317 void InspectorController::addConsoleMessage(ExecState* exec, ConsoleMessage* consoleMessage)
1319 ASSERT(enabled());
1320 ASSERT_ARG(consoleMessage, consoleMessage);
1322 if (m_previousMessage && m_previousMessage->isEqual(exec, consoleMessage)) {
1323 ++m_previousMessage->repeatCount;
1324 delete consoleMessage;
1325 } else {
1326 m_previousMessage = consoleMessage;
1327 m_consoleMessages.append(consoleMessage);
1330 if (windowVisible())
1331 addScriptConsoleMessage(m_previousMessage);
1334 void InspectorController::clearConsoleMessages()
1336 deleteAllValues(m_consoleMessages);
1337 m_consoleMessages.clear();
1338 m_previousMessage = 0;
1339 m_groupLevel = 0;
1342 void InspectorController::toggleRecordButton(bool isProfiling)
1344 if (!m_scriptContext)
1345 return;
1347 JSValueRef exception = 0;
1348 JSValueRef isProvingValue = JSValueMakeBoolean(m_scriptContext, isProfiling);
1349 callFunction(m_scriptContext, m_scriptObject, "setRecordingProfile", 1, &isProvingValue, exception);
1352 void InspectorController::startGroup(MessageSource source, ExecState* exec, const ArgList& arguments, unsigned lineNumber, const String& sourceURL)
1354 ++m_groupLevel;
1356 addConsoleMessage(exec, new ConsoleMessage(source, StartGroupMessageLevel, exec, arguments, lineNumber, sourceURL, m_groupLevel));
1359 void InspectorController::endGroup(MessageSource source, unsigned lineNumber, const String& sourceURL)
1361 if (m_groupLevel == 0)
1362 return;
1364 --m_groupLevel;
1366 addConsoleMessage(0, new ConsoleMessage(source, EndGroupMessageLevel, String(), lineNumber, sourceURL, m_groupLevel));
1369 void InspectorController::addProfile(PassRefPtr<Profile> prpProfile, unsigned lineNumber, const UString& sourceURL)
1371 if (!enabled())
1372 return;
1374 RefPtr<Profile> profile = prpProfile;
1375 m_profiles.append(profile);
1377 if (windowVisible())
1378 addScriptProfile(profile.get());
1380 addProfileMessageToConsole(profile, lineNumber, sourceURL);
1383 void InspectorController::addProfileMessageToConsole(PassRefPtr<Profile> prpProfile, unsigned lineNumber, const UString& sourceURL)
1385 RefPtr<Profile> profile = prpProfile;
1387 UString message = "Profile \"webkit-profile://";
1388 message += encodeWithURLEscapeSequences(profile->title());
1389 message += "/";
1390 message += UString::from(profile->uid());
1391 message += "\" finished.";
1392 addMessageToConsole(JSMessageSource, LogMessageLevel, message, lineNumber, sourceURL);
1395 void InspectorController::attachWindow()
1397 if (!enabled())
1398 return;
1399 m_client->attachWindow();
1402 void InspectorController::detachWindow()
1404 if (!enabled())
1405 return;
1406 m_client->detachWindow();
1409 void InspectorController::setAttachedWindow(bool attached)
1411 if (!enabled() || !m_scriptContext || !m_scriptObject)
1412 return;
1414 JSValueRef attachedValue = JSValueMakeBoolean(m_scriptContext, attached);
1416 JSValueRef exception = 0;
1417 callFunction(m_scriptContext, m_scriptObject, "setAttachedWindow", 1, &attachedValue, exception);
1420 void InspectorController::setAttachedWindowHeight(unsigned height)
1422 if (!enabled())
1423 return;
1424 m_client->setAttachedWindowHeight(height);
1427 void InspectorController::toggleSearchForNodeInPage()
1429 if (!enabled())
1430 return;
1432 m_searchingForNode = !m_searchingForNode;
1433 if (!m_searchingForNode)
1434 hideHighlight();
1437 void InspectorController::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags)
1439 if (!enabled() || !m_searchingForNode)
1440 return;
1442 Node* node = result.innerNode();
1443 if (node)
1444 highlight(node);
1447 void InspectorController::handleMousePressOnNode(Node* node)
1449 if (!enabled())
1450 return;
1452 ASSERT(m_searchingForNode);
1453 ASSERT(node);
1454 if (!node)
1455 return;
1457 // inspect() will implicitly call ElementsPanel's focusedNodeChanged() and the hover feedback will be stopped there.
1458 inspect(node);
1461 void InspectorController::inspectedWindowScriptObjectCleared(Frame* frame)
1463 if (!enabled() || !m_scriptContext || !m_scriptObject)
1464 return;
1466 JSDOMWindow* win = toJSDOMWindow(frame);
1467 ExecState* exec = win->globalExec();
1469 JSValueRef arg0;
1472 JSC::JSLock lock(false);
1473 arg0 = toRef(JSInspectedObjectWrapper::wrap(exec, win));
1476 JSValueRef exception = 0;
1477 callFunction(m_scriptContext, m_scriptObject, "inspectedWindowCleared", 1, &arg0, exception);
1480 void InspectorController::windowScriptObjectAvailable()
1482 if (!m_page || !enabled())
1483 return;
1485 m_scriptContext = toRef(m_page->mainFrame()->script()->globalObject()->globalExec());
1487 JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
1488 ASSERT(global);
1490 static JSStaticFunction staticFunctions[] = {
1491 // SIMPLE_INSPECTOR_CALLBACK
1492 { "hideDOMNodeHighlight", WebCore::hideDOMNodeHighlight, kJSPropertyAttributeNone },
1493 { "loaded", WebCore::loaded, kJSPropertyAttributeNone },
1494 { "windowUnloading", WebCore::unloading, kJSPropertyAttributeNone },
1495 { "attach", WebCore::attach, kJSPropertyAttributeNone },
1496 { "detach", WebCore::detach, kJSPropertyAttributeNone },
1497 #if ENABLE(JAVASCRIPT_DEBUGGER)
1498 { "enableDebugger", WebCore::enableDebugger, kJSPropertyAttributeNone },
1499 { "disableDebugger", WebCore::disableDebugger, kJSPropertyAttributeNone },
1500 { "pauseInDebugger", WebCore::pauseInDebugger, kJSPropertyAttributeNone },
1501 { "resumeDebugger", WebCore::resumeDebugger, kJSPropertyAttributeNone },
1502 { "stepOverStatementInDebugger", WebCore::stepOverStatementInDebugger, kJSPropertyAttributeNone },
1503 { "stepIntoStatementInDebugger", WebCore::stepIntoStatementInDebugger, kJSPropertyAttributeNone },
1504 { "stepOutOfFunctionInDebugger", WebCore::stepOutOfFunctionInDebugger, kJSPropertyAttributeNone },
1505 #endif
1506 { "closeWindow", WebCore::closeWindow, kJSPropertyAttributeNone },
1507 { "clearMessages", WebCore::clearMessages, kJSPropertyAttributeNone },
1508 { "startProfiling", WebCore::startProfiling, kJSPropertyAttributeNone },
1509 { "stopProfiling", WebCore::stopProfiling, kJSPropertyAttributeNone },
1510 { "enableProfiler", WebCore::enableProfiler, kJSPropertyAttributeNone },
1511 { "disableProfiler", WebCore::disableProfiler, kJSPropertyAttributeNone },
1512 { "toggleNodeSearch", WebCore::toggleNodeSearch, kJSPropertyAttributeNone },
1514 // BOOL_INSPECTOR_CALLBACK
1515 #if ENABLE(JAVASCRIPT_DEBUGGER)
1516 { "debuggerEnabled", WebCore::debuggerEnabled, kJSPropertyAttributeNone },
1517 { "pauseOnExceptions", WebCore::pauseOnExceptions, kJSPropertyAttributeNone },
1518 #endif
1519 { "profilerEnabled", WebCore::profilerEnabled, kJSPropertyAttributeNone },
1520 { "isWindowVisible", WebCore::isWindowVisible, kJSPropertyAttributeNone },
1521 { "searchingForNode", WebCore::searchingForNode, kJSPropertyAttributeNone },
1523 // Custom callbacks
1524 { "addResourceSourceToFrame", WebCore::addResourceSourceToFrame, kJSPropertyAttributeNone },
1525 { "addSourceToFrame", WebCore::addSourceToFrame, kJSPropertyAttributeNone },
1526 { "getResourceDocumentNode", WebCore::getResourceDocumentNode, kJSPropertyAttributeNone },
1527 { "highlightDOMNode", WebCore::highlightDOMNode, kJSPropertyAttributeNone },
1528 { "search", WebCore::search, kJSPropertyAttributeNone },
1529 #if ENABLE(DATABASE)
1530 { "databaseTableNames", WebCore::databaseTableNames, kJSPropertyAttributeNone },
1531 #endif
1532 { "setting", WebCore::setting, kJSPropertyAttributeNone },
1533 { "setSetting", WebCore::setSetting, kJSPropertyAttributeNone },
1534 { "inspectedWindow", WebCore::inspectedWindow, kJSPropertyAttributeNone },
1535 { "localizedStringsURL", WebCore::localizedStrings, kJSPropertyAttributeNone },
1536 { "platform", WebCore::platform, kJSPropertyAttributeNone },
1537 { "moveByUnrestricted", WebCore::moveByUnrestricted, kJSPropertyAttributeNone },
1538 { "setAttachedWindowHeight", WebCore::setAttachedWindowHeight, kJSPropertyAttributeNone },
1539 { "wrapCallback", WebCore::wrapCallback, kJSPropertyAttributeNone },
1540 #if ENABLE(JAVASCRIPT_DEBUGGER)
1541 { "currentCallFrame", WebCore::currentCallFrame, kJSPropertyAttributeNone },
1542 { "setPauseOnExceptions", WebCore::setPauseOnExceptions, kJSPropertyAttributeNone },
1543 { "addBreakpoint", WebCore::addBreakpoint, kJSPropertyAttributeNone },
1544 { "removeBreakpoint", WebCore::removeBreakpoint, kJSPropertyAttributeNone },
1545 #endif
1546 { "profiles", WebCore::profiles, kJSPropertyAttributeNone },
1547 { 0, 0, 0 }
1550 JSClassDefinition inspectorControllerDefinition = {
1551 0, kJSClassAttributeNone, "InspectorController", 0, 0, staticFunctions,
1552 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1555 JSClassRef controllerClass = JSClassCreate(&inspectorControllerDefinition);
1556 ASSERT(controllerClass);
1558 m_controllerScriptObject = JSObjectMake(m_scriptContext, controllerClass, reinterpret_cast<void*>(this));
1559 ASSERT(m_controllerScriptObject);
1561 JSObjectSetProperty(m_scriptContext, global, jsStringRef("InspectorController").get(), m_controllerScriptObject, kJSPropertyAttributeNone, 0);
1564 void InspectorController::scriptObjectReady()
1566 ASSERT(m_scriptContext);
1567 if (!m_scriptContext)
1568 return;
1570 JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
1571 ASSERT(global);
1573 JSValueRef exception = 0;
1575 JSValueRef inspectorValue = JSObjectGetProperty(m_scriptContext, global, jsStringRef("WebInspector").get(), &exception);
1576 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1577 return;
1579 ASSERT(inspectorValue);
1580 if (!inspectorValue)
1581 return;
1583 m_scriptObject = JSValueToObject(m_scriptContext, inspectorValue, &exception);
1584 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1585 return;
1587 ASSERT(m_scriptObject);
1589 JSValueProtect(m_scriptContext, m_scriptObject);
1591 // Make sure our window is visible now that the page loaded
1592 showWindow();
1595 void InspectorController::show()
1597 if (!enabled())
1598 return;
1600 if (!m_page) {
1601 m_page = m_client->createPage();
1602 if (!m_page)
1603 return;
1604 m_page->setParentInspectorController(this);
1606 // showWindow() will be called after the page loads in scriptObjectReady()
1607 return;
1610 showWindow();
1613 void InspectorController::showPanel(SpecialPanels panel)
1615 if (!enabled())
1616 return;
1618 show();
1620 if (!m_scriptObject) {
1621 m_showAfterVisible = panel;
1622 return;
1625 if (panel == CurrentPanel)
1626 return;
1628 const char* showFunctionName;
1629 switch (panel) {
1630 case ConsolePanel:
1631 showFunctionName = "showConsole";
1632 break;
1633 case DatabasesPanel:
1634 showFunctionName = "showDatabasesPanel";
1635 break;
1636 case ElementsPanel:
1637 showFunctionName = "showElementsPanel";
1638 break;
1639 case ProfilesPanel:
1640 showFunctionName = "showProfilesPanel";
1641 break;
1642 case ResourcesPanel:
1643 showFunctionName = "showResourcesPanel";
1644 break;
1645 case ScriptsPanel:
1646 showFunctionName = "showScriptsPanel";
1647 break;
1648 default:
1649 ASSERT_NOT_REACHED();
1650 showFunctionName = 0;
1653 if (showFunctionName)
1654 callSimpleFunction(m_scriptContext, m_scriptObject, showFunctionName);
1657 void InspectorController::close()
1659 if (!enabled())
1660 return;
1662 stopUserInitiatedProfiling();
1663 #if ENABLE(JAVASCRIPT_DEBUGGER)
1664 disableDebugger();
1665 #endif
1666 closeWindow();
1668 if (m_scriptContext && m_scriptObject)
1669 JSValueUnprotect(m_scriptContext, m_scriptObject);
1671 m_scriptObject = 0;
1672 m_scriptContext = 0;
1675 void InspectorController::showWindow()
1677 ASSERT(enabled());
1678 m_client->showWindow();
1681 void InspectorController::closeWindow()
1683 m_client->closeWindow();
1686 void InspectorController::startUserInitiatedProfilingSoon()
1688 m_startProfiling.startOneShot(0);
1691 void InspectorController::startUserInitiatedProfiling(Timer<InspectorController>*)
1693 if (!enabled())
1694 return;
1696 if (!profilerEnabled()) {
1697 enableProfiler(true);
1698 JavaScriptDebugServer::shared().recompileAllJSFunctions();
1701 m_recordingUserInitiatedProfile = true;
1702 m_currentUserInitiatedProfileNumber = m_nextUserInitiatedProfileNumber++;
1704 UString title = UserInitiatedProfileName;
1705 title += ".";
1706 title += UString::from(m_currentUserInitiatedProfileNumber);
1708 ExecState* exec = toJSDOMWindow(m_inspectedPage->mainFrame())->globalExec();
1709 Profiler::profiler()->startProfiling(exec, title);
1711 toggleRecordButton(true);
1714 void InspectorController::stopUserInitiatedProfiling()
1716 if (!enabled())
1717 return;
1719 m_recordingUserInitiatedProfile = false;
1721 UString title = UserInitiatedProfileName;
1722 title += ".";
1723 title += UString::from(m_currentUserInitiatedProfileNumber);
1725 ExecState* exec = toJSDOMWindow(m_inspectedPage->mainFrame())->globalExec();
1726 RefPtr<Profile> profile = Profiler::profiler()->stopProfiling(exec, title);
1727 if (profile)
1728 addProfile(profile, 0, UString());
1730 toggleRecordButton(false);
1733 void InspectorController::enableProfiler(bool skipRecompile)
1735 if (m_profilerEnabled)
1736 return;
1738 m_profilerEnabled = true;
1740 if (!skipRecompile)
1741 JavaScriptDebugServer::shared().recompileAllJSFunctionsSoon();
1743 if (m_scriptContext && m_scriptObject)
1744 callSimpleFunction(m_scriptContext, m_scriptObject, "profilerWasEnabled");
1747 void InspectorController::disableProfiler()
1749 if (!m_profilerEnabled)
1750 return;
1752 m_profilerEnabled = false;
1754 JavaScriptDebugServer::shared().recompileAllJSFunctionsSoon();
1756 if (m_scriptContext && m_scriptObject)
1757 callSimpleFunction(m_scriptContext, m_scriptObject, "profilerWasDisabled");
1760 static void addHeaders(JSContextRef context, JSObjectRef object, const HTTPHeaderMap& headers, JSValueRef* exception)
1762 ASSERT_ARG(context, context);
1763 ASSERT_ARG(object, object);
1765 HTTPHeaderMap::const_iterator end = headers.end();
1766 for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) {
1767 JSValueRef value = JSValueMakeString(context, jsStringRef(it->second).get());
1768 JSObjectSetProperty(context, object, jsStringRef(it->first).get(), value, kJSPropertyAttributeNone, exception);
1769 if (exception && *exception)
1770 return;
1774 static JSObjectRef scriptObjectForRequest(JSContextRef context, const InspectorResource* resource, JSValueRef* exception)
1776 ASSERT_ARG(context, context);
1778 JSObjectRef object = JSObjectMake(context, 0, 0);
1779 addHeaders(context, object, resource->requestHeaderFields, exception);
1781 return object;
1784 static JSObjectRef scriptObjectForResponse(JSContextRef context, const InspectorResource* resource, JSValueRef* exception)
1786 ASSERT_ARG(context, context);
1788 JSObjectRef object = JSObjectMake(context, 0, 0);
1789 addHeaders(context, object, resource->responseHeaderFields, exception);
1791 return object;
1794 JSObjectRef InspectorController::addScriptResource(InspectorResource* resource)
1796 ASSERT_ARG(resource, resource);
1798 ASSERT(m_scriptContext);
1799 ASSERT(m_scriptObject);
1800 if (!m_scriptContext || !m_scriptObject)
1801 return 0;
1803 if (!resource->scriptObject) {
1804 JSValueRef exception = 0;
1806 JSValueRef resourceProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("Resource").get(), &exception);
1807 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1808 return 0;
1810 JSObjectRef resourceConstructor = JSValueToObject(m_scriptContext, resourceProperty, &exception);
1811 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1812 return 0;
1814 JSValueRef urlValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.string()).get());
1815 JSValueRef domainValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.host()).get());
1816 JSValueRef pathValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.path()).get());
1817 JSValueRef lastPathComponentValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.lastPathComponent()).get());
1819 JSValueRef identifier = JSValueMakeNumber(m_scriptContext, resource->identifier);
1820 JSValueRef mainResource = JSValueMakeBoolean(m_scriptContext, m_mainResource == resource);
1821 JSValueRef cached = JSValueMakeBoolean(m_scriptContext, resource->cached);
1823 JSObjectRef scriptObject = scriptObjectForRequest(m_scriptContext, resource, &exception);
1824 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1825 return 0;
1827 JSValueRef arguments[] = { scriptObject, urlValue, domainValue, pathValue, lastPathComponentValue, identifier, mainResource, cached };
1828 JSObjectRef result = JSObjectCallAsConstructor(m_scriptContext, resourceConstructor, 8, arguments, &exception);
1829 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1830 return 0;
1832 ASSERT(result);
1834 resource->setScriptObject(m_scriptContext, result);
1837 JSValueRef exception = 0;
1838 callFunction(m_scriptContext, m_scriptObject, "addResource", 1, &resource->scriptObject, exception);
1840 if (exception)
1841 return 0;
1843 return resource->scriptObject;
1846 JSObjectRef InspectorController::addAndUpdateScriptResource(InspectorResource* resource)
1848 ASSERT_ARG(resource, resource);
1850 JSObjectRef scriptResource = addScriptResource(resource);
1851 if (!scriptResource)
1852 return 0;
1854 updateScriptResourceResponse(resource);
1855 updateScriptResource(resource, resource->length);
1856 updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
1857 updateScriptResource(resource, resource->finished, resource->failed);
1858 return scriptResource;
1861 void InspectorController::removeScriptResource(InspectorResource* resource)
1863 ASSERT(m_scriptContext);
1864 ASSERT(m_scriptObject);
1865 if (!m_scriptContext || !m_scriptObject)
1866 return;
1868 ASSERT(resource);
1869 ASSERT(resource->scriptObject);
1870 if (!resource || !resource->scriptObject)
1871 return;
1873 JSObjectRef scriptObject = resource->scriptObject;
1874 resource->setScriptObject(0, 0);
1876 JSValueRef exception = 0;
1877 callFunction(m_scriptContext, m_scriptObject, "removeResource", 1, &scriptObject, exception);
1880 static void updateResourceRequest(InspectorResource* resource, const ResourceRequest& request)
1882 resource->requestHeaderFields = request.httpHeaderFields();
1883 resource->requestURL = request.url();
1886 static void updateResourceResponse(InspectorResource* resource, const ResourceResponse& response)
1888 resource->expectedContentLength = response.expectedContentLength();
1889 resource->mimeType = response.mimeType();
1890 resource->responseHeaderFields = response.httpHeaderFields();
1891 resource->responseStatusCode = response.httpStatusCode();
1892 resource->suggestedFilename = response.suggestedFilename();
1895 void InspectorController::updateScriptResourceRequest(InspectorResource* resource)
1897 ASSERT(resource->scriptObject);
1898 ASSERT(m_scriptContext);
1899 if (!resource->scriptObject || !m_scriptContext)
1900 return;
1902 JSValueRef urlValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.string()).get());
1903 JSValueRef domainValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.host()).get());
1904 JSValueRef pathValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.path()).get());
1905 JSValueRef lastPathComponentValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.lastPathComponent()).get());
1907 JSValueRef mainResourceValue = JSValueMakeBoolean(m_scriptContext, m_mainResource == resource);
1909 JSValueRef exception = 0;
1911 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("url").get(), urlValue, kJSPropertyAttributeNone, &exception);
1912 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1913 return;
1915 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("domain").get(), domainValue, kJSPropertyAttributeNone, &exception);
1916 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1917 return;
1919 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("path").get(), pathValue, kJSPropertyAttributeNone, &exception);
1920 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1921 return;
1923 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("lastPathComponent").get(), lastPathComponentValue, kJSPropertyAttributeNone, &exception);
1924 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1925 return;
1927 JSObjectRef scriptObject = scriptObjectForRequest(m_scriptContext, resource, &exception);
1928 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1929 return;
1931 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("requestHeaders").get(), scriptObject, kJSPropertyAttributeNone, &exception);
1932 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1933 return;
1935 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("mainResource").get(), mainResourceValue, kJSPropertyAttributeNone, &exception);
1936 HANDLE_EXCEPTION(m_scriptContext, exception);
1939 void InspectorController::updateScriptResourceResponse(InspectorResource* resource)
1941 ASSERT(resource->scriptObject);
1942 ASSERT(m_scriptContext);
1943 if (!resource->scriptObject || !m_scriptContext)
1944 return;
1946 JSValueRef mimeTypeValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->mimeType).get());
1948 JSValueRef suggestedFilenameValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->suggestedFilename).get());
1950 JSValueRef expectedContentLengthValue = JSValueMakeNumber(m_scriptContext, static_cast<double>(resource->expectedContentLength));
1951 JSValueRef statusCodeValue = JSValueMakeNumber(m_scriptContext, resource->responseStatusCode);
1953 JSValueRef exception = 0;
1955 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("mimeType").get(), mimeTypeValue, kJSPropertyAttributeNone, &exception);
1956 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1957 return;
1959 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("suggestedFilename").get(), suggestedFilenameValue, kJSPropertyAttributeNone, &exception);
1960 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1961 return;
1963 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("expectedContentLength").get(), expectedContentLengthValue, kJSPropertyAttributeNone, &exception);
1964 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1965 return;
1967 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("statusCode").get(), statusCodeValue, kJSPropertyAttributeNone, &exception);
1968 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1969 return;
1971 JSObjectRef scriptObject = scriptObjectForResponse(m_scriptContext, resource, &exception);
1972 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1973 return;
1975 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("responseHeaders").get(), scriptObject, kJSPropertyAttributeNone, &exception);
1976 if (HANDLE_EXCEPTION(m_scriptContext, exception))
1977 return;
1979 updateScriptResourceType(resource);
1982 void InspectorController::updateScriptResourceType(InspectorResource* resource)
1984 ASSERT(resource->scriptObject);
1985 ASSERT(m_scriptContext);
1986 if (!resource->scriptObject || !m_scriptContext)
1987 return;
1989 JSValueRef exception = 0;
1991 JSValueRef typeValue = JSValueMakeNumber(m_scriptContext, resource->type());
1992 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("type").get(), typeValue, kJSPropertyAttributeNone, &exception);
1993 HANDLE_EXCEPTION(m_scriptContext, exception);
1996 void InspectorController::updateScriptResource(InspectorResource* resource, int length)
1998 ASSERT(resource->scriptObject);
1999 ASSERT(m_scriptContext);
2000 if (!resource->scriptObject || !m_scriptContext)
2001 return;
2003 JSValueRef lengthValue = JSValueMakeNumber(m_scriptContext, length);
2005 JSValueRef exception = 0;
2007 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("contentLength").get(), lengthValue, kJSPropertyAttributeNone, &exception);
2008 HANDLE_EXCEPTION(m_scriptContext, exception);
2011 void InspectorController::updateScriptResource(InspectorResource* resource, bool finished, bool failed)
2013 ASSERT(resource->scriptObject);
2014 ASSERT(m_scriptContext);
2015 if (!resource->scriptObject || !m_scriptContext)
2016 return;
2018 JSValueRef failedValue = JSValueMakeBoolean(m_scriptContext, failed);
2019 JSValueRef finishedValue = JSValueMakeBoolean(m_scriptContext, finished);
2021 JSValueRef exception = 0;
2023 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("failed").get(), failedValue, kJSPropertyAttributeNone, &exception);
2024 if (HANDLE_EXCEPTION(m_scriptContext, exception))
2025 return;
2027 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("finished").get(), finishedValue, kJSPropertyAttributeNone, &exception);
2028 HANDLE_EXCEPTION(m_scriptContext, exception);
2031 void InspectorController::updateScriptResource(InspectorResource* resource, double startTime, double responseReceivedTime, double endTime)
2033 ASSERT(resource->scriptObject);
2034 ASSERT(m_scriptContext);
2035 if (!resource->scriptObject || !m_scriptContext)
2036 return;
2038 JSValueRef startTimeValue = JSValueMakeNumber(m_scriptContext, startTime);
2039 JSValueRef responseReceivedTimeValue = JSValueMakeNumber(m_scriptContext, responseReceivedTime);
2040 JSValueRef endTimeValue = JSValueMakeNumber(m_scriptContext, endTime);
2042 JSValueRef exception = 0;
2044 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("startTime").get(), startTimeValue, kJSPropertyAttributeNone, &exception);
2045 if (HANDLE_EXCEPTION(m_scriptContext, exception))
2046 return;
2048 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("responseReceivedTime").get(), responseReceivedTimeValue, kJSPropertyAttributeNone, &exception);
2049 if (HANDLE_EXCEPTION(m_scriptContext, exception))
2050 return;
2052 JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("endTime").get(), endTimeValue, kJSPropertyAttributeNone, &exception);
2053 HANDLE_EXCEPTION(m_scriptContext, exception);
2056 void InspectorController::populateScriptObjects()
2058 ASSERT(m_scriptContext);
2059 if (!m_scriptContext)
2060 return;
2062 ResourcesMap::iterator resourcesEnd = m_resources.end();
2063 for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it)
2064 addAndUpdateScriptResource(it->second.get());
2066 unsigned messageCount = m_consoleMessages.size();
2067 for (unsigned i = 0; i < messageCount; ++i)
2068 addScriptConsoleMessage(m_consoleMessages[i]);
2070 #if ENABLE(DATABASE)
2071 DatabaseResourcesSet::iterator databasesEnd = m_databaseResources.end();
2072 for (DatabaseResourcesSet::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it)
2073 addDatabaseScriptResource((*it).get());
2074 #endif
2076 callSimpleFunction(m_scriptContext, m_scriptObject, "populateInterface");
2079 #if ENABLE(DATABASE)
2080 JSObjectRef InspectorController::addDatabaseScriptResource(InspectorDatabaseResource* resource)
2082 ASSERT_ARG(resource, resource);
2084 if (resource->scriptObject)
2085 return resource->scriptObject;
2087 ASSERT(m_scriptContext);
2088 ASSERT(m_scriptObject);
2089 if (!m_scriptContext || !m_scriptObject)
2090 return 0;
2092 Frame* frame = resource->database->document()->frame();
2093 if (!frame)
2094 return 0;
2096 JSValueRef exception = 0;
2098 JSValueRef databaseProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("Database").get(), &exception);
2099 if (HANDLE_EXCEPTION(m_scriptContext, exception))
2100 return 0;
2102 JSObjectRef databaseConstructor = JSValueToObject(m_scriptContext, databaseProperty, &exception);
2103 if (HANDLE_EXCEPTION(m_scriptContext, exception))
2104 return 0;
2106 ExecState* exec = toJSDOMWindow(frame)->globalExec();
2108 JSValueRef database;
2111 JSC::JSLock lock(false);
2112 database = toRef(JSInspectedObjectWrapper::wrap(exec, toJS(exec, resource->database.get())));
2115 JSValueRef domainValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->domain).get());
2116 JSValueRef nameValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->name).get());
2117 JSValueRef versionValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->version).get());
2119 JSValueRef arguments[] = { database, domainValue, nameValue, versionValue };
2120 JSObjectRef result = JSObjectCallAsConstructor(m_scriptContext, databaseConstructor, 4, arguments, &exception);
2121 if (HANDLE_EXCEPTION(m_scriptContext, exception))
2122 return 0;
2124 ASSERT(result);
2126 callFunction(m_scriptContext, m_scriptObject, "addDatabase", 1, &result, exception);
2128 if (exception)
2129 return 0;
2131 resource->setScriptObject(m_scriptContext, result);
2133 return result;
2136 void InspectorController::removeDatabaseScriptResource(InspectorDatabaseResource* resource)
2138 ASSERT(m_scriptContext);
2139 ASSERT(m_scriptObject);
2140 if (!m_scriptContext || !m_scriptObject)
2141 return;
2143 ASSERT(resource);
2144 ASSERT(resource->scriptObject);
2145 if (!resource || !resource->scriptObject)
2146 return;
2148 JSObjectRef scriptObject = resource->scriptObject;
2149 resource->setScriptObject(0, 0);
2151 JSValueRef exception = 0;
2152 callFunction(m_scriptContext, m_scriptObject, "removeDatabase", 1, &scriptObject, exception);
2154 #endif
2156 void InspectorController::addScriptConsoleMessage(const ConsoleMessage* message)
2158 ASSERT_ARG(message, message);
2160 JSValueRef exception = 0;
2162 JSValueRef messageConstructorProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("ConsoleMessage").get(), &exception);
2163 if (HANDLE_EXCEPTION(m_scriptContext, exception))
2164 return;
2166 JSObjectRef messageConstructor = JSValueToObject(m_scriptContext, messageConstructorProperty, &exception);
2167 if (HANDLE_EXCEPTION(m_scriptContext, exception))
2168 return;
2170 JSValueRef sourceValue = JSValueMakeNumber(m_scriptContext, message->source);
2171 JSValueRef levelValue = JSValueMakeNumber(m_scriptContext, message->level);
2172 JSValueRef lineValue = JSValueMakeNumber(m_scriptContext, message->line);
2173 JSValueRef urlValue = JSValueMakeString(m_scriptContext, jsStringRef(message->url).get());
2174 JSValueRef groupLevelValue = JSValueMakeNumber(m_scriptContext, message->groupLevel);
2175 JSValueRef repeatCountValue = JSValueMakeNumber(m_scriptContext, message->repeatCount);
2177 static const unsigned maximumMessageArguments = 256;
2178 JSValueRef arguments[maximumMessageArguments];
2179 unsigned argumentCount = 0;
2180 arguments[argumentCount++] = sourceValue;
2181 arguments[argumentCount++] = levelValue;
2182 arguments[argumentCount++] = lineValue;
2183 arguments[argumentCount++] = urlValue;
2184 arguments[argumentCount++] = groupLevelValue;
2185 arguments[argumentCount++] = repeatCountValue;
2187 if (!message->wrappedArguments.isEmpty()) {
2188 unsigned remainingSpaceInArguments = maximumMessageArguments - argumentCount;
2189 unsigned argumentsToAdd = min(remainingSpaceInArguments, static_cast<unsigned>(message->wrappedArguments.size()));
2190 for (unsigned i = 0; i < argumentsToAdd; ++i)
2191 arguments[argumentCount++] = toRef(message->wrappedArguments[i]);
2192 } else {
2193 JSValueRef messageValue = JSValueMakeString(m_scriptContext, jsStringRef(message->message).get());
2194 arguments[argumentCount++] = messageValue;
2197 JSObjectRef messageObject = JSObjectCallAsConstructor(m_scriptContext, messageConstructor, argumentCount, arguments, &exception);
2198 if (HANDLE_EXCEPTION(m_scriptContext, exception))
2199 return;
2201 callFunction(m_scriptContext, m_scriptObject, "addMessageToConsole", 1, &messageObject, exception);
2204 void InspectorController::addScriptProfile(Profile* profile)
2206 JSLock lock(false);
2207 JSValueRef exception = 0;
2208 JSValueRef profileObject = toRef(toJS(toJS(m_scriptContext), profile));
2209 callFunction(m_scriptContext, m_scriptObject, "addProfile", 1, &profileObject, exception);
2212 void InspectorController::resetScriptObjects()
2214 if (!m_scriptContext || !m_scriptObject)
2215 return;
2217 ResourcesMap::iterator resourcesEnd = m_resources.end();
2218 for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it) {
2219 InspectorResource* resource = it->second.get();
2220 resource->setScriptObject(0, 0);
2223 #if ENABLE(DATABASE)
2224 DatabaseResourcesSet::iterator databasesEnd = m_databaseResources.end();
2225 for (DatabaseResourcesSet::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it) {
2226 InspectorDatabaseResource* resource = (*it).get();
2227 resource->setScriptObject(0, 0);
2229 #endif
2231 callSimpleFunction(m_scriptContext, m_scriptObject, "reset");
2234 void InspectorController::pruneResources(ResourcesMap* resourceMap, DocumentLoader* loaderToKeep)
2236 ASSERT_ARG(resourceMap, resourceMap);
2238 ResourcesMap mapCopy(*resourceMap);
2239 ResourcesMap::iterator end = mapCopy.end();
2240 for (ResourcesMap::iterator it = mapCopy.begin(); it != end; ++it) {
2241 InspectorResource* resource = (*it).second.get();
2242 if (resource == m_mainResource)
2243 continue;
2245 if (!loaderToKeep || resource->loader != loaderToKeep) {
2246 removeResource(resource);
2247 if (windowVisible() && resource->scriptObject)
2248 removeScriptResource(resource);
2253 void InspectorController::didCommitLoad(DocumentLoader* loader)
2255 if (!enabled())
2256 return;
2258 ASSERT(m_inspectedPage);
2260 if (loader->frame() == m_inspectedPage->mainFrame()) {
2261 m_client->inspectedURLChanged(loader->url().string());
2263 clearConsoleMessages();
2265 m_times.clear();
2266 m_counts.clear();
2267 m_profiles.clear();
2269 #if ENABLE(DATABASE)
2270 m_databaseResources.clear();
2271 #endif
2273 if (windowVisible()) {
2274 resetScriptObjects();
2276 if (!loader->isLoadingFromCachedPage()) {
2277 ASSERT(m_mainResource && m_mainResource->loader == loader);
2278 // We don't add the main resource until its load is committed. This is
2279 // needed to keep the load for a user-entered URL from showing up in the
2280 // list of resources for the page they are navigating away from.
2281 addAndUpdateScriptResource(m_mainResource.get());
2282 } else {
2283 // Pages loaded from the page cache are committed before
2284 // m_mainResource is the right resource for this load, so we
2285 // clear it here. It will be re-assigned in
2286 // identifierForInitialRequest.
2287 m_mainResource = 0;
2292 for (Frame* frame = loader->frame(); frame; frame = frame->tree()->traverseNext(loader->frame()))
2293 if (ResourcesMap* resourceMap = m_frameResources.get(frame))
2294 pruneResources(resourceMap, loader);
2297 void InspectorController::frameDetachedFromParent(Frame* frame)
2299 if (!enabled())
2300 return;
2301 if (ResourcesMap* resourceMap = m_frameResources.get(frame))
2302 removeAllResources(resourceMap);
2305 void InspectorController::addResource(InspectorResource* resource)
2307 m_resources.set(resource->identifier, resource);
2308 m_knownResources.add(resource->requestURL.string());
2310 Frame* frame = resource->frame.get();
2311 ResourcesMap* resourceMap = m_frameResources.get(frame);
2312 if (resourceMap)
2313 resourceMap->set(resource->identifier, resource);
2314 else {
2315 resourceMap = new ResourcesMap;
2316 resourceMap->set(resource->identifier, resource);
2317 m_frameResources.set(frame, resourceMap);
2321 void InspectorController::removeResource(InspectorResource* resource)
2323 m_resources.remove(resource->identifier);
2324 m_knownResources.remove(resource->requestURL.string());
2326 Frame* frame = resource->frame.get();
2327 ResourcesMap* resourceMap = m_frameResources.get(frame);
2328 if (!resourceMap) {
2329 ASSERT_NOT_REACHED();
2330 return;
2333 resourceMap->remove(resource->identifier);
2334 if (resourceMap->isEmpty()) {
2335 m_frameResources.remove(frame);
2336 delete resourceMap;
2340 void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader* loader, const ResourceRequest& request, const ResourceResponse& response, int length)
2342 if (!enabled())
2343 return;
2345 // If the resource URL is already known, we don't need to add it again since this is just a cached load.
2346 if (m_knownResources.contains(request.url().string()))
2347 return;
2349 RefPtr<InspectorResource> resource = InspectorResource::create(m_nextIdentifier--, loader, loader->frame());
2350 resource->finished = true;
2352 updateResourceRequest(resource.get(), request);
2353 updateResourceResponse(resource.get(), response);
2355 resource->length = length;
2356 resource->cached = true;
2357 resource->startTime = currentTime();
2358 resource->responseReceivedTime = resource->startTime;
2359 resource->endTime = resource->startTime;
2361 ASSERT(m_inspectedPage);
2363 if (loader->frame() == m_inspectedPage->mainFrame() && request.url() == loader->requestURL())
2364 m_mainResource = resource;
2366 addResource(resource.get());
2368 if (windowVisible())
2369 addAndUpdateScriptResource(resource.get());
2372 void InspectorController::identifierForInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request)
2374 if (!enabled())
2375 return;
2377 RefPtr<InspectorResource> resource = InspectorResource::create(identifier, loader, loader->frame());
2379 updateResourceRequest(resource.get(), request);
2381 ASSERT(m_inspectedPage);
2383 if (loader->frame() == m_inspectedPage->mainFrame() && request.url() == loader->requestURL())
2384 m_mainResource = resource;
2386 addResource(resource.get());
2388 if (windowVisible() && loader->isLoadingFromCachedPage() && resource == m_mainResource)
2389 addAndUpdateScriptResource(resource.get());
2392 void InspectorController::willSendRequest(DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse)
2394 if (!enabled())
2395 return;
2397 InspectorResource* resource = m_resources.get(identifier).get();
2398 if (!resource)
2399 return;
2401 resource->startTime = currentTime();
2403 if (!redirectResponse.isNull()) {
2404 updateResourceRequest(resource, request);
2405 updateResourceResponse(resource, redirectResponse);
2408 if (resource != m_mainResource && windowVisible()) {
2409 if (!resource->scriptObject)
2410 addScriptResource(resource);
2411 else
2412 updateScriptResourceRequest(resource);
2414 updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
2416 if (!redirectResponse.isNull())
2417 updateScriptResourceResponse(resource);
2421 void InspectorController::didReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse& response)
2423 if (!enabled())
2424 return;
2426 InspectorResource* resource = m_resources.get(identifier).get();
2427 if (!resource)
2428 return;
2430 updateResourceResponse(resource, response);
2432 resource->responseReceivedTime = currentTime();
2434 if (windowVisible() && resource->scriptObject) {
2435 updateScriptResourceResponse(resource);
2436 updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
2440 void InspectorController::didReceiveContentLength(DocumentLoader*, unsigned long identifier, int lengthReceived)
2442 if (!enabled())
2443 return;
2445 InspectorResource* resource = m_resources.get(identifier).get();
2446 if (!resource)
2447 return;
2449 resource->length += lengthReceived;
2451 if (windowVisible() && resource->scriptObject)
2452 updateScriptResource(resource, resource->length);
2455 void InspectorController::didFinishLoading(DocumentLoader* loader, unsigned long identifier)
2457 if (!enabled())
2458 return;
2460 RefPtr<InspectorResource> resource = m_resources.get(identifier);
2461 if (!resource)
2462 return;
2464 removeResource(resource.get());
2466 resource->finished = true;
2467 resource->endTime = currentTime();
2469 addResource(resource.get());
2471 if (windowVisible() && resource->scriptObject) {
2472 updateScriptResource(resource.get(), resource->startTime, resource->responseReceivedTime, resource->endTime);
2473 updateScriptResource(resource.get(), resource->finished);
2477 void InspectorController::didFailLoading(DocumentLoader* loader, unsigned long identifier, const ResourceError& /*error*/)
2479 if (!enabled())
2480 return;
2482 RefPtr<InspectorResource> resource = m_resources.get(identifier);
2483 if (!resource)
2484 return;
2486 removeResource(resource.get());
2488 resource->finished = true;
2489 resource->failed = true;
2490 resource->endTime = currentTime();
2492 addResource(resource.get());
2494 if (windowVisible() && resource->scriptObject) {
2495 updateScriptResource(resource.get(), resource->startTime, resource->responseReceivedTime, resource->endTime);
2496 updateScriptResource(resource.get(), resource->finished, resource->failed);
2500 void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identifier, JSC::UString& sourceString)
2502 if (!enabled())
2503 return;
2505 InspectorResource* resource = m_resources.get(identifier).get();
2506 if (!resource)
2507 return;
2509 resource->setXMLHttpRequestProperties(sourceString);
2511 if (windowVisible() && resource->scriptObject)
2512 updateScriptResourceType(resource);
2516 #if ENABLE(DATABASE)
2517 void InspectorController::didOpenDatabase(Database* database, const String& domain, const String& name, const String& version)
2519 if (!enabled())
2520 return;
2522 RefPtr<InspectorDatabaseResource> resource = InspectorDatabaseResource::create(database, domain, name, version);
2524 m_databaseResources.add(resource);
2526 if (windowVisible())
2527 addDatabaseScriptResource(resource.get());
2529 #endif
2531 void InspectorController::moveWindowBy(float x, float y) const
2533 if (!m_page || !enabled())
2534 return;
2536 FloatRect frameRect = m_page->chrome()->windowRect();
2537 frameRect.move(x, y);
2538 m_page->chrome()->setWindowRect(frameRect);
2541 #if ENABLE(JAVASCRIPT_DEBUGGER)
2542 void InspectorController::enableDebugger()
2544 if (!enabled())
2545 return;
2547 if (!m_scriptContext || !m_scriptObject) {
2548 m_attachDebuggerWhenShown = true;
2549 return;
2552 ASSERT(m_inspectedPage);
2554 JavaScriptDebugServer::shared().addListener(this, m_inspectedPage);
2555 JavaScriptDebugServer::shared().clearBreakpoints();
2557 m_debuggerEnabled = true;
2558 m_attachDebuggerWhenShown = false;
2560 callSimpleFunction(m_scriptContext, m_scriptObject, "debuggerWasEnabled");
2563 void InspectorController::disableDebugger()
2565 if (!enabled())
2566 return;
2568 ASSERT(m_inspectedPage);
2570 JavaScriptDebugServer::shared().removeListener(this, m_inspectedPage);
2572 m_debuggerEnabled = false;
2573 m_attachDebuggerWhenShown = false;
2575 if (m_scriptContext && m_scriptObject)
2576 callSimpleFunction(m_scriptContext, m_scriptObject, "debuggerWasDisabled");
2579 JavaScriptCallFrame* InspectorController::currentCallFrame() const
2581 return JavaScriptDebugServer::shared().currentCallFrame();
2584 bool InspectorController::pauseOnExceptions()
2586 return JavaScriptDebugServer::shared().pauseOnExceptions();
2589 void InspectorController::setPauseOnExceptions(bool pause)
2591 JavaScriptDebugServer::shared().setPauseOnExceptions(pause);
2594 void InspectorController::pauseInDebugger()
2596 if (!m_debuggerEnabled)
2597 return;
2598 JavaScriptDebugServer::shared().pauseProgram();
2601 void InspectorController::resumeDebugger()
2603 if (!m_debuggerEnabled)
2604 return;
2605 JavaScriptDebugServer::shared().continueProgram();
2608 void InspectorController::stepOverStatementInDebugger()
2610 if (!m_debuggerEnabled)
2611 return;
2612 JavaScriptDebugServer::shared().stepOverStatement();
2615 void InspectorController::stepIntoStatementInDebugger()
2617 if (!m_debuggerEnabled)
2618 return;
2619 JavaScriptDebugServer::shared().stepIntoStatement();
2622 void InspectorController::stepOutOfFunctionInDebugger()
2624 if (!m_debuggerEnabled)
2625 return;
2626 JavaScriptDebugServer::shared().stepOutOfFunction();
2629 void InspectorController::addBreakpoint(intptr_t sourceID, unsigned lineNumber)
2631 JavaScriptDebugServer::shared().addBreakpoint(sourceID, lineNumber);
2634 void InspectorController::removeBreakpoint(intptr_t sourceID, unsigned lineNumber)
2636 JavaScriptDebugServer::shared().removeBreakpoint(sourceID, lineNumber);
2638 #endif
2640 static void drawOutlinedRect(GraphicsContext& context, const IntRect& rect, const Color& fillColor)
2642 static const int outlineThickness = 1;
2643 static const Color outlineColor(62, 86, 180, 228);
2645 IntRect outline = rect;
2646 outline.inflate(outlineThickness);
2648 context.clearRect(outline);
2650 context.save();
2651 context.clipOut(rect);
2652 context.fillRect(outline, outlineColor);
2653 context.restore();
2655 context.fillRect(rect, fillColor);
2658 static void drawHighlightForBoxes(GraphicsContext& context, const Vector<IntRect>& lineBoxRects, const IntRect& contentBox, const IntRect& paddingBox, const IntRect& borderBox, const IntRect& marginBox)
2660 static const Color contentBoxColor(125, 173, 217, 128);
2661 static const Color paddingBoxColor(125, 173, 217, 160);
2662 static const Color borderBoxColor(125, 173, 217, 192);
2663 static const Color marginBoxColor(125, 173, 217, 228);
2665 if (!lineBoxRects.isEmpty()) {
2666 for (size_t i = 0; i < lineBoxRects.size(); ++i)
2667 drawOutlinedRect(context, lineBoxRects[i], contentBoxColor);
2668 return;
2671 if (marginBox != borderBox)
2672 drawOutlinedRect(context, marginBox, marginBoxColor);
2673 if (borderBox != paddingBox)
2674 drawOutlinedRect(context, borderBox, borderBoxColor);
2675 if (paddingBox != contentBox)
2676 drawOutlinedRect(context, paddingBox, paddingBoxColor);
2677 drawOutlinedRect(context, contentBox, contentBoxColor);
2680 static inline void convertFromFrameToMainFrame(Frame* frame, IntRect& rect)
2682 rect = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(rect));
2685 void InspectorController::drawNodeHighlight(GraphicsContext& context) const
2687 if (!m_highlightedNode)
2688 return;
2690 RenderObject* renderer = m_highlightedNode->renderer();
2691 Frame* containingFrame = m_highlightedNode->document()->frame();
2692 if (!renderer || !containingFrame)
2693 return;
2695 IntRect contentBox = renderer->absoluteContentBox();
2696 IntRect boundingBox = renderer->absoluteBoundingBoxRect();
2698 // FIXME: Should we add methods to RenderObject to obtain these rects?
2699 IntRect paddingBox(contentBox.x() - renderer->paddingLeft(), contentBox.y() - renderer->paddingTop(), contentBox.width() + renderer->paddingLeft() + renderer->paddingRight(), contentBox.height() + renderer->paddingTop() + renderer->paddingBottom());
2700 IntRect borderBox(paddingBox.x() - renderer->borderLeft(), paddingBox.y() - renderer->borderTop(), paddingBox.width() + renderer->borderLeft() + renderer->borderRight(), paddingBox.height() + renderer->borderTop() + renderer->borderBottom());
2701 IntRect marginBox(borderBox.x() - renderer->marginLeft(), borderBox.y() - renderer->marginTop(), borderBox.width() + renderer->marginLeft() + renderer->marginRight(), borderBox.height() + renderer->marginTop() + renderer->marginBottom());
2703 convertFromFrameToMainFrame(containingFrame, contentBox);
2704 convertFromFrameToMainFrame(containingFrame, paddingBox);
2705 convertFromFrameToMainFrame(containingFrame, borderBox);
2706 convertFromFrameToMainFrame(containingFrame, marginBox);
2707 convertFromFrameToMainFrame(containingFrame, boundingBox);
2709 Vector<IntRect> lineBoxRects;
2710 if (renderer->isInline() || (renderer->isText() && !m_highlightedNode->isSVGElement())) {
2711 // FIXME: We should show margins/padding/border for inlines.
2712 renderer->addLineBoxRects(lineBoxRects);
2715 for (unsigned i = 0; i < lineBoxRects.size(); ++i)
2716 convertFromFrameToMainFrame(containingFrame, lineBoxRects[i]);
2718 if (lineBoxRects.isEmpty() && contentBox.isEmpty()) {
2719 // If we have no line boxes and our content box is empty, we'll just draw our bounding box.
2720 // This can happen, e.g., with an <a> enclosing an <img style="float:right">.
2721 // FIXME: Can we make this better/more accurate? The <a> in the above case has no
2722 // width/height but the highlight makes it appear to be the size of the <img>.
2723 lineBoxRects.append(boundingBox);
2726 ASSERT(m_inspectedPage);
2728 FrameView* view = m_inspectedPage->mainFrame()->view();
2729 FloatRect overlayRect = view->visibleContentRect();
2731 if (!overlayRect.contains(boundingBox) && !boundingBox.contains(enclosingIntRect(overlayRect))) {
2732 Element* element;
2733 if (m_highlightedNode->isElementNode())
2734 element = static_cast<Element*>(m_highlightedNode.get());
2735 else
2736 element = static_cast<Element*>(m_highlightedNode->parent());
2737 overlayRect = view->visibleContentRect();
2740 context.translate(-overlayRect.x(), -overlayRect.y());
2742 drawHighlightForBoxes(context, lineBoxRects, contentBox, paddingBox, borderBox, marginBox);
2745 void InspectorController::count(const UString& title, unsigned lineNumber, const String& sourceID)
2747 String identifier = String(title) + String::format("@%s:%d", sourceID.utf8().data(), lineNumber);
2748 HashMap<String, unsigned>::iterator it = m_counts.find(identifier);
2749 int count;
2750 if (it == m_counts.end())
2751 count = 1;
2752 else {
2753 count = it->second + 1;
2754 m_counts.remove(it);
2757 m_counts.add(identifier, count);
2759 String message = String::format("%s: %d", title.UTF8String().c_str(), count);
2760 addMessageToConsole(JSMessageSource, LogMessageLevel, message, lineNumber, sourceID);
2763 void InspectorController::startTiming(const UString& title)
2765 m_times.add(title, currentTime() * 1000);
2768 bool InspectorController::stopTiming(const UString& title, double& elapsed)
2770 HashMap<String, double>::iterator it = m_times.find(title);
2771 if (it == m_times.end())
2772 return false;
2774 double startTime = it->second;
2775 m_times.remove(it);
2777 elapsed = currentTime() * 1000 - startTime;
2778 return true;
2781 bool InspectorController::handleException(JSContextRef context, JSValueRef exception, unsigned lineNumber) const
2783 if (!exception)
2784 return false;
2786 if (!m_page)
2787 return true;
2789 String message = toString(context, exception, 0);
2790 String file(__FILE__);
2792 if (JSObjectRef exceptionObject = JSValueToObject(context, exception, 0)) {
2793 JSValueRef lineValue = JSObjectGetProperty(context, exceptionObject, jsStringRef("line").get(), NULL);
2794 if (lineValue)
2795 lineNumber = static_cast<unsigned>(JSValueToNumber(context, lineValue, 0));
2797 JSValueRef fileValue = JSObjectGetProperty(context, exceptionObject, jsStringRef("sourceURL").get(), NULL);
2798 if (fileValue)
2799 file = toString(context, fileValue, 0);
2802 m_page->mainFrame()->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, lineNumber, file);
2803 return true;
2806 #if ENABLE(JAVASCRIPT_DEBUGGER)
2807 // JavaScriptDebugListener functions
2809 void InspectorController::didParseSource(ExecState* exec, const SourceCode& source)
2811 JSValueRef sourceIDValue = JSValueMakeNumber(m_scriptContext, source.provider()->asID());
2812 JSValueRef sourceURLValue = JSValueMakeString(m_scriptContext, jsStringRef(source.provider()->url()).get());
2813 JSValueRef sourceValue = JSValueMakeString(m_scriptContext, jsStringRef(source).get());
2814 JSValueRef firstLineValue = JSValueMakeNumber(m_scriptContext, source.firstLine());
2816 JSValueRef exception = 0;
2817 JSValueRef arguments[] = { sourceIDValue, sourceURLValue, sourceValue, firstLineValue };
2818 callFunction(m_scriptContext, m_scriptObject, "parsedScriptSource", 4, arguments, exception);
2821 void InspectorController::failedToParseSource(ExecState* exec, const SourceCode& source, int errorLine, const UString& errorMessage)
2823 JSValueRef sourceURLValue = JSValueMakeString(m_scriptContext, jsStringRef(source.provider()->url()).get());
2824 JSValueRef sourceValue = JSValueMakeString(m_scriptContext, jsStringRef(source.data()).get());
2825 JSValueRef firstLineValue = JSValueMakeNumber(m_scriptContext, source.firstLine());
2826 JSValueRef errorLineValue = JSValueMakeNumber(m_scriptContext, errorLine);
2827 JSValueRef errorMessageValue = JSValueMakeString(m_scriptContext, jsStringRef(errorMessage).get());
2829 JSValueRef exception = 0;
2830 JSValueRef arguments[] = { sourceURLValue, sourceValue, firstLineValue, errorLineValue, errorMessageValue };
2831 callFunction(m_scriptContext, m_scriptObject, "failedToParseScriptSource", 5, arguments, exception);
2834 void InspectorController::didPause()
2836 JSValueRef exception = 0;
2837 callFunction(m_scriptContext, m_scriptObject, "pausedScript", 0, 0, exception);
2839 #endif
2841 } // namespace WebCore