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