• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "config.h"
30 #include "Console.h"
31 
32 #include "ChromeClient.h"
33 #include "CString.h"
34 #include "Frame.h"
35 #include "FrameLoader.h"
36 #include "FrameTree.h"
37 #include "InspectorController.h"
38 #include "Page.h"
39 #include "PageGroup.h"
40 #include "PlatformString.h"
41 
42 #if USE(JSC)
43 #include <profiler/Profiler.h>
44 #endif
45 
46 #include "ScriptCallStack.h"
47 #include <stdio.h>
48 
49 namespace WebCore {
50 
Console(Frame * frame)51 Console::Console(Frame* frame)
52     : m_frame(frame)
53 {
54 }
55 
disconnectFrame()56 void Console::disconnectFrame()
57 {
58     m_frame = 0;
59 }
60 
printSourceURLAndLine(const String & sourceURL,unsigned lineNumber)61 static void printSourceURLAndLine(const String& sourceURL, unsigned lineNumber)
62 {
63     if (!sourceURL.isEmpty()) {
64         if (lineNumber > 0)
65             printf("%s:%d: ", sourceURL.utf8().data(), lineNumber);
66         else
67             printf("%s: ", sourceURL.utf8().data());
68     }
69 }
70 
getFirstArgumentAsString(const ScriptCallFrame & callFrame,String & result,bool checkForNullOrUndefined=false)71 static bool getFirstArgumentAsString(const ScriptCallFrame& callFrame, String& result, bool checkForNullOrUndefined = false)
72 {
73     if (!callFrame.argumentCount())
74         return false;
75 
76     const ScriptValue& value = callFrame.argumentAt(0);
77     if (checkForNullOrUndefined && (value.isNull() || value.isUndefined()))
78         return false;
79 
80     return value.getString(result);
81 }
82 
printMessageSourceAndLevelPrefix(MessageSource source,MessageLevel level)83 static void printMessageSourceAndLevelPrefix(MessageSource source, MessageLevel level)
84 {
85     const char* sourceString;
86     switch (source) {
87         case HTMLMessageSource:
88             sourceString = "HTML";
89             break;
90         case WMLMessageSource:
91             sourceString = "WML";
92             break;
93         case XMLMessageSource:
94             sourceString = "XML";
95             break;
96         case JSMessageSource:
97             sourceString = "JS";
98             break;
99         case CSSMessageSource:
100             sourceString = "CSS";
101             break;
102         default:
103             ASSERT_NOT_REACHED();
104             // Fall thru.
105         case OtherMessageSource:
106             sourceString = "OTHER";
107             break;
108     }
109 
110     const char* levelString;
111     switch (level) {
112         case TipMessageLevel:
113             levelString = "TIP";
114             break;
115         default:
116             ASSERT_NOT_REACHED();
117             // Fall thru.
118         case LogMessageLevel:
119             levelString = "LOG";
120             break;
121         case WarningMessageLevel:
122             levelString = "WARN";
123             break;
124         case ErrorMessageLevel:
125             levelString = "ERROR";
126             break;
127     }
128 
129     printf("%s %s:", sourceString, levelString);
130 }
131 
addMessage(MessageSource source,MessageLevel level,const String & message,unsigned lineNumber,const String & sourceURL)132 void Console::addMessage(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL)
133 {
134     Page* page = this->page();
135     if (!page)
136         return;
137 
138     if (source == JSMessageSource || source == WMLMessageSource)
139         page->chrome()->client()->addMessageToConsole(message, lineNumber, sourceURL);
140 
141     page->inspectorController()->addMessageToConsole(source, level, message, lineNumber, sourceURL);
142 
143     if (!Console::shouldPrintExceptions())
144         return;
145 
146     printSourceURLAndLine(sourceURL, lineNumber);
147     printMessageSourceAndLevelPrefix(source, level);
148 
149     printf(" %s\n", message.utf8().data());
150 }
151 
addMessage(MessageLevel level,ScriptCallStack * callStack,bool acceptNoArguments)152 void Console::addMessage(MessageLevel level, ScriptCallStack* callStack, bool acceptNoArguments) {
153     Page* page = this->page();
154     if (!page)
155         return;
156 
157     const ScriptCallFrame& lastCaller = callStack->at(0);
158 
159     if (!acceptNoArguments && !lastCaller.argumentCount())
160         return;
161 
162     String message;
163     if (getFirstArgumentAsString(lastCaller, message))
164         page->chrome()->client()->addMessageToConsole(message, lastCaller.lineNumber(), lastCaller.sourceURL().prettyURL());
165 
166     page->inspectorController()->addMessageToConsole(JSMessageSource, level, callStack);
167 
168     if (!Console::shouldPrintExceptions())
169         return;
170 
171     printSourceURLAndLine(lastCaller.sourceURL().prettyURL(), 0);
172     printMessageSourceAndLevelPrefix(JSMessageSource, level);
173 
174     for (unsigned i = 0; i < lastCaller.argumentCount(); ++i) {
175         String argAsString;
176         if (lastCaller.argumentAt(i).getString(argAsString))
177             printf(" %s", argAsString.utf8().data());
178     }
179     printf("\n");
180 }
181 
debug(ScriptCallStack * callStack)182 void Console::debug(ScriptCallStack* callStack)
183 {
184     // In Firebug, console.debug has the same behavior as console.log. So we'll do the same.
185     log(callStack);
186 }
187 
error(ScriptCallStack * callStack)188 void Console::error(ScriptCallStack* callStack)
189 {
190     addMessage(ErrorMessageLevel, callStack);
191 }
192 
info(ScriptCallStack * callStack)193 void Console::info(ScriptCallStack* callStack)
194 {
195     log(callStack);
196 }
197 
log(ScriptCallStack * callStack)198 void Console::log(ScriptCallStack* callStack)
199 {
200     addMessage(LogMessageLevel, callStack);
201 }
202 
dir(ScriptCallStack * callStack)203 void Console::dir(ScriptCallStack* callStack)
204 {
205     addMessage(ObjectMessageLevel, callStack);
206 }
207 
dirxml(ScriptCallStack * callStack)208 void Console::dirxml(ScriptCallStack* callStack)
209 {
210     addMessage(NodeMessageLevel, callStack);
211 }
212 
trace(ScriptCallStack * callStack)213 void Console::trace(ScriptCallStack* callStack)
214 {
215     addMessage(TraceMessageLevel, callStack, true);
216 
217     if (!shouldPrintExceptions())
218         return;
219 
220     printf("Stack Trace\n");
221     for (unsigned i = 0; i < callStack->size(); ++i) {
222         String functionName = String(callStack->at(i).functionName());
223         printf("\t%s\n", functionName.utf8().data());
224     }
225 }
226 
assertCondition(bool condition,ScriptCallStack * callStack)227 void Console::assertCondition(bool condition, ScriptCallStack* callStack)
228 {
229     if (condition)
230         return;
231 
232     // FIXME: <https://bugs.webkit.org/show_bug.cgi?id=19135> It would be nice to prefix assertion failures with a message like "Assertion failed: ".
233     addMessage(ErrorMessageLevel, callStack, true);
234 }
235 
count(ScriptCallStack * callStack)236 void Console::count(ScriptCallStack* callStack)
237 {
238     Page* page = this->page();
239     if (!page)
240         return;
241 
242     const ScriptCallFrame& lastCaller = callStack->at(0);
243     // Follow Firebug's behavior of counting with null and undefined title in
244     // the same bucket as no argument
245     String title;
246     getFirstArgumentAsString(lastCaller, title);
247 
248     page->inspectorController()->count(title, lastCaller.lineNumber(), lastCaller.sourceURL().string());
249 }
250 
251 #if USE(JSC)
252 
profile(const JSC::UString & title,ScriptCallStack * callStack)253 void Console::profile(const JSC::UString& title, ScriptCallStack* callStack)
254 {
255     Page* page = this->page();
256     if (!page)
257         return;
258 
259     if (title.isNull())
260         return;
261 
262     // FIXME: log a console message when profiling is disabled.
263     if (!page->inspectorController()->profilerEnabled())
264         return;
265 
266     JSC::Profiler::profiler()->startProfiling(callStack->state(), title);
267 }
268 
profileEnd(const JSC::UString & title,ScriptCallStack * callStack)269 void Console::profileEnd(const JSC::UString& title, ScriptCallStack* callStack)
270 {
271     Page* page = this->page();
272     if (!page)
273         return;
274 
275     if (!page->inspectorController()->profilerEnabled())
276         return;
277 
278     RefPtr<JSC::Profile> profile = JSC::Profiler::profiler()->stopProfiling(callStack->state(), title);
279     if (!profile)
280         return;
281 
282     m_profiles.append(profile);
283 
284     if (Page* page = this->page()) {
285         const ScriptCallFrame& lastCaller = callStack->at(0);
286         page->inspectorController()->addProfile(profile, lastCaller.lineNumber(), lastCaller.sourceURL());
287     }
288 }
289 
290 #endif
291 
time(const String & title)292 void Console::time(const String& title)
293 {
294     Page* page = this->page();
295     if (!page)
296         return;
297 
298     // Follow Firebug's behavior of requiring a title that is not null or
299     // undefined for timing functions
300     if (title.isNull())
301         return;
302 
303     page->inspectorController()->startTiming(title);
304 }
305 
timeEnd(const String & title,ScriptCallStack * callStack)306 void Console::timeEnd(const String& title, ScriptCallStack* callStack)
307 {
308     Page* page = this->page();
309     if (!page)
310         return;
311 
312     // Follow Firebug's behavior of requiring a title that is not null or
313     // undefined for timing functions
314     if (title.isNull())
315         return;
316 
317     double elapsed;
318     if (!page->inspectorController()->stopTiming(title, elapsed))
319         return;
320 
321     String message = title + String::format(": %.0fms", elapsed);
322 
323     const ScriptCallFrame& lastCaller = callStack->at(0);
324     page->inspectorController()->addMessageToConsole(JSMessageSource, LogMessageLevel, message, lastCaller.lineNumber(), lastCaller.sourceURL().string());
325 }
326 
group(ScriptCallStack * callStack)327 void Console::group(ScriptCallStack* callStack)
328 {
329     Page* page = this->page();
330     if (!page)
331         return;
332 
333     page->inspectorController()->startGroup(JSMessageSource, callStack);
334 }
335 
groupEnd()336 void Console::groupEnd()
337 {
338     Page* page = this->page();
339     if (!page)
340         return;
341 
342     page->inspectorController()->endGroup(JSMessageSource, 0, String());
343 }
344 
warn(ScriptCallStack * callStack)345 void Console::warn(ScriptCallStack* callStack)
346 {
347     addMessage(WarningMessageLevel, callStack);
348 }
349 
350 static bool printExceptions = false;
351 
shouldPrintExceptions()352 bool Console::shouldPrintExceptions()
353 {
354     return printExceptions;
355 }
356 
setShouldPrintExceptions(bool print)357 void Console::setShouldPrintExceptions(bool print)
358 {
359     printExceptions = print;
360 }
361 
page() const362 Page* Console::page() const
363 {
364     if (!m_frame)
365         return 0;
366     return m_frame->page();
367 }
368 
369 } // namespace WebCore
370