• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "config.h"
31 #include "InspectorController.h"
32 
33 #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 "FloatQuad.h"
43 #include "FloatRect.h"
44 #include "Frame.h"
45 #include "FrameLoader.h"
46 #include "FrameTree.h"
47 #include "FrameView.h"
48 #include "GraphicsContext.h"
49 #include "HitTestResult.h"
50 #include "HTMLFrameOwnerElement.h"
51 #include "InspectorClient.h"
52 #include "JSDOMWindow.h"
53 #include "JSInspectedObjectWrapper.h"
54 #include "JSInspectorCallbackWrapper.h"
55 #include "JSNode.h"
56 #include "JSRange.h"
57 #include "JavaScriptProfile.h"
58 #include "Page.h"
59 #include "Range.h"
60 #include "ResourceRequest.h"
61 #include "ResourceResponse.h"
62 #include "Settings.h"
63 #include "ScriptCallStack.h"
64 #include "SharedBuffer.h"
65 #include "TextEncoding.h"
66 #include "TextIterator.h"
67 #include "ScriptController.h"
68 #include <JavaScriptCore/APICast.h>
69 #include <JavaScriptCore/JSRetainPtr.h>
70 #include <JavaScriptCore/JSStringRef.h>
71 #include <JavaScriptCore/OpaqueJSString.h>
72 #include <runtime/JSLock.h>
73 #include <runtime/UString.h>
74 #include <runtime/CollectorHeapIterator.h>
75 #include <profiler/Profile.h>
76 #include <profiler/Profiler.h>
77 #include <wtf/CurrentTime.h>
78 #include <wtf/RefCounted.h>
79 #include <wtf/StdLibExtras.h>
80 
81 #if ENABLE(DATABASE)
82 #include "Database.h"
83 #include "JSDatabase.h"
84 #endif
85 
86 #if ENABLE(JAVASCRIPT_DEBUGGER)
87 #include "JavaScriptCallFrame.h"
88 #include "JavaScriptDebugServer.h"
89 #include "JSJavaScriptCallFrame.h"
90 #endif
91 
92 using namespace JSC;
93 using namespace std;
94 
95 namespace WebCore {
96 
97 static const char* const UserInitiatedProfileName = "org.webkit.profiles.user-initiated";
98 
jsStringRef(const char * str)99 static JSRetainPtr<JSStringRef> jsStringRef(const char* str)
100 {
101     return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString(str));
102 }
103 
jsStringRef(const SourceCode & str)104 static JSRetainPtr<JSStringRef> jsStringRef(const SourceCode& str)
105 {
106     return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithCharacters(str.data(), str.length()));
107 }
108 
jsStringRef(const String & str)109 static JSRetainPtr<JSStringRef> jsStringRef(const String& str)
110 {
111     return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithCharacters(str.characters(), str.length()));
112 }
113 
jsStringRef(const UString & str)114 static JSRetainPtr<JSStringRef> jsStringRef(const UString& str)
115 {
116     return JSRetainPtr<JSStringRef>(Adopt, OpaqueJSString::create(str).releaseRef());
117 }
118 
toString(JSContextRef context,JSValueRef value,JSValueRef * exception)119 static String toString(JSContextRef context, JSValueRef value, JSValueRef* exception)
120 {
121     ASSERT_ARG(value, value);
122     if (!value)
123         return String();
124     JSRetainPtr<JSStringRef> scriptString(Adopt, JSValueToStringCopy(context, value, exception));
125     if (exception && *exception)
126         return String();
127     return String(JSStringGetCharactersPtr(scriptString.get()), JSStringGetLength(scriptString.get()));
128 }
129 
130 #define HANDLE_EXCEPTION(context, exception) handleException((context), (exception), __LINE__)
131 
callSimpleFunction(JSContextRef context,JSObjectRef thisObject,const char * functionName) const132 JSValueRef InspectorController::callSimpleFunction(JSContextRef context, JSObjectRef thisObject, const char* functionName) const
133 {
134     JSValueRef exception = 0;
135     return callFunction(context, thisObject, functionName, 0, 0, exception);
136 }
137 
callFunction(JSContextRef context,JSObjectRef thisObject,const char * functionName,size_t argumentCount,const JSValueRef arguments[],JSValueRef & exception) const138 JSValueRef InspectorController::callFunction(JSContextRef context, JSObjectRef thisObject, const char* functionName, size_t argumentCount, const JSValueRef arguments[], JSValueRef& exception) const
139 {
140     ASSERT_ARG(context, context);
141     ASSERT_ARG(thisObject, thisObject);
142 
143     if (exception)
144         return JSValueMakeUndefined(context);
145 
146     JSValueRef functionProperty = JSObjectGetProperty(context, thisObject, jsStringRef(functionName).get(), &exception);
147     if (HANDLE_EXCEPTION(context, exception))
148         return JSValueMakeUndefined(context);
149 
150     JSObjectRef function = JSValueToObject(context, functionProperty, &exception);
151     if (HANDLE_EXCEPTION(context, exception))
152         return JSValueMakeUndefined(context);
153 
154     JSValueRef result = JSObjectCallAsFunction(context, function, thisObject, argumentCount, arguments, &exception);
155     if (HANDLE_EXCEPTION(context, exception))
156         return JSValueMakeUndefined(context);
157 
158     return result;
159 }
160 
161 // ConsoleMessage Struct
162 
163 struct ConsoleMessage {
ConsoleMessageWebCore::ConsoleMessage164     ConsoleMessage(MessageSource s, MessageLevel l, const String& m, unsigned li, const String& u, unsigned g)
165         : source(s)
166         , level(l)
167         , message(m)
168         , line(li)
169         , url(u)
170         , groupLevel(g)
171         , repeatCount(1)
172     {
173     }
174 
ConsoleMessageWebCore::ConsoleMessage175     ConsoleMessage(MessageSource s, MessageLevel l, ScriptCallStack* callStack, unsigned g, bool storeTrace = false)
176         : source(s)
177         , level(l)
178         , wrappedArguments(callStack->at(0).argumentCount())
179         , frames(storeTrace ? callStack->size() : 0)
180         , groupLevel(g)
181         , repeatCount(1)
182     {
183         const ScriptCallFrame& lastCaller = callStack->at(0);
184         line = lastCaller.lineNumber();
185         url = lastCaller.sourceURL().string();
186 
187         // FIXME: For now, just store function names as strings.
188         // As ScriptCallStack start storing line number and source URL for all
189         // frames, refactor to use that, as well.
190         if (storeTrace) {
191             unsigned stackSize = callStack->size();
192             for (unsigned i = 0; i < stackSize; ++i)
193                 frames[i] = callStack->at(i).functionName();
194         }
195 
196         JSLock lock(false);
197 
198         for (unsigned i = 0; i < lastCaller.argumentCount(); ++i)
199             wrappedArguments[i] = JSInspectedObjectWrapper::wrap(callStack->state(), lastCaller.argumentAt(i).jsValue());
200     }
201 
isEqualWebCore::ConsoleMessage202     bool isEqual(ExecState* exec, ConsoleMessage* msg) const
203     {
204         if (msg->wrappedArguments.size() != this->wrappedArguments.size() ||
205            (!exec && msg->wrappedArguments.size()))
206             return false;
207 
208         for (size_t i = 0; i < msg->wrappedArguments.size(); ++i) {
209             ASSERT_ARG(exec, exec);
210             if (!JSValueIsEqual(toRef(exec), toRef(msg->wrappedArguments[i].get()), toRef(this->wrappedArguments[i].get()), 0))
211                 return false;
212         }
213 
214         size_t frameCount = msg->frames.size();
215         if (frameCount != this->frames.size())
216             return false;
217 
218         for (size_t i = 0; i < frameCount; ++i) {
219             const ScriptString& myFrameFunctionName = this->frames[i];
220             if (myFrameFunctionName != msg->frames[i])
221                 return false;
222         }
223 
224         return msg->source == this->source
225             && msg->level == this->level
226             && msg->message == this->message
227             && msg->line == this->line
228             && msg->url == this->url
229             && msg->groupLevel == this->groupLevel;
230     }
231 
232     MessageSource source;
233     MessageLevel level;
234     String message;
235     Vector<ProtectedJSValuePtr> wrappedArguments;
236     Vector<ScriptString> frames;
237     unsigned line;
238     String url;
239     unsigned groupLevel;
240     unsigned repeatCount;
241 };
242 
243 // XMLHttpRequestResource Class
244 
245 struct XMLHttpRequestResource {
XMLHttpRequestResourceWebCore::XMLHttpRequestResource246     XMLHttpRequestResource(const JSC::UString& sourceString)
247     {
248         JSC::JSLock lock(false);
249         this->sourceString = sourceString.rep();
250     }
251 
~XMLHttpRequestResourceWebCore::XMLHttpRequestResource252     ~XMLHttpRequestResource()
253     {
254         JSC::JSLock lock(false);
255         sourceString.clear();
256     }
257 
258     RefPtr<JSC::UString::Rep> sourceString;
259 };
260 
261 // InspectorResource Struct
262 
263 struct InspectorResource : public RefCounted<InspectorResource> {
264     // Keep these in sync with WebInspector.Resource.Type
265     enum Type {
266         Doc,
267         Stylesheet,
268         Image,
269         Font,
270         Script,
271         XHR,
272         Media,
273         Other
274     };
275 
createWebCore::InspectorResource276     static PassRefPtr<InspectorResource> create(long long identifier, DocumentLoader* documentLoader, Frame* frame)
277     {
278         return adoptRef(new InspectorResource(identifier, documentLoader, frame));
279     }
280 
~InspectorResourceWebCore::InspectorResource281     ~InspectorResource()
282     {
283         setScriptObject(0, 0);
284     }
285 
typeWebCore::InspectorResource286     Type type() const
287     {
288         if (xmlHttpRequestResource)
289             return XHR;
290 
291         if (requestURL == loader->requestURL())
292             return Doc;
293 
294         if (loader->frameLoader() && requestURL == loader->frameLoader()->iconURL())
295             return Image;
296 
297         CachedResource* cachedResource = frame->document()->docLoader()->cachedResource(requestURL.string());
298         if (!cachedResource)
299             return Other;
300 
301         switch (cachedResource->type()) {
302             case CachedResource::ImageResource:
303                 return Image;
304             case CachedResource::FontResource:
305                 return Font;
306             case CachedResource::CSSStyleSheet:
307 #if ENABLE(XSLT)
308             case CachedResource::XSLStyleSheet:
309 #endif
310                 return Stylesheet;
311             case CachedResource::Script:
312                 return Script;
313             default:
314                 return Other;
315         }
316     }
317 
setScriptObjectWebCore::InspectorResource318     void setScriptObject(JSContextRef context, JSObjectRef newScriptObject)
319     {
320         if (scriptContext && scriptObject)
321             JSValueUnprotect(scriptContext, scriptObject);
322 
323         scriptObject = newScriptObject;
324         scriptContext = context;
325 
326         ASSERT((context && newScriptObject) || (!context && !newScriptObject));
327         if (context && newScriptObject)
328             JSValueProtect(context, newScriptObject);
329     }
330 
setXMLHttpRequestPropertiesWebCore::InspectorResource331     void setXMLHttpRequestProperties(const JSC::UString& data)
332     {
333         xmlHttpRequestResource.set(new XMLHttpRequestResource(data));
334     }
335 
sourceStringWebCore::InspectorResource336     String sourceString() const
337      {
338          if (xmlHttpRequestResource)
339             return JSC::UString(xmlHttpRequestResource->sourceString);
340 
341         RefPtr<SharedBuffer> buffer;
342         String textEncodingName;
343 
344         if (requestURL == loader->requestURL()) {
345             buffer = loader->mainResourceData();
346             textEncodingName = frame->document()->inputEncoding();
347         } else {
348             CachedResource* cachedResource = frame->document()->docLoader()->cachedResource(requestURL.string());
349             if (!cachedResource)
350                 return String();
351 
352             if (cachedResource->isPurgeable()) {
353                 // If the resource is purgeable then make it unpurgeable to get
354                 // get its data. This might fail, in which case we return an
355                 // empty String.
356                 // FIXME: should we do something else in the case of a purged
357                 // resource that informs the user why there is no data in the
358                 // inspector?
359                 if (!cachedResource->makePurgeable(false))
360                     return String();
361             }
362 
363             buffer = cachedResource->data();
364             textEncodingName = cachedResource->encoding();
365         }
366 
367         if (!buffer)
368             return String();
369 
370         TextEncoding encoding(textEncodingName);
371         if (!encoding.isValid())
372             encoding = WindowsLatin1Encoding();
373         return encoding.decode(buffer->data(), buffer->size());
374      }
375 
376     long long identifier;
377     RefPtr<DocumentLoader> loader;
378     RefPtr<Frame> frame;
379     OwnPtr<XMLHttpRequestResource> xmlHttpRequestResource;
380     KURL requestURL;
381     HTTPHeaderMap requestHeaderFields;
382     HTTPHeaderMap responseHeaderFields;
383     String mimeType;
384     String suggestedFilename;
385     JSContextRef scriptContext;
386     JSObjectRef scriptObject;
387     long long expectedContentLength;
388     bool cached;
389     bool finished;
390     bool failed;
391     int length;
392     int responseStatusCode;
393     double startTime;
394     double responseReceivedTime;
395     double endTime;
396 
397 protected:
InspectorResourceWebCore::InspectorResource398     InspectorResource(long long identifier, DocumentLoader* documentLoader, Frame* frame)
399         : identifier(identifier)
400         , loader(documentLoader)
401         , frame(frame)
402         , xmlHttpRequestResource(0)
403         , scriptContext(0)
404         , scriptObject(0)
405         , expectedContentLength(0)
406         , cached(false)
407         , finished(false)
408         , failed(false)
409         , length(0)
410         , responseStatusCode(0)
411         , startTime(-1.0)
412         , responseReceivedTime(-1.0)
413         , endTime(-1.0)
414     {
415     }
416 };
417 
418 // InspectorDatabaseResource Struct
419 
420 #if ENABLE(DATABASE)
421 struct InspectorDatabaseResource : public RefCounted<InspectorDatabaseResource> {
createWebCore::InspectorDatabaseResource422     static PassRefPtr<InspectorDatabaseResource> create(Database* database, const String& domain, const String& name, const String& version)
423     {
424         return adoptRef(new InspectorDatabaseResource(database, domain, name, version));
425     }
426 
setScriptObjectWebCore::InspectorDatabaseResource427     void setScriptObject(JSContextRef context, JSObjectRef newScriptObject)
428     {
429         if (scriptContext && scriptObject)
430             JSValueUnprotect(scriptContext, scriptObject);
431 
432         scriptObject = newScriptObject;
433         scriptContext = context;
434 
435         ASSERT((context && newScriptObject) || (!context && !newScriptObject));
436         if (context && newScriptObject)
437             JSValueProtect(context, newScriptObject);
438     }
439 
440     RefPtr<Database> database;
441     String domain;
442     String name;
443     String version;
444     JSContextRef scriptContext;
445     JSObjectRef scriptObject;
446 
447 private:
InspectorDatabaseResourceWebCore::InspectorDatabaseResource448     InspectorDatabaseResource(Database* database, const String& domain, const String& name, const String& version)
449         : database(database)
450         , domain(domain)
451         , name(name)
452         , version(version)
453         , scriptContext(0)
454         , scriptObject(0)
455     {
456     }
457 };
458 #endif
459 
460 // JavaScript Callbacks
461 
462 #define SIMPLE_INSPECTOR_CALLBACK(jsFunction, inspectorControllerMethod) \
463 static JSValueRef jsFunction(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*) \
464 { \
465     if (InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject))) \
466         controller->inspectorControllerMethod(); \
467     return JSValueMakeUndefined(ctx); \
468 }
469 
470 SIMPLE_INSPECTOR_CALLBACK(hideDOMNodeHighlight, hideHighlight);
471 SIMPLE_INSPECTOR_CALLBACK(loaded, scriptObjectReady);
472 SIMPLE_INSPECTOR_CALLBACK(unloading, close);
473 SIMPLE_INSPECTOR_CALLBACK(attach, attachWindow);
474 SIMPLE_INSPECTOR_CALLBACK(detach, detachWindow);
475 #if ENABLE(JAVASCRIPT_DEBUGGER)
476 SIMPLE_INSPECTOR_CALLBACK(enableDebugger, enableDebugger);
477 SIMPLE_INSPECTOR_CALLBACK(disableDebugger, disableDebugger);
478 SIMPLE_INSPECTOR_CALLBACK(pauseInDebugger, pauseInDebugger);
479 SIMPLE_INSPECTOR_CALLBACK(resumeDebugger, resumeDebugger);
480 SIMPLE_INSPECTOR_CALLBACK(stepOverStatementInDebugger, stepOverStatementInDebugger);
481 SIMPLE_INSPECTOR_CALLBACK(stepIntoStatementInDebugger, stepIntoStatementInDebugger);
482 SIMPLE_INSPECTOR_CALLBACK(stepOutOfFunctionInDebugger, stepOutOfFunctionInDebugger);
483 #endif
484 SIMPLE_INSPECTOR_CALLBACK(closeWindow, closeWindow);
485 SIMPLE_INSPECTOR_CALLBACK(clearMessages, clearConsoleMessages);
486 SIMPLE_INSPECTOR_CALLBACK(startProfiling, startUserInitiatedProfilingSoon);
487 SIMPLE_INSPECTOR_CALLBACK(stopProfiling, stopUserInitiatedProfiling);
488 SIMPLE_INSPECTOR_CALLBACK(enableProfiler, enableProfiler);
489 SIMPLE_INSPECTOR_CALLBACK(disableProfiler, disableProfiler);
490 SIMPLE_INSPECTOR_CALLBACK(toggleNodeSearch, toggleSearchForNodeInPage);
491 
492 #define BOOL_INSPECTOR_CALLBACK(jsFunction, inspectorControllerMethod) \
493 static JSValueRef jsFunction(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*) \
494 { \
495     if (InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject))) \
496         return JSValueMakeBoolean(ctx, controller->inspectorControllerMethod()); \
497     return JSValueMakeUndefined(ctx); \
498 }
499 
500 #if ENABLE(JAVASCRIPT_DEBUGGER)
501 BOOL_INSPECTOR_CALLBACK(debuggerEnabled, debuggerEnabled);
502 BOOL_INSPECTOR_CALLBACK(pauseOnExceptions, pauseOnExceptions);
503 #endif
504 BOOL_INSPECTOR_CALLBACK(profilerEnabled, profilerEnabled);
505 BOOL_INSPECTOR_CALLBACK(isWindowVisible, windowVisible);
506 BOOL_INSPECTOR_CALLBACK(searchingForNode, searchingForNodeInPage);
507 
addSourceToFrame(const String & mimeType,const String & source,Node * frameNode)508 static bool addSourceToFrame(const String& mimeType, const String& source, Node* frameNode)
509 {
510     ASSERT_ARG(frameNode, frameNode);
511 
512     if (!frameNode)
513         return false;
514 
515     if (!frameNode->attached()) {
516         ASSERT_NOT_REACHED();
517         return false;
518     }
519 
520     ASSERT(frameNode->isElementNode());
521     if (!frameNode->isElementNode())
522         return false;
523 
524     Element* element = static_cast<Element*>(frameNode);
525     ASSERT(element->isFrameOwnerElement());
526     if (!element->isFrameOwnerElement())
527         return false;
528 
529     HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(element);
530     ASSERT(frameOwner->contentFrame());
531     if (!frameOwner->contentFrame())
532         return false;
533 
534     FrameLoader* loader = frameOwner->contentFrame()->loader();
535 
536     loader->setResponseMIMEType(mimeType);
537     loader->begin();
538     loader->write(source);
539     loader->end();
540 
541     return true;
542 }
543 
addResourceSourceToFrame(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)544 static JSValueRef addResourceSourceToFrame(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
545 {
546     JSValueRef undefined = JSValueMakeUndefined(ctx);
547 
548     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
549     if (argumentCount < 2 || !controller)
550         return undefined;
551 
552     JSValueRef identifierValue = arguments[0];
553     if (!JSValueIsNumber(ctx, identifierValue))
554         return undefined;
555 
556     long long identifier = static_cast<long long>(JSValueToNumber(ctx, identifierValue, exception));
557     if (exception && *exception)
558         return undefined;
559 
560     RefPtr<InspectorResource> resource = controller->resources().get(identifier);
561     ASSERT(resource);
562     if (!resource)
563         return undefined;
564 
565     String sourceString = resource->sourceString();
566     if (sourceString.isEmpty())
567         return undefined;
568 
569     bool successfullyAddedSource = addSourceToFrame(resource->mimeType, sourceString, toNode(toJS(arguments[1])));
570     return JSValueMakeBoolean(ctx, successfullyAddedSource);
571 }
572 
addSourceToFrame(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)573 static JSValueRef addSourceToFrame(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
574 {
575     JSValueRef undefined = JSValueMakeUndefined(ctx);
576 
577     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
578     if (argumentCount < 3 || !controller)
579         return undefined;
580 
581     JSValueRef mimeTypeValue = arguments[0];
582     if (!JSValueIsString(ctx, mimeTypeValue))
583         return undefined;
584 
585     JSValueRef sourceValue = arguments[1];
586     if (!JSValueIsString(ctx, sourceValue))
587         return undefined;
588 
589     String mimeType = toString(ctx, mimeTypeValue, exception);
590     if (mimeType.isEmpty())
591         return undefined;
592 
593     String source = toString(ctx, sourceValue, exception);
594     if (source.isEmpty())
595         return undefined;
596 
597     bool successfullyAddedSource = addSourceToFrame(mimeType, source, toNode(toJS(arguments[2])));
598     return JSValueMakeBoolean(ctx, successfullyAddedSource);
599 }
600 
getResourceDocumentNode(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)601 static JSValueRef getResourceDocumentNode(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
602 {
603     JSValueRef undefined = JSValueMakeUndefined(ctx);
604 
605     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
606     if (!argumentCount || argumentCount > 1 || !controller)
607         return undefined;
608 
609     JSValueRef identifierValue = arguments[0];
610     if (!JSValueIsNumber(ctx, identifierValue))
611         return undefined;
612 
613     long long identifier = static_cast<long long>(JSValueToNumber(ctx, identifierValue, exception));
614     if (exception && *exception)
615         return undefined;
616 
617     RefPtr<InspectorResource> resource = controller->resources().get(identifier);
618     ASSERT(resource);
619     if (!resource)
620         return undefined;
621 
622     Frame* frame = resource->frame.get();
623 
624     Document* document = frame->document();
625     if (!document)
626         return undefined;
627 
628     if (document->isPluginDocument() || document->isImageDocument() || document->isMediaDocument())
629         return undefined;
630 
631     ExecState* exec = toJSDOMWindowShell(resource->frame.get())->window()->globalExec();
632 
633     JSC::JSLock lock(false);
634     JSValueRef documentValue = toRef(JSInspectedObjectWrapper::wrap(exec, toJS(exec, document)));
635     return documentValue;
636 }
637 
highlightDOMNode(JSContextRef context,JSObjectRef,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef *)638 static JSValueRef highlightDOMNode(JSContextRef context, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
639 {
640     JSValueRef undefined = JSValueMakeUndefined(context);
641 
642     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
643     if (argumentCount < 1 || !controller)
644         return undefined;
645 
646     JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(toJS(arguments[0]));
647     if (!wrapper)
648         return undefined;
649     Node* node = toNode(wrapper->unwrappedObject());
650     if (!node)
651         return undefined;
652 
653     controller->highlight(node);
654 
655     return undefined;
656 }
657 
search(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)658 static JSValueRef search(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
659 {
660     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
661     if (!controller)
662         return JSValueMakeUndefined(ctx);
663 
664     if (argumentCount < 2 || !JSValueIsString(ctx, arguments[1]))
665         return JSValueMakeUndefined(ctx);
666 
667     Node* node = toNode(toJS(arguments[0]));
668     if (!node)
669         return JSValueMakeUndefined(ctx);
670 
671     String target = toString(ctx, arguments[1], exception);
672 
673     JSObjectRef global = JSContextGetGlobalObject(ctx);
674 
675     JSValueRef arrayProperty = JSObjectGetProperty(ctx, global, jsStringRef("Array").get(), exception);
676     if (exception && *exception)
677         return JSValueMakeUndefined(ctx);
678 
679     JSObjectRef arrayConstructor = JSValueToObject(ctx, arrayProperty, exception);
680     if (exception && *exception)
681         return JSValueMakeUndefined(ctx);
682 
683     JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, exception);
684     if (exception && *exception)
685         return JSValueMakeUndefined(ctx);
686 
687     JSValueRef pushProperty = JSObjectGetProperty(ctx, result, jsStringRef("push").get(), exception);
688     if (exception && *exception)
689         return JSValueMakeUndefined(ctx);
690 
691     JSObjectRef pushFunction = JSValueToObject(ctx, pushProperty, exception);
692     if (exception && *exception)
693         return JSValueMakeUndefined(ctx);
694 
695     RefPtr<Range> searchRange(rangeOfContents(node));
696 
697     ExceptionCode ec = 0;
698     do {
699         RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, false));
700         if (resultRange->collapsed(ec))
701             break;
702 
703         // A non-collapsed result range can in some funky whitespace cases still not
704         // advance the range's start position (4509328). Break to avoid infinite loop.
705         VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
706         if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
707             break;
708 
709         JSC::JSLock lock(false);
710         JSValueRef arg0 = toRef(toJS(toJS(ctx), resultRange.get()));
711         JSObjectCallAsFunction(ctx, pushFunction, result, 1, &arg0, exception);
712         if (exception && *exception)
713             return JSValueMakeUndefined(ctx);
714 
715         setStart(searchRange.get(), newStart);
716     } while (true);
717 
718     return result;
719 }
720 
721 #if ENABLE(DATABASE)
databaseTableNames(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)722 static JSValueRef databaseTableNames(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
723 {
724     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
725     if (!controller)
726         return JSValueMakeUndefined(ctx);
727 
728     if (argumentCount < 1)
729         return JSValueMakeUndefined(ctx);
730 
731     JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(toJS(arguments[0]));
732     if (!wrapper)
733         return JSValueMakeUndefined(ctx);
734 
735     Database* database = toDatabase(wrapper->unwrappedObject());
736     if (!database)
737         return JSValueMakeUndefined(ctx);
738 
739     JSObjectRef global = JSContextGetGlobalObject(ctx);
740 
741     JSValueRef arrayProperty = JSObjectGetProperty(ctx, global, jsStringRef("Array").get(), exception);
742     if (exception && *exception)
743         return JSValueMakeUndefined(ctx);
744 
745     JSObjectRef arrayConstructor = JSValueToObject(ctx, arrayProperty, exception);
746     if (exception && *exception)
747         return JSValueMakeUndefined(ctx);
748 
749     JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, exception);
750     if (exception && *exception)
751         return JSValueMakeUndefined(ctx);
752 
753     JSValueRef pushProperty = JSObjectGetProperty(ctx, result, jsStringRef("push").get(), exception);
754     if (exception && *exception)
755         return JSValueMakeUndefined(ctx);
756 
757     JSObjectRef pushFunction = JSValueToObject(ctx, pushProperty, exception);
758     if (exception && *exception)
759         return JSValueMakeUndefined(ctx);
760 
761     Vector<String> tableNames = database->tableNames();
762     unsigned length = tableNames.size();
763     for (unsigned i = 0; i < length; ++i) {
764         String tableName = tableNames[i];
765         JSValueRef tableNameValue = JSValueMakeString(ctx, jsStringRef(tableName).get());
766 
767         JSValueRef pushArguments[] = { tableNameValue };
768         JSObjectCallAsFunction(ctx, pushFunction, result, 1, pushArguments, exception);
769         if (exception && *exception)
770             return JSValueMakeUndefined(ctx);
771     }
772 
773     return result;
774 }
775 #endif
776 
inspectedWindow(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t,const JSValueRef[],JSValueRef *)777 static JSValueRef inspectedWindow(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
778 {
779     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
780     if (!controller)
781         return JSValueMakeUndefined(ctx);
782 
783     JSDOMWindow* inspectedWindow = toJSDOMWindow(controller->inspectedPage()->mainFrame());
784     JSLock lock(false);
785     return toRef(JSInspectedObjectWrapper::wrap(inspectedWindow->globalExec(), inspectedWindow));
786 }
787 
setting(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t,const JSValueRef arguments[],JSValueRef * exception)788 static JSValueRef setting(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef arguments[], JSValueRef* exception)
789 {
790     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
791     if (!controller)
792         return JSValueMakeUndefined(ctx);
793 
794     JSValueRef keyValue = arguments[0];
795     if (!JSValueIsString(ctx, keyValue))
796         return JSValueMakeUndefined(ctx);
797 
798     const InspectorController::Setting& setting = controller->setting(toString(ctx, keyValue, exception));
799 
800     switch (setting.type()) {
801         default:
802         case InspectorController::Setting::NoType:
803             return JSValueMakeUndefined(ctx);
804         case InspectorController::Setting::StringType:
805             return JSValueMakeString(ctx, jsStringRef(setting.string()).get());
806         case InspectorController::Setting::DoubleType:
807             return JSValueMakeNumber(ctx, setting.doubleValue());
808         case InspectorController::Setting::IntegerType:
809             return JSValueMakeNumber(ctx, setting.integerValue());
810         case InspectorController::Setting::BooleanType:
811             return JSValueMakeBoolean(ctx, setting.booleanValue());
812         case InspectorController::Setting::StringVectorType: {
813             Vector<JSValueRef> stringValues;
814             const Vector<String>& strings = setting.stringVector();
815             const unsigned length = strings.size();
816             for (unsigned i = 0; i < length; ++i)
817                 stringValues.append(JSValueMakeString(ctx, jsStringRef(strings[i]).get()));
818 
819             JSObjectRef stringsArray = JSObjectMakeArray(ctx, stringValues.size(), stringValues.data(), exception);
820             if (exception && *exception)
821                 return JSValueMakeUndefined(ctx);
822             return stringsArray;
823         }
824     }
825 }
826 
setSetting(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t,const JSValueRef arguments[],JSValueRef * exception)827 static JSValueRef setSetting(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef arguments[], JSValueRef* exception)
828 {
829     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
830     if (!controller)
831         return JSValueMakeUndefined(ctx);
832 
833     JSValueRef keyValue = arguments[0];
834     if (!JSValueIsString(ctx, keyValue))
835         return JSValueMakeUndefined(ctx);
836 
837     InspectorController::Setting setting;
838 
839     JSValueRef value = arguments[1];
840     switch (JSValueGetType(ctx, value)) {
841         default:
842         case kJSTypeUndefined:
843         case kJSTypeNull:
844             // Do nothing. The setting is already NoType.
845             ASSERT(setting.type() == InspectorController::Setting::NoType);
846             break;
847         case kJSTypeString:
848             setting.set(toString(ctx, value, exception));
849             break;
850         case kJSTypeNumber:
851             setting.set(JSValueToNumber(ctx, value, exception));
852             break;
853         case kJSTypeBoolean:
854             setting.set(JSValueToBoolean(ctx, value));
855             break;
856         case kJSTypeObject: {
857             JSObjectRef object = JSValueToObject(ctx, value, 0);
858             JSValueRef lengthValue = JSObjectGetProperty(ctx, object, jsStringRef("length").get(), exception);
859             if (exception && *exception)
860                 return JSValueMakeUndefined(ctx);
861 
862             Vector<String> strings;
863             const unsigned length = static_cast<unsigned>(JSValueToNumber(ctx, lengthValue, 0));
864             for (unsigned i = 0; i < length; ++i) {
865                 JSValueRef itemValue = JSObjectGetPropertyAtIndex(ctx, object, i, exception);
866                 if (exception && *exception)
867                     return JSValueMakeUndefined(ctx);
868                 strings.append(toString(ctx, itemValue, exception));
869                 if (exception && *exception)
870                     return JSValueMakeUndefined(ctx);
871             }
872 
873             setting.set(strings);
874             break;
875         }
876     }
877 
878     if (exception && *exception)
879         return JSValueMakeUndefined(ctx);
880 
881     controller->setSetting(toString(ctx, keyValue, exception), setting);
882 
883     return JSValueMakeUndefined(ctx);
884 }
885 
localizedStrings(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t,const JSValueRef[],JSValueRef *)886 static JSValueRef localizedStrings(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
887 {
888     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
889     if (!controller)
890         return JSValueMakeUndefined(ctx);
891 
892     String url = controller->localizedStringsURL();
893     if (url.isNull())
894         return JSValueMakeNull(ctx);
895 
896     return JSValueMakeString(ctx, jsStringRef(url).get());
897 }
898 
platform(JSContextRef ctx,JSObjectRef,JSObjectRef,size_t,const JSValueRef[],JSValueRef *)899 static JSValueRef platform(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef /*thisObject*/, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
900 {
901 #if PLATFORM(MAC)
902 #ifdef BUILDING_ON_TIGER
903     DEFINE_STATIC_LOCAL(const String, platform, ("mac-tiger"));
904 #else
905     DEFINE_STATIC_LOCAL(const String, platform, ("mac-leopard"));
906 #endif
907 #elif PLATFORM(WIN_OS)
908     DEFINE_STATIC_LOCAL(const String, platform, ("windows"));
909 #elif PLATFORM(QT)
910     DEFINE_STATIC_LOCAL(const String, platform, ("qt"));
911 #elif PLATFORM(GTK)
912     DEFINE_STATIC_LOCAL(const String, platform, ("gtk"));
913 #elif PLATFORM(WX)
914     DEFINE_STATIC_LOCAL(const String, platform, ("wx"));
915 #else
916     DEFINE_STATIC_LOCAL(const String, platform, ("unknown"));
917 #endif
918 
919     JSValueRef platformValue = JSValueMakeString(ctx, jsStringRef(platform).get());
920 
921     return platformValue;
922 }
923 
moveByUnrestricted(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)924 static JSValueRef moveByUnrestricted(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
925 {
926     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
927     if (!controller)
928         return JSValueMakeUndefined(ctx);
929 
930     if (argumentCount < 2)
931         return JSValueMakeUndefined(ctx);
932 
933     double x = JSValueToNumber(ctx, arguments[0], exception);
934     if (exception && *exception)
935         return JSValueMakeUndefined(ctx);
936 
937     double y = JSValueToNumber(ctx, arguments[1], exception);
938     if (exception && *exception)
939         return JSValueMakeUndefined(ctx);
940 
941     controller->moveWindowBy(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y));
942 
943     return JSValueMakeUndefined(ctx);
944 }
945 
setAttachedWindowHeight(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)946 static JSValueRef setAttachedWindowHeight(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
947 {
948     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
949     if (!controller)
950         return JSValueMakeUndefined(ctx);
951 
952     if (argumentCount < 1)
953         return JSValueMakeUndefined(ctx);
954 
955     unsigned height = static_cast<unsigned>(JSValueToNumber(ctx, arguments[0], exception));
956     if (exception && *exception)
957         return JSValueMakeUndefined(ctx);
958 
959     controller->setAttachedWindowHeight(height);
960 
961     return JSValueMakeUndefined(ctx);
962 }
963 
wrapCallback(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef *)964 static JSValueRef wrapCallback(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
965 {
966     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
967     if (!controller)
968         return JSValueMakeUndefined(ctx);
969 
970     if (argumentCount < 1)
971         return JSValueMakeUndefined(ctx);
972 
973     JSLock lock(false);
974     return toRef(JSInspectorCallbackWrapper::wrap(toJS(ctx), toJS(arguments[0])));
975 }
976 
977 #if ENABLE(JAVASCRIPT_DEBUGGER)
currentCallFrame(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t,const JSValueRef[],JSValueRef *)978 static JSValueRef currentCallFrame(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* /*exception*/)
979 {
980     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
981     if (!controller)
982         return JSValueMakeUndefined(ctx);
983 
984     JavaScriptCallFrame* callFrame = controller->currentCallFrame();
985     if (!callFrame || !callFrame->isValid())
986         return JSValueMakeNull(ctx);
987 
988     ExecState* globalExec = callFrame->scopeChain()->globalObject()->globalExec();
989 
990     JSLock lock(false);
991     return toRef(JSInspectedObjectWrapper::wrap(globalExec, toJS(toJS(ctx), callFrame)));
992 }
993 
setPauseOnExceptions(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef *)994 static JSValueRef setPauseOnExceptions(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
995 {
996     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
997     if (!controller)
998         return JSValueMakeUndefined(ctx);
999 
1000     if (argumentCount < 1)
1001         return JSValueMakeUndefined(ctx);
1002 
1003     controller->setPauseOnExceptions(JSValueToBoolean(ctx, arguments[0]));
1004 
1005     return JSValueMakeUndefined(ctx);
1006 }
1007 
addBreakpoint(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)1008 static JSValueRef addBreakpoint(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
1009 {
1010     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
1011     if (!controller)
1012         return JSValueMakeUndefined(ctx);
1013 
1014     if (argumentCount < 2)
1015         return JSValueMakeUndefined(ctx);
1016 
1017     double sourceID = JSValueToNumber(ctx, arguments[0], exception);
1018     if (exception && *exception)
1019         return JSValueMakeUndefined(ctx);
1020 
1021     double lineNumber = JSValueToNumber(ctx, arguments[1], exception);
1022     if (exception && *exception)
1023         return JSValueMakeUndefined(ctx);
1024 
1025     controller->addBreakpoint(static_cast<int>(sourceID), static_cast<unsigned>(lineNumber));
1026 
1027     return JSValueMakeUndefined(ctx);
1028 }
1029 
removeBreakpoint(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)1030 static JSValueRef removeBreakpoint(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
1031 {
1032     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
1033     if (!controller)
1034         return JSValueMakeUndefined(ctx);
1035 
1036     if (argumentCount < 2)
1037         return JSValueMakeUndefined(ctx);
1038 
1039     double sourceID = JSValueToNumber(ctx, arguments[0], exception);
1040     if (exception && *exception)
1041         return JSValueMakeUndefined(ctx);
1042 
1043     double lineNumber = JSValueToNumber(ctx, arguments[1], exception);
1044     if (exception && *exception)
1045         return JSValueMakeUndefined(ctx);
1046 
1047     controller->removeBreakpoint(static_cast<int>(sourceID), static_cast<unsigned>(lineNumber));
1048 
1049     return JSValueMakeUndefined(ctx);
1050 }
1051 #endif
1052 
profiles(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t,const JSValueRef[],JSValueRef * exception)1053 static JSValueRef profiles(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* exception)
1054 {
1055     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
1056     if (!controller)
1057         return JSValueMakeUndefined(ctx);
1058 
1059     JSLock lock(false);
1060 
1061     const Vector<RefPtr<Profile> >& profiles = controller->profiles();
1062 
1063     JSObjectRef global = JSContextGetGlobalObject(ctx);
1064 
1065     JSValueRef arrayProperty = JSObjectGetProperty(ctx, global, jsStringRef("Array").get(), exception);
1066     if (exception && *exception)
1067         return JSValueMakeUndefined(ctx);
1068 
1069     JSObjectRef arrayConstructor = JSValueToObject(ctx, arrayProperty, exception);
1070     if (exception && *exception)
1071         return JSValueMakeUndefined(ctx);
1072 
1073     JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, exception);
1074     if (exception && *exception)
1075         return JSValueMakeUndefined(ctx);
1076 
1077     JSValueRef pushProperty = JSObjectGetProperty(ctx, result, jsStringRef("push").get(), exception);
1078     if (exception && *exception)
1079         return JSValueMakeUndefined(ctx);
1080 
1081     JSObjectRef pushFunction = JSValueToObject(ctx, pushProperty, exception);
1082     if (exception && *exception)
1083         return JSValueMakeUndefined(ctx);
1084 
1085     for (size_t i = 0; i < profiles.size(); ++i) {
1086         JSValueRef arg0 = toRef(toJS(toJS(ctx), profiles[i].get()));
1087         JSObjectCallAsFunction(ctx, pushFunction, result, 1, &arg0, exception);
1088         if (exception && *exception)
1089             return JSValueMakeUndefined(ctx);
1090     }
1091 
1092     return result;
1093 }
1094 
1095 // InspectorController Class
1096 
1097 static unsigned s_inspectorControllerCount;
1098 static HashMap<String, InspectorController::Setting*>* s_settingCache;
1099 
InspectorController(Page * page,InspectorClient * client)1100 InspectorController::InspectorController(Page* page, InspectorClient* client)
1101     : m_inspectedPage(page)
1102     , m_client(client)
1103     , m_page(0)
1104     , m_scriptObject(0)
1105     , m_controllerScriptObject(0)
1106     , m_scriptContext(0)
1107     , m_windowVisible(false)
1108 #if ENABLE(JAVASCRIPT_DEBUGGER)
1109     , m_debuggerEnabled(false)
1110     , m_attachDebuggerWhenShown(false)
1111 #endif
1112     , m_profilerEnabled(false)
1113     , m_recordingUserInitiatedProfile(false)
1114     , m_showAfterVisible(ElementsPanel)
1115     , m_nextIdentifier(-2)
1116     , m_groupLevel(0)
1117     , m_searchingForNode(false)
1118     , m_currentUserInitiatedProfileNumber(-1)
1119     , m_nextUserInitiatedProfileNumber(1)
1120     , m_previousMessage(0)
1121     , m_startProfiling(this, &InspectorController::startUserInitiatedProfiling)
1122 {
1123     ASSERT_ARG(page, page);
1124     ASSERT_ARG(client, client);
1125     ++s_inspectorControllerCount;
1126 }
1127 
~InspectorController()1128 InspectorController::~InspectorController()
1129 {
1130     m_client->inspectorDestroyed();
1131 
1132     if (m_scriptContext) {
1133         JSValueRef exception = 0;
1134 
1135         JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
1136         JSValueRef controllerProperty = JSObjectGetProperty(m_scriptContext, global, jsStringRef("InspectorController").get(), &exception);
1137         if (!HANDLE_EXCEPTION(m_scriptContext, exception)) {
1138             if (JSObjectRef controller = JSValueToObject(m_scriptContext, controllerProperty, &exception)) {
1139                 if (!HANDLE_EXCEPTION(m_scriptContext, exception))
1140                     JSObjectSetPrivate(controller, 0);
1141             }
1142         }
1143     }
1144 
1145     if (m_page)
1146         m_page->setParentInspectorController(0);
1147 
1148     // m_inspectedPage should have been cleared in inspectedPageDestroyed().
1149     ASSERT(!m_inspectedPage);
1150 
1151     deleteAllValues(m_frameResources);
1152     deleteAllValues(m_consoleMessages);
1153 
1154     ASSERT(s_inspectorControllerCount);
1155     --s_inspectorControllerCount;
1156 
1157     if (!s_inspectorControllerCount && s_settingCache) {
1158         deleteAllValues(*s_settingCache);
1159         delete s_settingCache;
1160         s_settingCache = 0;
1161     }
1162 }
1163 
inspectedPageDestroyed()1164 void InspectorController::inspectedPageDestroyed()
1165 {
1166     close();
1167 
1168     ASSERT(m_inspectedPage);
1169     m_inspectedPage = 0;
1170 }
1171 
enabled() const1172 bool InspectorController::enabled() const
1173 {
1174     if (!m_inspectedPage)
1175         return false;
1176     return m_inspectedPage->settings()->developerExtrasEnabled();
1177 }
1178 
setting(const String & key) const1179 const InspectorController::Setting& InspectorController::setting(const String& key) const
1180 {
1181     if (!s_settingCache)
1182         s_settingCache = new HashMap<String, Setting*>;
1183 
1184     if (Setting* cachedSetting = s_settingCache->get(key))
1185         return *cachedSetting;
1186 
1187     Setting* newSetting = new Setting;
1188     s_settingCache->set(key, newSetting);
1189 
1190     m_client->populateSetting(key, *newSetting);
1191 
1192     return *newSetting;
1193 }
1194 
setSetting(const String & key,const Setting & setting)1195 void InspectorController::setSetting(const String& key, const Setting& setting)
1196 {
1197     if (setting.type() == Setting::NoType) {
1198         if (s_settingCache) {
1199             Setting* cachedSetting = s_settingCache->get(key);
1200             if (cachedSetting) {
1201                 s_settingCache->remove(key);
1202                 delete cachedSetting;
1203             }
1204         }
1205 
1206         m_client->removeSetting(key);
1207         return;
1208     }
1209 
1210     if (!s_settingCache)
1211         s_settingCache = new HashMap<String, Setting*>;
1212 
1213     if (Setting* cachedSetting = s_settingCache->get(key))
1214         *cachedSetting = setting;
1215     else
1216         s_settingCache->set(key, new Setting(setting));
1217 
1218     m_client->storeSetting(key, setting);
1219 }
1220 
localizedStringsURL()1221 String InspectorController::localizedStringsURL()
1222 {
1223     if (!enabled())
1224         return String();
1225     return m_client->localizedStringsURL();
1226 }
1227 
1228 // Trying to inspect something in a frame with JavaScript disabled would later lead to
1229 // crashes trying to create JavaScript wrappers. Some day we could fix this issue, but
1230 // for now prevent crashes here by never targeting a node in such a frame.
canPassNodeToJavaScript(Node * node)1231 static bool canPassNodeToJavaScript(Node* node)
1232 {
1233     if (!node)
1234         return false;
1235     Frame* frame = node->document()->frame();
1236     return frame && frame->script()->isEnabled();
1237 }
1238 
inspect(Node * node)1239 void InspectorController::inspect(Node* node)
1240 {
1241     if (!canPassNodeToJavaScript(node) || !enabled())
1242         return;
1243 
1244     show();
1245 
1246     if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
1247         node = node->parentNode();
1248     m_nodeToFocus = node;
1249 
1250     if (!m_scriptObject) {
1251         m_showAfterVisible = ElementsPanel;
1252         return;
1253     }
1254 
1255     if (windowVisible())
1256         focusNode();
1257 }
1258 
focusNode()1259 void InspectorController::focusNode()
1260 {
1261     if (!enabled())
1262         return;
1263 
1264     ASSERT(m_scriptContext);
1265     ASSERT(m_scriptObject);
1266     ASSERT(m_nodeToFocus);
1267 
1268     Frame* frame = m_nodeToFocus->document()->frame();
1269     if (!frame)
1270         return;
1271 
1272     ExecState* exec = toJSDOMWindow(frame)->globalExec();
1273 
1274     JSValueRef arg0;
1275 
1276     {
1277         JSC::JSLock lock(false);
1278         arg0 = toRef(JSInspectedObjectWrapper::wrap(exec, toJS(exec, m_nodeToFocus.get())));
1279     }
1280 
1281     m_nodeToFocus = 0;
1282 
1283     JSValueRef exception = 0;
1284     callFunction(m_scriptContext, m_scriptObject, "updateFocusedNode", 1, &arg0, exception);
1285 }
1286 
highlight(Node * node)1287 void InspectorController::highlight(Node* node)
1288 {
1289     if (!enabled())
1290         return;
1291     ASSERT_ARG(node, node);
1292     m_highlightedNode = node;
1293     m_client->highlight(node);
1294 }
1295 
hideHighlight()1296 void InspectorController::hideHighlight()
1297 {
1298     if (!enabled())
1299         return;
1300     m_client->hideHighlight();
1301 }
1302 
windowVisible()1303 bool InspectorController::windowVisible()
1304 {
1305     return m_windowVisible;
1306 }
1307 
setWindowVisible(bool visible,bool attached)1308 void InspectorController::setWindowVisible(bool visible, bool attached)
1309 {
1310     if (visible == m_windowVisible)
1311         return;
1312 
1313     m_windowVisible = visible;
1314 
1315     if (!m_scriptContext || !m_scriptObject)
1316         return;
1317 
1318     if (m_windowVisible) {
1319         setAttachedWindow(attached);
1320         populateScriptObjects();
1321         if (m_nodeToFocus)
1322             focusNode();
1323 #if ENABLE(JAVASCRIPT_DEBUGGER)
1324         if (m_attachDebuggerWhenShown)
1325             enableDebugger();
1326 #endif
1327         if (m_showAfterVisible != CurrentPanel)
1328             showPanel(m_showAfterVisible);
1329     } else {
1330 #if ENABLE(JAVASCRIPT_DEBUGGER)
1331         disableDebugger();
1332 #endif
1333         resetScriptObjects();
1334     }
1335 
1336     m_showAfterVisible = CurrentPanel;
1337 }
1338 
addMessageToConsole(MessageSource source,MessageLevel level,ScriptCallStack * callStack)1339 void InspectorController::addMessageToConsole(MessageSource source, MessageLevel level, ScriptCallStack* callStack)
1340 {
1341     if (!enabled())
1342         return;
1343 
1344     addConsoleMessage(callStack->state(), new ConsoleMessage(source, level, callStack, m_groupLevel, level == TraceMessageLevel));
1345 }
1346 
addMessageToConsole(MessageSource source,MessageLevel level,const String & message,unsigned lineNumber,const String & sourceID)1347 void InspectorController::addMessageToConsole(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceID)
1348 {
1349     if (!enabled())
1350         return;
1351 
1352     addConsoleMessage(0, new ConsoleMessage(source, level, message, lineNumber, sourceID, m_groupLevel));
1353 }
1354 
addConsoleMessage(ExecState * exec,ConsoleMessage * consoleMessage)1355 void InspectorController::addConsoleMessage(ExecState* exec, ConsoleMessage* consoleMessage)
1356 {
1357     ASSERT(enabled());
1358     ASSERT_ARG(consoleMessage, consoleMessage);
1359 
1360     if (m_previousMessage && m_previousMessage->isEqual(exec, consoleMessage)) {
1361         ++m_previousMessage->repeatCount;
1362         delete consoleMessage;
1363     } else {
1364         m_previousMessage = consoleMessage;
1365         m_consoleMessages.append(consoleMessage);
1366     }
1367 
1368     if (windowVisible())
1369         addScriptConsoleMessage(m_previousMessage);
1370 }
1371 
clearConsoleMessages()1372 void InspectorController::clearConsoleMessages()
1373 {
1374     deleteAllValues(m_consoleMessages);
1375     m_consoleMessages.clear();
1376     m_previousMessage = 0;
1377     m_groupLevel = 0;
1378 }
1379 
toggleRecordButton(bool isProfiling)1380 void InspectorController::toggleRecordButton(bool isProfiling)
1381 {
1382     if (!m_scriptContext)
1383         return;
1384 
1385     JSValueRef exception = 0;
1386     JSValueRef isProvingValue = JSValueMakeBoolean(m_scriptContext, isProfiling);
1387     callFunction(m_scriptContext, m_scriptObject, "setRecordingProfile", 1, &isProvingValue, exception);
1388 }
1389 
startGroup(MessageSource source,ScriptCallStack * callStack)1390 void InspectorController::startGroup(MessageSource source, ScriptCallStack* callStack)
1391 {
1392     ++m_groupLevel;
1393 
1394     addConsoleMessage(callStack->state(), new ConsoleMessage(source, StartGroupMessageLevel, callStack, m_groupLevel));
1395 }
1396 
endGroup(MessageSource source,unsigned lineNumber,const String & sourceURL)1397 void InspectorController::endGroup(MessageSource source, unsigned lineNumber, const String& sourceURL)
1398 {
1399     if (m_groupLevel == 0)
1400         return;
1401 
1402     --m_groupLevel;
1403 
1404     addConsoleMessage(0, new ConsoleMessage(source, EndGroupMessageLevel, String(), lineNumber, sourceURL, m_groupLevel));
1405 }
1406 
addProfile(PassRefPtr<Profile> prpProfile,unsigned lineNumber,const UString & sourceURL)1407 void InspectorController::addProfile(PassRefPtr<Profile> prpProfile, unsigned lineNumber, const UString& sourceURL)
1408 {
1409     if (!enabled())
1410         return;
1411 
1412     RefPtr<Profile> profile = prpProfile;
1413     m_profiles.append(profile);
1414 
1415     if (windowVisible())
1416         addScriptProfile(profile.get());
1417 
1418     addProfileMessageToConsole(profile, lineNumber, sourceURL);
1419 }
1420 
addProfileMessageToConsole(PassRefPtr<Profile> prpProfile,unsigned lineNumber,const UString & sourceURL)1421 void InspectorController::addProfileMessageToConsole(PassRefPtr<Profile> prpProfile, unsigned lineNumber, const UString& sourceURL)
1422 {
1423     RefPtr<Profile> profile = prpProfile;
1424 
1425     UString message = "Profile \"webkit-profile://";
1426     message += encodeWithURLEscapeSequences(profile->title());
1427     message += "/";
1428     message += UString::from(profile->uid());
1429     message += "\" finished.";
1430     addMessageToConsole(JSMessageSource, LogMessageLevel, message, lineNumber, sourceURL);
1431 }
1432 
attachWindow()1433 void InspectorController::attachWindow()
1434 {
1435     if (!enabled())
1436         return;
1437     m_client->attachWindow();
1438 }
1439 
detachWindow()1440 void InspectorController::detachWindow()
1441 {
1442     if (!enabled())
1443         return;
1444     m_client->detachWindow();
1445 }
1446 
setAttachedWindow(bool attached)1447 void InspectorController::setAttachedWindow(bool attached)
1448 {
1449     if (!enabled() || !m_scriptContext || !m_scriptObject)
1450         return;
1451 
1452     JSValueRef attachedValue = JSValueMakeBoolean(m_scriptContext, attached);
1453 
1454     JSValueRef exception = 0;
1455     callFunction(m_scriptContext, m_scriptObject, "setAttachedWindow", 1, &attachedValue, exception);
1456 }
1457 
setAttachedWindowHeight(unsigned height)1458 void InspectorController::setAttachedWindowHeight(unsigned height)
1459 {
1460     if (!enabled())
1461         return;
1462     m_client->setAttachedWindowHeight(height);
1463 }
1464 
toggleSearchForNodeInPage()1465 void InspectorController::toggleSearchForNodeInPage()
1466 {
1467     if (!enabled())
1468         return;
1469 
1470     m_searchingForNode = !m_searchingForNode;
1471     if (!m_searchingForNode)
1472         hideHighlight();
1473 }
1474 
mouseDidMoveOverElement(const HitTestResult & result,unsigned)1475 void InspectorController::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
1476 {
1477     if (!enabled() || !m_searchingForNode)
1478         return;
1479 
1480     Node* node = result.innerNode();
1481     if (node)
1482         highlight(node);
1483 }
1484 
handleMousePressOnNode(Node * node)1485 void InspectorController::handleMousePressOnNode(Node* node)
1486 {
1487     if (!enabled())
1488         return;
1489 
1490     ASSERT(m_searchingForNode);
1491     ASSERT(node);
1492     if (!node)
1493         return;
1494 
1495     // inspect() will implicitly call ElementsPanel's focusedNodeChanged() and the hover feedback will be stopped there.
1496     inspect(node);
1497 }
1498 
inspectedWindowScriptObjectCleared(Frame * frame)1499 void InspectorController::inspectedWindowScriptObjectCleared(Frame* frame)
1500 {
1501     if (!enabled() || !m_scriptContext || !m_scriptObject)
1502         return;
1503 
1504     JSDOMWindow* win = toJSDOMWindow(frame);
1505     ExecState* exec = win->globalExec();
1506 
1507     JSValueRef arg0;
1508 
1509     {
1510         JSC::JSLock lock(false);
1511         arg0 = toRef(JSInspectedObjectWrapper::wrap(exec, win));
1512     }
1513 
1514     JSValueRef exception = 0;
1515     callFunction(m_scriptContext, m_scriptObject, "inspectedWindowCleared", 1, &arg0, exception);
1516 }
1517 
windowScriptObjectAvailable()1518 void InspectorController::windowScriptObjectAvailable()
1519 {
1520     if (!m_page || !enabled())
1521         return;
1522 
1523     m_scriptContext = toRef(m_page->mainFrame()->script()->globalObject()->globalExec());
1524 
1525     JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
1526     ASSERT(global);
1527 
1528     static JSStaticFunction staticFunctions[] = {
1529         // SIMPLE_INSPECTOR_CALLBACK
1530         { "hideDOMNodeHighlight", WebCore::hideDOMNodeHighlight, kJSPropertyAttributeNone },
1531         { "loaded", WebCore::loaded, kJSPropertyAttributeNone },
1532         { "windowUnloading", WebCore::unloading, kJSPropertyAttributeNone },
1533         { "attach", WebCore::attach, kJSPropertyAttributeNone },
1534         { "detach", WebCore::detach, kJSPropertyAttributeNone },
1535 #if ENABLE(JAVASCRIPT_DEBUGGER)
1536         { "enableDebugger", WebCore::enableDebugger, kJSPropertyAttributeNone },
1537         { "disableDebugger", WebCore::disableDebugger, kJSPropertyAttributeNone },
1538         { "pauseInDebugger", WebCore::pauseInDebugger, kJSPropertyAttributeNone },
1539         { "resumeDebugger", WebCore::resumeDebugger, kJSPropertyAttributeNone },
1540         { "stepOverStatementInDebugger", WebCore::stepOverStatementInDebugger, kJSPropertyAttributeNone },
1541         { "stepIntoStatementInDebugger", WebCore::stepIntoStatementInDebugger, kJSPropertyAttributeNone },
1542         { "stepOutOfFunctionInDebugger", WebCore::stepOutOfFunctionInDebugger, kJSPropertyAttributeNone },
1543 #endif
1544         { "closeWindow", WebCore::closeWindow, kJSPropertyAttributeNone },
1545         { "clearMessages", WebCore::clearMessages, kJSPropertyAttributeNone },
1546         { "startProfiling", WebCore::startProfiling, kJSPropertyAttributeNone },
1547         { "stopProfiling", WebCore::stopProfiling, kJSPropertyAttributeNone },
1548         { "enableProfiler", WebCore::enableProfiler, kJSPropertyAttributeNone },
1549         { "disableProfiler", WebCore::disableProfiler, kJSPropertyAttributeNone },
1550         { "toggleNodeSearch", WebCore::toggleNodeSearch, kJSPropertyAttributeNone },
1551 
1552         // BOOL_INSPECTOR_CALLBACK
1553 #if ENABLE(JAVASCRIPT_DEBUGGER)
1554         { "debuggerEnabled", WebCore::debuggerEnabled, kJSPropertyAttributeNone },
1555         { "pauseOnExceptions", WebCore::pauseOnExceptions, kJSPropertyAttributeNone },
1556 #endif
1557         { "profilerEnabled", WebCore::profilerEnabled, kJSPropertyAttributeNone },
1558         { "isWindowVisible", WebCore::isWindowVisible, kJSPropertyAttributeNone },
1559         { "searchingForNode", WebCore::searchingForNode, kJSPropertyAttributeNone },
1560 
1561         // Custom callbacks
1562         { "addResourceSourceToFrame", WebCore::addResourceSourceToFrame, kJSPropertyAttributeNone },
1563         { "addSourceToFrame", WebCore::addSourceToFrame, kJSPropertyAttributeNone },
1564         { "getResourceDocumentNode", WebCore::getResourceDocumentNode, kJSPropertyAttributeNone },
1565         { "highlightDOMNode", WebCore::highlightDOMNode, kJSPropertyAttributeNone },
1566         { "search", WebCore::search, kJSPropertyAttributeNone },
1567 #if ENABLE(DATABASE)
1568         { "databaseTableNames", WebCore::databaseTableNames, kJSPropertyAttributeNone },
1569 #endif
1570         { "setting", WebCore::setting, kJSPropertyAttributeNone },
1571         { "setSetting", WebCore::setSetting, kJSPropertyAttributeNone },
1572         { "inspectedWindow", WebCore::inspectedWindow, kJSPropertyAttributeNone },
1573         { "localizedStringsURL", WebCore::localizedStrings, kJSPropertyAttributeNone },
1574         { "platform", WebCore::platform, kJSPropertyAttributeNone },
1575         { "moveByUnrestricted", WebCore::moveByUnrestricted, kJSPropertyAttributeNone },
1576         { "setAttachedWindowHeight", WebCore::setAttachedWindowHeight, kJSPropertyAttributeNone },
1577         { "wrapCallback", WebCore::wrapCallback, kJSPropertyAttributeNone },
1578 #if ENABLE(JAVASCRIPT_DEBUGGER)
1579         { "currentCallFrame", WebCore::currentCallFrame, kJSPropertyAttributeNone },
1580         { "setPauseOnExceptions", WebCore::setPauseOnExceptions, kJSPropertyAttributeNone },
1581         { "addBreakpoint", WebCore::addBreakpoint, kJSPropertyAttributeNone },
1582         { "removeBreakpoint", WebCore::removeBreakpoint, kJSPropertyAttributeNone },
1583 #endif
1584         { "profiles", WebCore::profiles, kJSPropertyAttributeNone },
1585         { 0, 0, 0 }
1586     };
1587 
1588     JSClassDefinition inspectorControllerDefinition = {
1589         0, kJSClassAttributeNone, "InspectorController", 0, 0, staticFunctions,
1590         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1591     };
1592 
1593     JSClassRef controllerClass = JSClassCreate(&inspectorControllerDefinition);
1594     ASSERT(controllerClass);
1595 
1596     m_controllerScriptObject = JSObjectMake(m_scriptContext, controllerClass, reinterpret_cast<void*>(this));
1597     ASSERT(m_controllerScriptObject);
1598 
1599     JSObjectSetProperty(m_scriptContext, global, jsStringRef("InspectorController").get(), m_controllerScriptObject, kJSPropertyAttributeNone, 0);
1600 }
1601 
scriptObjectReady()1602 void InspectorController::scriptObjectReady()
1603 {
1604     ASSERT(m_scriptContext);
1605     if (!m_scriptContext)
1606         return;
1607 
1608     JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
1609     ASSERT(global);
1610 
1611     JSValueRef exception = 0;
1612 
1613     JSValueRef inspectorValue = JSObjectGetProperty(m_scriptContext, global, jsStringRef("WebInspector").get(), &exception);
1614     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1615         return;
1616 
1617     ASSERT(inspectorValue);
1618     if (!inspectorValue)
1619         return;
1620 
1621     m_scriptObject = JSValueToObject(m_scriptContext, inspectorValue, &exception);
1622     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1623         return;
1624 
1625     ASSERT(m_scriptObject);
1626 
1627     JSValueProtect(m_scriptContext, m_scriptObject);
1628 
1629     // Make sure our window is visible now that the page loaded
1630     showWindow();
1631 }
1632 
show()1633 void InspectorController::show()
1634 {
1635     if (!enabled())
1636         return;
1637 
1638     if (!m_page) {
1639         m_page = m_client->createPage();
1640         if (!m_page)
1641             return;
1642         m_page->setParentInspectorController(this);
1643 
1644         // showWindow() will be called after the page loads in scriptObjectReady()
1645         return;
1646     }
1647 
1648     showWindow();
1649 }
1650 
showPanel(SpecialPanels panel)1651 void InspectorController::showPanel(SpecialPanels panel)
1652 {
1653     if (!enabled())
1654         return;
1655 
1656     show();
1657 
1658     if (!m_scriptObject) {
1659         m_showAfterVisible = panel;
1660         return;
1661     }
1662 
1663     if (panel == CurrentPanel)
1664         return;
1665 
1666     const char* showFunctionName;
1667     switch (panel) {
1668         case ConsolePanel:
1669             showFunctionName = "showConsole";
1670             break;
1671         case DatabasesPanel:
1672             showFunctionName = "showDatabasesPanel";
1673             break;
1674         case ElementsPanel:
1675             showFunctionName = "showElementsPanel";
1676             break;
1677         case ProfilesPanel:
1678             showFunctionName = "showProfilesPanel";
1679             break;
1680         case ResourcesPanel:
1681             showFunctionName = "showResourcesPanel";
1682             break;
1683         case ScriptsPanel:
1684             showFunctionName = "showScriptsPanel";
1685             break;
1686         default:
1687             ASSERT_NOT_REACHED();
1688             showFunctionName = 0;
1689     }
1690 
1691     if (showFunctionName)
1692         callSimpleFunction(m_scriptContext, m_scriptObject, showFunctionName);
1693 }
1694 
close()1695 void InspectorController::close()
1696 {
1697     if (!enabled())
1698         return;
1699 
1700     stopUserInitiatedProfiling();
1701 #if ENABLE(JAVASCRIPT_DEBUGGER)
1702     disableDebugger();
1703 #endif
1704     closeWindow();
1705 
1706     if (m_scriptContext && m_scriptObject)
1707         JSValueUnprotect(m_scriptContext, m_scriptObject);
1708 
1709     m_scriptObject = 0;
1710     m_scriptContext = 0;
1711 }
1712 
showWindow()1713 void InspectorController::showWindow()
1714 {
1715     ASSERT(enabled());
1716     m_client->showWindow();
1717 }
1718 
closeWindow()1719 void InspectorController::closeWindow()
1720 {
1721     m_client->closeWindow();
1722 }
1723 
startUserInitiatedProfilingSoon()1724 void InspectorController::startUserInitiatedProfilingSoon()
1725 {
1726     m_startProfiling.startOneShot(0);
1727 }
1728 
startUserInitiatedProfiling(Timer<InspectorController> *)1729 void InspectorController::startUserInitiatedProfiling(Timer<InspectorController>*)
1730 {
1731     if (!enabled())
1732         return;
1733 
1734     if (!profilerEnabled()) {
1735         enableProfiler(true);
1736         JavaScriptDebugServer::shared().recompileAllJSFunctions();
1737     }
1738 
1739     m_recordingUserInitiatedProfile = true;
1740     m_currentUserInitiatedProfileNumber = m_nextUserInitiatedProfileNumber++;
1741 
1742     UString title = UserInitiatedProfileName;
1743     title += ".";
1744     title += UString::from(m_currentUserInitiatedProfileNumber);
1745 
1746     ExecState* exec = toJSDOMWindow(m_inspectedPage->mainFrame())->globalExec();
1747     Profiler::profiler()->startProfiling(exec, title);
1748 
1749     toggleRecordButton(true);
1750 }
1751 
stopUserInitiatedProfiling()1752 void InspectorController::stopUserInitiatedProfiling()
1753 {
1754     if (!enabled())
1755         return;
1756 
1757     m_recordingUserInitiatedProfile = false;
1758 
1759     UString title =  UserInitiatedProfileName;
1760     title += ".";
1761     title += UString::from(m_currentUserInitiatedProfileNumber);
1762 
1763     ExecState* exec = toJSDOMWindow(m_inspectedPage->mainFrame())->globalExec();
1764     RefPtr<Profile> profile = Profiler::profiler()->stopProfiling(exec, title);
1765     if (profile)
1766         addProfile(profile, 0, UString());
1767 
1768     toggleRecordButton(false);
1769 }
1770 
enableProfiler(bool skipRecompile)1771 void InspectorController::enableProfiler(bool skipRecompile)
1772 {
1773     if (m_profilerEnabled)
1774         return;
1775 
1776     m_profilerEnabled = true;
1777 
1778     if (!skipRecompile)
1779         JavaScriptDebugServer::shared().recompileAllJSFunctionsSoon();
1780 
1781     if (m_scriptContext && m_scriptObject)
1782         callSimpleFunction(m_scriptContext, m_scriptObject, "profilerWasEnabled");
1783 }
1784 
disableProfiler()1785 void InspectorController::disableProfiler()
1786 {
1787     if (!m_profilerEnabled)
1788         return;
1789 
1790     m_profilerEnabled = false;
1791 
1792     JavaScriptDebugServer::shared().recompileAllJSFunctionsSoon();
1793 
1794     if (m_scriptContext && m_scriptObject)
1795         callSimpleFunction(m_scriptContext, m_scriptObject, "profilerWasDisabled");
1796 }
1797 
addHeaders(JSContextRef context,JSObjectRef object,const HTTPHeaderMap & headers,JSValueRef * exception)1798 static void addHeaders(JSContextRef context, JSObjectRef object, const HTTPHeaderMap& headers, JSValueRef* exception)
1799 {
1800     ASSERT_ARG(context, context);
1801     ASSERT_ARG(object, object);
1802 
1803     HTTPHeaderMap::const_iterator end = headers.end();
1804     for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) {
1805         JSValueRef value = JSValueMakeString(context, jsStringRef(it->second).get());
1806         JSObjectSetProperty(context, object, jsStringRef((it->first).string()).get(), value, kJSPropertyAttributeNone, exception);
1807         if (exception && *exception)
1808             return;
1809     }
1810 }
1811 
scriptObjectForRequest(JSContextRef context,const InspectorResource * resource,JSValueRef * exception)1812 static JSObjectRef scriptObjectForRequest(JSContextRef context, const InspectorResource* resource, JSValueRef* exception)
1813 {
1814     ASSERT_ARG(context, context);
1815 
1816     JSObjectRef object = JSObjectMake(context, 0, 0);
1817     addHeaders(context, object, resource->requestHeaderFields, exception);
1818 
1819     return object;
1820 }
1821 
scriptObjectForResponse(JSContextRef context,const InspectorResource * resource,JSValueRef * exception)1822 static JSObjectRef scriptObjectForResponse(JSContextRef context, const InspectorResource* resource, JSValueRef* exception)
1823 {
1824     ASSERT_ARG(context, context);
1825 
1826     JSObjectRef object = JSObjectMake(context, 0, 0);
1827     addHeaders(context, object, resource->responseHeaderFields, exception);
1828 
1829     return object;
1830 }
1831 
addScriptResource(InspectorResource * resource)1832 JSObjectRef InspectorController::addScriptResource(InspectorResource* resource)
1833 {
1834     ASSERT_ARG(resource, resource);
1835 
1836     ASSERT(m_scriptContext);
1837     ASSERT(m_scriptObject);
1838     if (!m_scriptContext || !m_scriptObject)
1839         return 0;
1840 
1841     if (!resource->scriptObject) {
1842         JSValueRef exception = 0;
1843 
1844         JSValueRef resourceProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("Resource").get(), &exception);
1845         if (HANDLE_EXCEPTION(m_scriptContext, exception))
1846             return 0;
1847 
1848         JSObjectRef resourceConstructor = JSValueToObject(m_scriptContext, resourceProperty, &exception);
1849         if (HANDLE_EXCEPTION(m_scriptContext, exception))
1850             return 0;
1851 
1852         JSValueRef urlValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.string()).get());
1853         JSValueRef domainValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.host()).get());
1854         JSValueRef pathValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.path()).get());
1855         JSValueRef lastPathComponentValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.lastPathComponent()).get());
1856 
1857         JSValueRef identifier = JSValueMakeNumber(m_scriptContext, resource->identifier);
1858         JSValueRef mainResource = JSValueMakeBoolean(m_scriptContext, m_mainResource == resource);
1859         JSValueRef cached = JSValueMakeBoolean(m_scriptContext, resource->cached);
1860 
1861         JSObjectRef scriptObject = scriptObjectForRequest(m_scriptContext, resource, &exception);
1862         if (HANDLE_EXCEPTION(m_scriptContext, exception))
1863             return 0;
1864 
1865         JSValueRef arguments[] = { scriptObject, urlValue, domainValue, pathValue, lastPathComponentValue, identifier, mainResource, cached };
1866         JSObjectRef result = JSObjectCallAsConstructor(m_scriptContext, resourceConstructor, 8, arguments, &exception);
1867         if (HANDLE_EXCEPTION(m_scriptContext, exception))
1868             return 0;
1869 
1870         ASSERT(result);
1871 
1872         resource->setScriptObject(m_scriptContext, result);
1873     }
1874 
1875     JSValueRef exception = 0;
1876     callFunction(m_scriptContext, m_scriptObject, "addResource", 1, &resource->scriptObject, exception);
1877 
1878     if (exception)
1879         return 0;
1880 
1881     return resource->scriptObject;
1882 }
1883 
addAndUpdateScriptResource(InspectorResource * resource)1884 JSObjectRef InspectorController::addAndUpdateScriptResource(InspectorResource* resource)
1885 {
1886     ASSERT_ARG(resource, resource);
1887 
1888     JSObjectRef scriptResource = addScriptResource(resource);
1889     if (!scriptResource)
1890         return 0;
1891 
1892     updateScriptResourceResponse(resource);
1893     updateScriptResource(resource, resource->length);
1894     updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
1895     updateScriptResource(resource, resource->finished, resource->failed);
1896     return scriptResource;
1897 }
1898 
removeScriptResource(InspectorResource * resource)1899 void InspectorController::removeScriptResource(InspectorResource* resource)
1900 {
1901     ASSERT(m_scriptContext);
1902     ASSERT(m_scriptObject);
1903     if (!m_scriptContext || !m_scriptObject)
1904         return;
1905 
1906     ASSERT(resource);
1907     ASSERT(resource->scriptObject);
1908     if (!resource || !resource->scriptObject)
1909         return;
1910 
1911     JSObjectRef scriptObject = resource->scriptObject;
1912     resource->setScriptObject(0, 0);
1913 
1914     JSValueRef exception = 0;
1915     callFunction(m_scriptContext, m_scriptObject, "removeResource", 1, &scriptObject, exception);
1916 }
1917 
updateResourceRequest(InspectorResource * resource,const ResourceRequest & request)1918 static void updateResourceRequest(InspectorResource* resource, const ResourceRequest& request)
1919 {
1920     resource->requestHeaderFields = request.httpHeaderFields();
1921     resource->requestURL = request.url();
1922 }
1923 
updateResourceResponse(InspectorResource * resource,const ResourceResponse & response)1924 static void updateResourceResponse(InspectorResource* resource, const ResourceResponse& response)
1925 {
1926     resource->expectedContentLength = response.expectedContentLength();
1927     resource->mimeType = response.mimeType();
1928     resource->responseHeaderFields = response.httpHeaderFields();
1929     resource->responseStatusCode = response.httpStatusCode();
1930     resource->suggestedFilename = response.suggestedFilename();
1931 }
1932 
updateScriptResourceRequest(InspectorResource * resource)1933 void InspectorController::updateScriptResourceRequest(InspectorResource* resource)
1934 {
1935     ASSERT(resource->scriptObject);
1936     ASSERT(m_scriptContext);
1937     if (!resource->scriptObject || !m_scriptContext)
1938         return;
1939 
1940     JSValueRef urlValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.string()).get());
1941     JSValueRef domainValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.host()).get());
1942     JSValueRef pathValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.path()).get());
1943     JSValueRef lastPathComponentValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.lastPathComponent()).get());
1944 
1945     JSValueRef mainResourceValue = JSValueMakeBoolean(m_scriptContext, m_mainResource == resource);
1946 
1947     JSValueRef exception = 0;
1948 
1949     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("url").get(), urlValue, kJSPropertyAttributeNone, &exception);
1950     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1951         return;
1952 
1953     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("domain").get(), domainValue, kJSPropertyAttributeNone, &exception);
1954     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1955         return;
1956 
1957     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("path").get(), pathValue, kJSPropertyAttributeNone, &exception);
1958     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1959         return;
1960 
1961     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("lastPathComponent").get(), lastPathComponentValue, kJSPropertyAttributeNone, &exception);
1962     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1963         return;
1964 
1965     JSObjectRef scriptObject = scriptObjectForRequest(m_scriptContext, resource, &exception);
1966     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1967         return;
1968 
1969     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("requestHeaders").get(), scriptObject, kJSPropertyAttributeNone, &exception);
1970     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1971         return;
1972 
1973     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("mainResource").get(), mainResourceValue, kJSPropertyAttributeNone, &exception);
1974     HANDLE_EXCEPTION(m_scriptContext, exception);
1975 }
1976 
updateScriptResourceResponse(InspectorResource * resource)1977 void InspectorController::updateScriptResourceResponse(InspectorResource* resource)
1978 {
1979     ASSERT(resource->scriptObject);
1980     ASSERT(m_scriptContext);
1981     if (!resource->scriptObject || !m_scriptContext)
1982         return;
1983 
1984     JSValueRef mimeTypeValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->mimeType).get());
1985 
1986     JSValueRef suggestedFilenameValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->suggestedFilename).get());
1987 
1988     JSValueRef expectedContentLengthValue = JSValueMakeNumber(m_scriptContext, static_cast<double>(resource->expectedContentLength));
1989     JSValueRef statusCodeValue = JSValueMakeNumber(m_scriptContext, resource->responseStatusCode);
1990 
1991     JSValueRef exception = 0;
1992 
1993     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("mimeType").get(), mimeTypeValue, kJSPropertyAttributeNone, &exception);
1994     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1995         return;
1996 
1997     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("suggestedFilename").get(), suggestedFilenameValue, kJSPropertyAttributeNone, &exception);
1998     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1999         return;
2000 
2001     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("expectedContentLength").get(), expectedContentLengthValue, kJSPropertyAttributeNone, &exception);
2002     if (HANDLE_EXCEPTION(m_scriptContext, exception))
2003         return;
2004 
2005     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("statusCode").get(), statusCodeValue, kJSPropertyAttributeNone, &exception);
2006     if (HANDLE_EXCEPTION(m_scriptContext, exception))
2007         return;
2008 
2009     JSObjectRef scriptObject = scriptObjectForResponse(m_scriptContext, resource, &exception);
2010     if (HANDLE_EXCEPTION(m_scriptContext, exception))
2011         return;
2012 
2013     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("responseHeaders").get(), scriptObject, kJSPropertyAttributeNone, &exception);
2014     if (HANDLE_EXCEPTION(m_scriptContext, exception))
2015         return;
2016 
2017     updateScriptResourceType(resource);
2018 }
2019 
updateScriptResourceType(InspectorResource * resource)2020 void InspectorController::updateScriptResourceType(InspectorResource* resource)
2021 {
2022     ASSERT(resource->scriptObject);
2023     ASSERT(m_scriptContext);
2024     if (!resource->scriptObject || !m_scriptContext)
2025         return;
2026 
2027     JSValueRef exception = 0;
2028 
2029     JSValueRef typeValue = JSValueMakeNumber(m_scriptContext, resource->type());
2030     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("type").get(), typeValue, kJSPropertyAttributeNone, &exception);
2031     HANDLE_EXCEPTION(m_scriptContext, exception);
2032 }
2033 
updateScriptResource(InspectorResource * resource,int length)2034 void InspectorController::updateScriptResource(InspectorResource* resource, int length)
2035 {
2036     ASSERT(resource->scriptObject);
2037     ASSERT(m_scriptContext);
2038     if (!resource->scriptObject || !m_scriptContext)
2039         return;
2040 
2041     JSValueRef lengthValue = JSValueMakeNumber(m_scriptContext, length);
2042 
2043     JSValueRef exception = 0;
2044 
2045     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("contentLength").get(), lengthValue, kJSPropertyAttributeNone, &exception);
2046     HANDLE_EXCEPTION(m_scriptContext, exception);
2047 }
2048 
updateScriptResource(InspectorResource * resource,bool finished,bool failed)2049 void InspectorController::updateScriptResource(InspectorResource* resource, bool finished, bool failed)
2050 {
2051     ASSERT(resource->scriptObject);
2052     ASSERT(m_scriptContext);
2053     if (!resource->scriptObject || !m_scriptContext)
2054         return;
2055 
2056     JSValueRef failedValue = JSValueMakeBoolean(m_scriptContext, failed);
2057     JSValueRef finishedValue = JSValueMakeBoolean(m_scriptContext, finished);
2058 
2059     JSValueRef exception = 0;
2060 
2061     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("failed").get(), failedValue, kJSPropertyAttributeNone, &exception);
2062     if (HANDLE_EXCEPTION(m_scriptContext, exception))
2063         return;
2064 
2065     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("finished").get(), finishedValue, kJSPropertyAttributeNone, &exception);
2066     HANDLE_EXCEPTION(m_scriptContext, exception);
2067 }
2068 
updateScriptResource(InspectorResource * resource,double startTime,double responseReceivedTime,double endTime)2069 void InspectorController::updateScriptResource(InspectorResource* resource, double startTime, double responseReceivedTime, double endTime)
2070 {
2071     ASSERT(resource->scriptObject);
2072     ASSERT(m_scriptContext);
2073     if (!resource->scriptObject || !m_scriptContext)
2074         return;
2075 
2076     JSValueRef startTimeValue = JSValueMakeNumber(m_scriptContext, startTime);
2077     JSValueRef responseReceivedTimeValue = JSValueMakeNumber(m_scriptContext, responseReceivedTime);
2078     JSValueRef endTimeValue = JSValueMakeNumber(m_scriptContext, endTime);
2079 
2080     JSValueRef exception = 0;
2081 
2082     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("startTime").get(), startTimeValue, kJSPropertyAttributeNone, &exception);
2083     if (HANDLE_EXCEPTION(m_scriptContext, exception))
2084         return;
2085 
2086     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("responseReceivedTime").get(), responseReceivedTimeValue, kJSPropertyAttributeNone, &exception);
2087     if (HANDLE_EXCEPTION(m_scriptContext, exception))
2088         return;
2089 
2090     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("endTime").get(), endTimeValue, kJSPropertyAttributeNone, &exception);
2091     HANDLE_EXCEPTION(m_scriptContext, exception);
2092 }
2093 
populateScriptObjects()2094 void InspectorController::populateScriptObjects()
2095 {
2096     ASSERT(m_scriptContext);
2097     if (!m_scriptContext)
2098         return;
2099 
2100     ResourcesMap::iterator resourcesEnd = m_resources.end();
2101     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it)
2102         addAndUpdateScriptResource(it->second.get());
2103 
2104     unsigned messageCount = m_consoleMessages.size();
2105     for (unsigned i = 0; i < messageCount; ++i)
2106         addScriptConsoleMessage(m_consoleMessages[i]);
2107 
2108 #if ENABLE(DATABASE)
2109     DatabaseResourcesSet::iterator databasesEnd = m_databaseResources.end();
2110     for (DatabaseResourcesSet::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it)
2111         addDatabaseScriptResource((*it).get());
2112 #endif
2113 
2114     callSimpleFunction(m_scriptContext, m_scriptObject, "populateInterface");
2115 }
2116 
2117 #if ENABLE(DATABASE)
addDatabaseScriptResource(InspectorDatabaseResource * resource)2118 JSObjectRef InspectorController::addDatabaseScriptResource(InspectorDatabaseResource* resource)
2119 {
2120     ASSERT_ARG(resource, resource);
2121 
2122     if (resource->scriptObject)
2123         return resource->scriptObject;
2124 
2125     ASSERT(m_scriptContext);
2126     ASSERT(m_scriptObject);
2127     if (!m_scriptContext || !m_scriptObject)
2128         return 0;
2129 
2130     Frame* frame = resource->database->document()->frame();
2131     if (!frame)
2132         return 0;
2133 
2134     JSValueRef exception = 0;
2135 
2136     JSValueRef databaseProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("Database").get(), &exception);
2137     if (HANDLE_EXCEPTION(m_scriptContext, exception))
2138         return 0;
2139 
2140     JSObjectRef databaseConstructor = JSValueToObject(m_scriptContext, databaseProperty, &exception);
2141     if (HANDLE_EXCEPTION(m_scriptContext, exception))
2142         return 0;
2143 
2144     ExecState* exec = toJSDOMWindow(frame)->globalExec();
2145 
2146     JSValueRef database;
2147 
2148     {
2149         JSC::JSLock lock(false);
2150         database = toRef(JSInspectedObjectWrapper::wrap(exec, toJS(exec, resource->database.get())));
2151     }
2152 
2153     JSValueRef domainValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->domain).get());
2154     JSValueRef nameValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->name).get());
2155     JSValueRef versionValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->version).get());
2156 
2157     JSValueRef arguments[] = { database, domainValue, nameValue, versionValue };
2158     JSObjectRef result = JSObjectCallAsConstructor(m_scriptContext, databaseConstructor, 4, arguments, &exception);
2159     if (HANDLE_EXCEPTION(m_scriptContext, exception))
2160         return 0;
2161 
2162     ASSERT(result);
2163 
2164     callFunction(m_scriptContext, m_scriptObject, "addDatabase", 1, &result, exception);
2165 
2166     if (exception)
2167         return 0;
2168 
2169     resource->setScriptObject(m_scriptContext, result);
2170 
2171     return result;
2172 }
2173 
removeDatabaseScriptResource(InspectorDatabaseResource * resource)2174 void InspectorController::removeDatabaseScriptResource(InspectorDatabaseResource* resource)
2175 {
2176     ASSERT(m_scriptContext);
2177     ASSERT(m_scriptObject);
2178     if (!m_scriptContext || !m_scriptObject)
2179         return;
2180 
2181     ASSERT(resource);
2182     ASSERT(resource->scriptObject);
2183     if (!resource || !resource->scriptObject)
2184         return;
2185 
2186     JSObjectRef scriptObject = resource->scriptObject;
2187     resource->setScriptObject(0, 0);
2188 
2189     JSValueRef exception = 0;
2190     callFunction(m_scriptContext, m_scriptObject, "removeDatabase", 1, &scriptObject, exception);
2191 }
2192 #endif
2193 
addScriptConsoleMessage(const ConsoleMessage * message)2194 void InspectorController::addScriptConsoleMessage(const ConsoleMessage* message)
2195 {
2196     ASSERT_ARG(message, message);
2197 
2198     JSValueRef exception = 0;
2199 
2200     JSValueRef messageConstructorProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("ConsoleMessage").get(), &exception);
2201     if (HANDLE_EXCEPTION(m_scriptContext, exception))
2202         return;
2203 
2204     JSObjectRef messageConstructor = JSValueToObject(m_scriptContext, messageConstructorProperty, &exception);
2205     if (HANDLE_EXCEPTION(m_scriptContext, exception))
2206         return;
2207 
2208     JSValueRef sourceValue = JSValueMakeNumber(m_scriptContext, message->source);
2209     JSValueRef levelValue = JSValueMakeNumber(m_scriptContext, message->level);
2210     JSValueRef lineValue = JSValueMakeNumber(m_scriptContext, message->line);
2211     JSValueRef urlValue = JSValueMakeString(m_scriptContext, jsStringRef(message->url).get());
2212     JSValueRef groupLevelValue = JSValueMakeNumber(m_scriptContext, message->groupLevel);
2213     JSValueRef repeatCountValue = JSValueMakeNumber(m_scriptContext, message->repeatCount);
2214 
2215     static const unsigned maximumMessageArguments = 256;
2216     JSValueRef arguments[maximumMessageArguments];
2217     unsigned argumentCount = 0;
2218     arguments[argumentCount++] = sourceValue;
2219     arguments[argumentCount++] = levelValue;
2220     arguments[argumentCount++] = lineValue;
2221     arguments[argumentCount++] = urlValue;
2222     arguments[argumentCount++] = groupLevelValue;
2223     arguments[argumentCount++] = repeatCountValue;
2224 
2225     if (!message->frames.isEmpty()) {
2226         unsigned remainingSpaceInArguments = maximumMessageArguments - argumentCount;
2227         unsigned argumentsToAdd = min(remainingSpaceInArguments, static_cast<unsigned>(message->frames.size()));
2228         for (unsigned i = 0; i < argumentsToAdd; ++i)
2229             arguments[argumentCount++] = JSValueMakeString(m_scriptContext, jsStringRef(message->frames[i]).get());
2230     } else if (!message->wrappedArguments.isEmpty()) {
2231         unsigned remainingSpaceInArguments = maximumMessageArguments - argumentCount;
2232         unsigned argumentsToAdd = min(remainingSpaceInArguments, static_cast<unsigned>(message->wrappedArguments.size()));
2233         for (unsigned i = 0; i < argumentsToAdd; ++i)
2234             arguments[argumentCount++] = toRef(message->wrappedArguments[i]);
2235     } else {
2236         JSValueRef messageValue = JSValueMakeString(m_scriptContext, jsStringRef(message->message).get());
2237         arguments[argumentCount++] = messageValue;
2238     }
2239 
2240     JSObjectRef messageObject = JSObjectCallAsConstructor(m_scriptContext, messageConstructor, argumentCount, arguments, &exception);
2241     if (HANDLE_EXCEPTION(m_scriptContext, exception))
2242         return;
2243 
2244     callFunction(m_scriptContext, m_scriptObject, "addMessageToConsole", 1, &messageObject, exception);
2245 }
2246 
addScriptProfile(Profile * profile)2247 void InspectorController::addScriptProfile(Profile* profile)
2248 {
2249     JSLock lock(false);
2250     JSValueRef exception = 0;
2251     JSValueRef profileObject = toRef(toJS(toJS(m_scriptContext), profile));
2252     callFunction(m_scriptContext, m_scriptObject, "addProfile", 1, &profileObject, exception);
2253 }
2254 
resetScriptObjects()2255 void InspectorController::resetScriptObjects()
2256 {
2257     if (!m_scriptContext || !m_scriptObject)
2258         return;
2259 
2260     ResourcesMap::iterator resourcesEnd = m_resources.end();
2261     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it) {
2262         InspectorResource* resource = it->second.get();
2263         resource->setScriptObject(0, 0);
2264     }
2265 
2266 #if ENABLE(DATABASE)
2267     DatabaseResourcesSet::iterator databasesEnd = m_databaseResources.end();
2268     for (DatabaseResourcesSet::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it) {
2269         InspectorDatabaseResource* resource = (*it).get();
2270         resource->setScriptObject(0, 0);
2271     }
2272 #endif
2273 
2274     callSimpleFunction(m_scriptContext, m_scriptObject, "reset");
2275 }
2276 
pruneResources(ResourcesMap * resourceMap,DocumentLoader * loaderToKeep)2277 void InspectorController::pruneResources(ResourcesMap* resourceMap, DocumentLoader* loaderToKeep)
2278 {
2279     ASSERT_ARG(resourceMap, resourceMap);
2280 
2281     ResourcesMap mapCopy(*resourceMap);
2282     ResourcesMap::iterator end = mapCopy.end();
2283     for (ResourcesMap::iterator it = mapCopy.begin(); it != end; ++it) {
2284         InspectorResource* resource = (*it).second.get();
2285         if (resource == m_mainResource)
2286             continue;
2287 
2288         if (!loaderToKeep || resource->loader != loaderToKeep) {
2289             removeResource(resource);
2290             if (windowVisible() && resource->scriptObject)
2291                 removeScriptResource(resource);
2292         }
2293     }
2294 }
2295 
didCommitLoad(DocumentLoader * loader)2296 void InspectorController::didCommitLoad(DocumentLoader* loader)
2297 {
2298     if (!enabled())
2299         return;
2300 
2301     ASSERT(m_inspectedPage);
2302 
2303     if (loader->frame() == m_inspectedPage->mainFrame()) {
2304         m_client->inspectedURLChanged(loader->url().string());
2305 
2306         clearConsoleMessages();
2307 
2308         m_times.clear();
2309         m_counts.clear();
2310         m_profiles.clear();
2311 
2312 #if ENABLE(DATABASE)
2313         m_databaseResources.clear();
2314 #endif
2315 
2316         if (windowVisible()) {
2317             resetScriptObjects();
2318 
2319             if (!loader->isLoadingFromCachedPage()) {
2320                 ASSERT(m_mainResource && m_mainResource->loader == loader);
2321                 // We don't add the main resource until its load is committed. This is
2322                 // needed to keep the load for a user-entered URL from showing up in the
2323                 // list of resources for the page they are navigating away from.
2324                 addAndUpdateScriptResource(m_mainResource.get());
2325             } else {
2326                 // Pages loaded from the page cache are committed before
2327                 // m_mainResource is the right resource for this load, so we
2328                 // clear it here. It will be re-assigned in
2329                 // identifierForInitialRequest.
2330                 m_mainResource = 0;
2331             }
2332         }
2333     }
2334 
2335     for (Frame* frame = loader->frame(); frame; frame = frame->tree()->traverseNext(loader->frame()))
2336         if (ResourcesMap* resourceMap = m_frameResources.get(frame))
2337             pruneResources(resourceMap, loader);
2338 }
2339 
frameDetachedFromParent(Frame * frame)2340 void InspectorController::frameDetachedFromParent(Frame* frame)
2341 {
2342     if (!enabled())
2343         return;
2344     if (ResourcesMap* resourceMap = m_frameResources.get(frame))
2345         removeAllResources(resourceMap);
2346 }
2347 
addResource(InspectorResource * resource)2348 void InspectorController::addResource(InspectorResource* resource)
2349 {
2350     m_resources.set(resource->identifier, resource);
2351     m_knownResources.add(resource->requestURL.string());
2352 
2353     Frame* frame = resource->frame.get();
2354     ResourcesMap* resourceMap = m_frameResources.get(frame);
2355     if (resourceMap)
2356         resourceMap->set(resource->identifier, resource);
2357     else {
2358         resourceMap = new ResourcesMap;
2359         resourceMap->set(resource->identifier, resource);
2360         m_frameResources.set(frame, resourceMap);
2361     }
2362 }
2363 
removeResource(InspectorResource * resource)2364 void InspectorController::removeResource(InspectorResource* resource)
2365 {
2366     m_resources.remove(resource->identifier);
2367     m_knownResources.remove(resource->requestURL.string());
2368 
2369     Frame* frame = resource->frame.get();
2370     ResourcesMap* resourceMap = m_frameResources.get(frame);
2371     if (!resourceMap) {
2372         ASSERT_NOT_REACHED();
2373         return;
2374     }
2375 
2376     resourceMap->remove(resource->identifier);
2377     if (resourceMap->isEmpty()) {
2378         m_frameResources.remove(frame);
2379         delete resourceMap;
2380     }
2381 }
2382 
didLoadResourceFromMemoryCache(DocumentLoader * loader,const CachedResource * cachedResource)2383 void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader* loader, const CachedResource* cachedResource)
2384 {
2385     if (!enabled())
2386         return;
2387 
2388     // If the resource URL is already known, we don't need to add it again since this is just a cached load.
2389     if (m_knownResources.contains(cachedResource->url()))
2390         return;
2391 
2392     RefPtr<InspectorResource> resource = InspectorResource::create(m_nextIdentifier--, loader, loader->frame());
2393     resource->finished = true;
2394 
2395     resource->requestURL = KURL(cachedResource->url());
2396     updateResourceResponse(resource.get(), cachedResource->response());
2397 
2398     resource->length = cachedResource->encodedSize();
2399     resource->cached = true;
2400     resource->startTime = currentTime();
2401     resource->responseReceivedTime = resource->startTime;
2402     resource->endTime = resource->startTime;
2403 
2404     ASSERT(m_inspectedPage);
2405 
2406     if (loader->frame() == m_inspectedPage->mainFrame() && cachedResource->url() == loader->requestURL())
2407         m_mainResource = resource;
2408 
2409     addResource(resource.get());
2410 
2411     if (windowVisible())
2412         addAndUpdateScriptResource(resource.get());
2413 }
2414 
identifierForInitialRequest(unsigned long identifier,DocumentLoader * loader,const ResourceRequest & request)2415 void InspectorController::identifierForInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request)
2416 {
2417     if (!enabled())
2418         return;
2419 
2420     RefPtr<InspectorResource> resource = InspectorResource::create(identifier, loader, loader->frame());
2421 
2422     updateResourceRequest(resource.get(), request);
2423 
2424     ASSERT(m_inspectedPage);
2425 
2426     if (loader->frame() == m_inspectedPage->mainFrame() && request.url() == loader->requestURL())
2427         m_mainResource = resource;
2428 
2429     addResource(resource.get());
2430 
2431     if (windowVisible() && loader->isLoadingFromCachedPage() && resource == m_mainResource)
2432         addAndUpdateScriptResource(resource.get());
2433 }
2434 
willSendRequest(DocumentLoader *,unsigned long identifier,ResourceRequest & request,const ResourceResponse & redirectResponse)2435 void InspectorController::willSendRequest(DocumentLoader*, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse)
2436 {
2437     if (!enabled())
2438         return;
2439 
2440     InspectorResource* resource = m_resources.get(identifier).get();
2441     if (!resource)
2442         return;
2443 
2444     resource->startTime = currentTime();
2445 
2446     if (!redirectResponse.isNull()) {
2447         updateResourceRequest(resource, request);
2448         updateResourceResponse(resource, redirectResponse);
2449     }
2450 
2451     if (resource != m_mainResource && windowVisible()) {
2452         if (!resource->scriptObject)
2453             addScriptResource(resource);
2454         else
2455             updateScriptResourceRequest(resource);
2456 
2457         updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
2458 
2459         if (!redirectResponse.isNull())
2460             updateScriptResourceResponse(resource);
2461     }
2462 }
2463 
didReceiveResponse(DocumentLoader *,unsigned long identifier,const ResourceResponse & response)2464 void InspectorController::didReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse& response)
2465 {
2466     if (!enabled())
2467         return;
2468 
2469     InspectorResource* resource = m_resources.get(identifier).get();
2470     if (!resource)
2471         return;
2472 
2473     updateResourceResponse(resource, response);
2474 
2475     resource->responseReceivedTime = currentTime();
2476 
2477     if (windowVisible() && resource->scriptObject) {
2478         updateScriptResourceResponse(resource);
2479         updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
2480     }
2481 }
2482 
didReceiveContentLength(DocumentLoader *,unsigned long identifier,int lengthReceived)2483 void InspectorController::didReceiveContentLength(DocumentLoader*, unsigned long identifier, int lengthReceived)
2484 {
2485     if (!enabled())
2486         return;
2487 
2488     InspectorResource* resource = m_resources.get(identifier).get();
2489     if (!resource)
2490         return;
2491 
2492     resource->length += lengthReceived;
2493 
2494     if (windowVisible() && resource->scriptObject)
2495         updateScriptResource(resource, resource->length);
2496 }
2497 
didFinishLoading(DocumentLoader *,unsigned long identifier)2498 void InspectorController::didFinishLoading(DocumentLoader*, unsigned long identifier)
2499 {
2500     if (!enabled())
2501         return;
2502 
2503     RefPtr<InspectorResource> resource = m_resources.get(identifier);
2504     if (!resource)
2505         return;
2506 
2507     removeResource(resource.get());
2508 
2509     resource->finished = true;
2510     resource->endTime = currentTime();
2511 
2512     addResource(resource.get());
2513 
2514     if (windowVisible() && resource->scriptObject) {
2515         updateScriptResource(resource.get(), resource->startTime, resource->responseReceivedTime, resource->endTime);
2516         updateScriptResource(resource.get(), resource->finished);
2517     }
2518 }
2519 
didFailLoading(DocumentLoader *,unsigned long identifier,const ResourceError &)2520 void InspectorController::didFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError& /*error*/)
2521 {
2522     if (!enabled())
2523         return;
2524 
2525     RefPtr<InspectorResource> resource = m_resources.get(identifier);
2526     if (!resource)
2527         return;
2528 
2529     removeResource(resource.get());
2530 
2531     resource->finished = true;
2532     resource->failed = true;
2533     resource->endTime = currentTime();
2534 
2535     addResource(resource.get());
2536 
2537     if (windowVisible() && resource->scriptObject) {
2538         updateScriptResource(resource.get(), resource->startTime, resource->responseReceivedTime, resource->endTime);
2539         updateScriptResource(resource.get(), resource->finished, resource->failed);
2540     }
2541 }
2542 
resourceRetrievedByXMLHttpRequest(unsigned long identifier,const JSC::UString & sourceString)2543 void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identifier, const JSC::UString& sourceString)
2544 {
2545     if (!enabled())
2546         return;
2547 
2548     InspectorResource* resource = m_resources.get(identifier).get();
2549     if (!resource)
2550         return;
2551 
2552     resource->setXMLHttpRequestProperties(sourceString);
2553 
2554     if (windowVisible() && resource->scriptObject)
2555         updateScriptResourceType(resource);
2556 }
2557 
2558 
2559 #if ENABLE(DATABASE)
didOpenDatabase(Database * database,const String & domain,const String & name,const String & version)2560 void InspectorController::didOpenDatabase(Database* database, const String& domain, const String& name, const String& version)
2561 {
2562     if (!enabled())
2563         return;
2564 
2565     RefPtr<InspectorDatabaseResource> resource = InspectorDatabaseResource::create(database, domain, name, version);
2566 
2567     m_databaseResources.add(resource);
2568 
2569     if (windowVisible())
2570         addDatabaseScriptResource(resource.get());
2571 }
2572 #endif
2573 
moveWindowBy(float x,float y) const2574 void InspectorController::moveWindowBy(float x, float y) const
2575 {
2576     if (!m_page || !enabled())
2577         return;
2578 
2579     FloatRect frameRect = m_page->chrome()->windowRect();
2580     frameRect.move(x, y);
2581     m_page->chrome()->setWindowRect(frameRect);
2582 }
2583 
2584 #if ENABLE(JAVASCRIPT_DEBUGGER)
enableDebugger()2585 void InspectorController::enableDebugger()
2586 {
2587     if (!enabled())
2588         return;
2589 
2590     if (!m_scriptContext || !m_scriptObject) {
2591         m_attachDebuggerWhenShown = true;
2592         return;
2593     }
2594 
2595     ASSERT(m_inspectedPage);
2596 
2597     JavaScriptDebugServer::shared().addListener(this, m_inspectedPage);
2598     JavaScriptDebugServer::shared().clearBreakpoints();
2599 
2600     m_debuggerEnabled = true;
2601     m_attachDebuggerWhenShown = false;
2602 
2603     callSimpleFunction(m_scriptContext, m_scriptObject, "debuggerWasEnabled");
2604 }
2605 
disableDebugger()2606 void InspectorController::disableDebugger()
2607 {
2608     if (!enabled())
2609         return;
2610 
2611     ASSERT(m_inspectedPage);
2612 
2613     JavaScriptDebugServer::shared().removeListener(this, m_inspectedPage);
2614 
2615     m_debuggerEnabled = false;
2616     m_attachDebuggerWhenShown = false;
2617 
2618     if (m_scriptContext && m_scriptObject)
2619         callSimpleFunction(m_scriptContext, m_scriptObject, "debuggerWasDisabled");
2620 }
2621 
currentCallFrame() const2622 JavaScriptCallFrame* InspectorController::currentCallFrame() const
2623 {
2624     return JavaScriptDebugServer::shared().currentCallFrame();
2625 }
2626 
pauseOnExceptions()2627 bool InspectorController::pauseOnExceptions()
2628 {
2629     return JavaScriptDebugServer::shared().pauseOnExceptions();
2630 }
2631 
setPauseOnExceptions(bool pause)2632 void InspectorController::setPauseOnExceptions(bool pause)
2633 {
2634     JavaScriptDebugServer::shared().setPauseOnExceptions(pause);
2635 }
2636 
pauseInDebugger()2637 void InspectorController::pauseInDebugger()
2638 {
2639     if (!m_debuggerEnabled)
2640         return;
2641     JavaScriptDebugServer::shared().pauseProgram();
2642 }
2643 
resumeDebugger()2644 void InspectorController::resumeDebugger()
2645 {
2646     if (!m_debuggerEnabled)
2647         return;
2648     JavaScriptDebugServer::shared().continueProgram();
2649 }
2650 
stepOverStatementInDebugger()2651 void InspectorController::stepOverStatementInDebugger()
2652 {
2653     if (!m_debuggerEnabled)
2654         return;
2655     JavaScriptDebugServer::shared().stepOverStatement();
2656 }
2657 
stepIntoStatementInDebugger()2658 void InspectorController::stepIntoStatementInDebugger()
2659 {
2660     if (!m_debuggerEnabled)
2661         return;
2662     JavaScriptDebugServer::shared().stepIntoStatement();
2663 }
2664 
stepOutOfFunctionInDebugger()2665 void InspectorController::stepOutOfFunctionInDebugger()
2666 {
2667     if (!m_debuggerEnabled)
2668         return;
2669     JavaScriptDebugServer::shared().stepOutOfFunction();
2670 }
2671 
addBreakpoint(intptr_t sourceID,unsigned lineNumber)2672 void InspectorController::addBreakpoint(intptr_t sourceID, unsigned lineNumber)
2673 {
2674     JavaScriptDebugServer::shared().addBreakpoint(sourceID, lineNumber);
2675 }
2676 
removeBreakpoint(intptr_t sourceID,unsigned lineNumber)2677 void InspectorController::removeBreakpoint(intptr_t sourceID, unsigned lineNumber)
2678 {
2679     JavaScriptDebugServer::shared().removeBreakpoint(sourceID, lineNumber);
2680 }
2681 #endif
2682 
drawOutlinedQuad(GraphicsContext & context,const FloatQuad & quad,const Color & fillColor)2683 static void drawOutlinedQuad(GraphicsContext& context, const FloatQuad& quad, const Color& fillColor)
2684 {
2685     static const int outlineThickness = 2;
2686     static const Color outlineColor(62, 86, 180, 228);
2687 
2688     Path quadPath;
2689     quadPath.moveTo(quad.p1());
2690     quadPath.addLineTo(quad.p2());
2691     quadPath.addLineTo(quad.p3());
2692     quadPath.addLineTo(quad.p4());
2693     quadPath.closeSubpath();
2694 
2695     // Clear the quad
2696     {
2697         context.save();
2698         context.setCompositeOperation(CompositeClear);
2699         context.addPath(quadPath);
2700         context.fillPath();
2701         context.restore();
2702     }
2703 
2704     // Clip out the quad, then draw with a 2px stroke to get a pixel
2705     // of outline (because inflating a quad is hard)
2706     {
2707         context.save();
2708         context.addPath(quadPath);
2709         context.clipOut(quadPath);
2710 
2711         context.addPath(quadPath);
2712         context.setStrokeThickness(outlineThickness);
2713         context.setStrokeColor(outlineColor);
2714         context.strokePath();
2715 
2716         context.restore();
2717     }
2718 
2719     // Now do the fill
2720     context.addPath(quadPath);
2721     context.setFillColor(fillColor);
2722     context.fillPath();
2723 }
2724 
drawHighlightForBoxes(GraphicsContext & context,const Vector<FloatQuad> & lineBoxQuads,const FloatQuad & contentQuad,const FloatQuad & paddingQuad,const FloatQuad & borderQuad,const FloatQuad & marginQuad)2725 static void drawHighlightForBoxes(GraphicsContext& context, const Vector<FloatQuad>& lineBoxQuads, const FloatQuad& contentQuad, const FloatQuad& paddingQuad, const FloatQuad& borderQuad, const FloatQuad& marginQuad)
2726 {
2727     static const Color contentBoxColor(125, 173, 217, 128);
2728     static const Color paddingBoxColor(125, 173, 217, 160);
2729     static const Color borderBoxColor(125, 173, 217, 192);
2730     static const Color marginBoxColor(125, 173, 217, 228);
2731 
2732     if (!lineBoxQuads.isEmpty()) {
2733         for (size_t i = 0; i < lineBoxQuads.size(); ++i)
2734             drawOutlinedQuad(context, lineBoxQuads[i], contentBoxColor);
2735         return;
2736     }
2737 
2738     if (marginQuad != borderQuad)
2739         drawOutlinedQuad(context, marginQuad, marginBoxColor);
2740     if (borderQuad != paddingQuad)
2741         drawOutlinedQuad(context, borderQuad, borderBoxColor);
2742     if (paddingQuad != contentQuad)
2743         drawOutlinedQuad(context, paddingQuad, paddingBoxColor);
2744 
2745     drawOutlinedQuad(context, contentQuad, contentBoxColor);
2746 }
2747 
convertFromFrameToMainFrame(Frame * frame,IntRect & rect)2748 static inline void convertFromFrameToMainFrame(Frame* frame, IntRect& rect)
2749 {
2750     rect = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(rect));
2751 }
2752 
frameToMainFrameOffset(Frame * frame)2753 static inline IntSize frameToMainFrameOffset(Frame* frame)
2754 {
2755     IntPoint mainFramePoint = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint()));
2756     return mainFramePoint - IntPoint();
2757 }
2758 
drawNodeHighlight(GraphicsContext & context) const2759 void InspectorController::drawNodeHighlight(GraphicsContext& context) const
2760 {
2761     if (!m_highlightedNode)
2762         return;
2763 
2764     RenderBox* renderer = m_highlightedNode->renderBox();
2765     Frame* containingFrame = m_highlightedNode->document()->frame();
2766     if (!renderer || !containingFrame)
2767         return;
2768 
2769     IntRect contentBox = renderer->contentBoxRect();
2770 
2771     // FIXME: Should we add methods to RenderObject to obtain these rects?
2772     IntRect paddingBox(contentBox.x() - renderer->paddingLeft(), contentBox.y() - renderer->paddingTop(),
2773                        contentBox.width() + renderer->paddingLeft() + renderer->paddingRight(), contentBox.height() + renderer->paddingTop() + renderer->paddingBottom());
2774     IntRect borderBox(paddingBox.x() - renderer->borderLeft(), paddingBox.y() - renderer->borderTop(),
2775                       paddingBox.width() + renderer->borderLeft() + renderer->borderRight(), paddingBox.height() + renderer->borderTop() + renderer->borderBottom());
2776     IntRect marginBox(borderBox.x() - renderer->marginLeft(), borderBox.y() - renderer->marginTop(),
2777                       borderBox.width() + renderer->marginLeft() + renderer->marginRight(), borderBox.height() + renderer->marginTop() + renderer->marginBottom());
2778 
2779 
2780     IntSize mainFrameOffset = frameToMainFrameOffset(containingFrame);
2781 
2782     FloatQuad absContentQuad = renderer->localToAbsoluteQuad(FloatRect(contentBox));
2783     FloatQuad absPaddingQuad = renderer->localToAbsoluteQuad(FloatRect(paddingBox));
2784     FloatQuad absBorderQuad = renderer->localToAbsoluteQuad(FloatRect(borderBox));
2785     FloatQuad absMarginQuad = renderer->localToAbsoluteQuad(FloatRect(marginBox));
2786 
2787     absContentQuad.move(mainFrameOffset);
2788     absPaddingQuad.move(mainFrameOffset);
2789     absBorderQuad.move(mainFrameOffset);
2790     absMarginQuad.move(mainFrameOffset);
2791 
2792     IntRect boundingBox = renderer->absoluteBoundingBoxRect(true);
2793     boundingBox.move(mainFrameOffset);
2794 
2795     Vector<FloatQuad> lineBoxQuads;
2796     if (renderer->isInline() || (renderer->isText() && !m_highlightedNode->isSVGElement())) {
2797         // FIXME: We should show margins/padding/border for inlines.
2798         renderer->collectAbsoluteLineBoxQuads(lineBoxQuads);
2799     }
2800 
2801     for (unsigned i = 0; i < lineBoxQuads.size(); ++i)
2802         lineBoxQuads[i] += mainFrameOffset;
2803 
2804     if (lineBoxQuads.isEmpty() && contentBox.isEmpty()) {
2805         // If we have no line boxes and our content box is empty, we'll just draw our bounding box.
2806         // This can happen, e.g., with an <a> enclosing an <img style="float:right">.
2807         // FIXME: Can we make this better/more accurate? The <a> in the above case has no
2808         // width/height but the highlight makes it appear to be the size of the <img>.
2809         lineBoxQuads.append(FloatRect(boundingBox));
2810     }
2811 
2812     ASSERT(m_inspectedPage);
2813 
2814     FrameView* view = m_inspectedPage->mainFrame()->view();
2815     FloatRect overlayRect = view->visibleContentRect();
2816 
2817     if (!overlayRect.contains(boundingBox) && !boundingBox.contains(enclosingIntRect(overlayRect))) {
2818         Element* element;
2819         if (m_highlightedNode->isElementNode())
2820             element = static_cast<Element*>(m_highlightedNode.get());
2821         else
2822             element = static_cast<Element*>(m_highlightedNode->parent());
2823         overlayRect = view->visibleContentRect();
2824     }
2825 
2826     context.translate(-overlayRect.x(), -overlayRect.y());
2827 
2828     drawHighlightForBoxes(context, lineBoxQuads, absContentQuad, absPaddingQuad, absBorderQuad, absMarginQuad);
2829 }
2830 
count(const String & title,unsigned lineNumber,const String & sourceID)2831 void InspectorController::count(const String& title, unsigned lineNumber, const String& sourceID)
2832 {
2833     String identifier = title + String::format("@%s:%d", sourceID.utf8().data(), lineNumber);
2834     HashMap<String, unsigned>::iterator it = m_counts.find(identifier);
2835     int count;
2836     if (it == m_counts.end())
2837         count = 1;
2838     else {
2839         count = it->second + 1;
2840         m_counts.remove(it);
2841     }
2842 
2843     m_counts.add(identifier, count);
2844 
2845     String message = String::format("%s: %d", title.utf8().data(), count);
2846     addMessageToConsole(JSMessageSource, LogMessageLevel, message, lineNumber, sourceID);
2847 }
2848 
startTiming(const String & title)2849 void InspectorController::startTiming(const String& title)
2850 {
2851     m_times.add(title, currentTime() * 1000);
2852 }
2853 
stopTiming(const String & title,double & elapsed)2854 bool InspectorController::stopTiming(const String& title, double& elapsed)
2855 {
2856     HashMap<String, double>::iterator it = m_times.find(title);
2857     if (it == m_times.end())
2858         return false;
2859 
2860     double startTime = it->second;
2861     m_times.remove(it);
2862 
2863     elapsed = currentTime() * 1000 - startTime;
2864     return true;
2865 }
2866 
handleException(JSContextRef context,JSValueRef exception,unsigned lineNumber) const2867 bool InspectorController::handleException(JSContextRef context, JSValueRef exception, unsigned lineNumber) const
2868 {
2869     if (!exception)
2870         return false;
2871 
2872     if (!m_page)
2873         return true;
2874 
2875     String message = toString(context, exception, 0);
2876     String file(__FILE__);
2877 
2878     if (JSObjectRef exceptionObject = JSValueToObject(context, exception, 0)) {
2879         JSValueRef lineValue = JSObjectGetProperty(context, exceptionObject, jsStringRef("line").get(), NULL);
2880         if (lineValue)
2881             lineNumber = static_cast<unsigned>(JSValueToNumber(context, lineValue, 0));
2882 
2883         JSValueRef fileValue = JSObjectGetProperty(context, exceptionObject, jsStringRef("sourceURL").get(), NULL);
2884         if (fileValue)
2885             file = toString(context, fileValue, 0);
2886     }
2887 
2888     m_page->mainFrame()->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, lineNumber, file);
2889     return true;
2890 }
2891 
2892 #if ENABLE(JAVASCRIPT_DEBUGGER)
2893 
2894 // JavaScriptDebugListener functions
2895 
didParseSource(ExecState *,const SourceCode & source)2896 void InspectorController::didParseSource(ExecState*, const SourceCode& source)
2897 {
2898     JSValueRef sourceIDValue = JSValueMakeNumber(m_scriptContext, source.provider()->asID());
2899     JSValueRef sourceURLValue = JSValueMakeString(m_scriptContext, jsStringRef(source.provider()->url()).get());
2900     JSValueRef sourceValue = JSValueMakeString(m_scriptContext, jsStringRef(source).get());
2901     JSValueRef firstLineValue = JSValueMakeNumber(m_scriptContext, source.firstLine());
2902 
2903     JSValueRef exception = 0;
2904     JSValueRef arguments[] = { sourceIDValue, sourceURLValue, sourceValue, firstLineValue };
2905     callFunction(m_scriptContext, m_scriptObject, "parsedScriptSource", 4, arguments, exception);
2906 }
2907 
failedToParseSource(ExecState *,const SourceCode & source,int errorLine,const UString & errorMessage)2908 void InspectorController::failedToParseSource(ExecState*, const SourceCode& source, int errorLine, const UString& errorMessage)
2909 {
2910     JSValueRef sourceURLValue = JSValueMakeString(m_scriptContext, jsStringRef(source.provider()->url()).get());
2911     JSValueRef sourceValue = JSValueMakeString(m_scriptContext, jsStringRef(source.data()).get());
2912     JSValueRef firstLineValue = JSValueMakeNumber(m_scriptContext, source.firstLine());
2913     JSValueRef errorLineValue = JSValueMakeNumber(m_scriptContext, errorLine);
2914     JSValueRef errorMessageValue = JSValueMakeString(m_scriptContext, jsStringRef(errorMessage).get());
2915 
2916     JSValueRef exception = 0;
2917     JSValueRef arguments[] = { sourceURLValue, sourceValue, firstLineValue, errorLineValue, errorMessageValue };
2918     callFunction(m_scriptContext, m_scriptObject, "failedToParseScriptSource", 5, arguments, exception);
2919 }
2920 
didPause()2921 void InspectorController::didPause()
2922 {
2923     JSValueRef exception = 0;
2924     callFunction(m_scriptContext, m_scriptObject, "pausedScript", 0, 0, exception);
2925 }
2926 
2927 #endif
2928 
2929 } // namespace WebCore
2930