• 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 "Chrome.h"
33 #include "ChromeClient.h"
34 #include "Frame.h"
35 #include "FrameLoader.h"
36 #include "FrameTree.h"
37 #include "InspectorConsoleInstrumentation.h"
38 #include "InspectorController.h"
39 #include "MemoryInfo.h"
40 #include "Page.h"
41 #include "PageGroup.h"
42 #include "PlatformString.h"
43 
44 #include "ScriptArguments.h"
45 #include "ScriptCallStack.h"
46 #include "ScriptProfile.h"
47 #include "ScriptProfiler.h"
48 #include <stdio.h>
49 #include <wtf/text/CString.h>
50 #include <wtf/UnusedParam.h>
51 
52 namespace WebCore {
53 
Console(Frame * frame)54 Console::Console(Frame* frame)
55     : m_frame(frame)
56 {
57 }
58 
frame() const59 Frame* Console::frame() const
60 {
61     return m_frame;
62 }
63 
disconnectFrame()64 void Console::disconnectFrame()
65 {
66     if (m_memory)
67         m_memory = 0;
68     m_frame = 0;
69 }
70 
printSourceURLAndLine(const String & sourceURL,unsigned lineNumber)71 static void printSourceURLAndLine(const String& sourceURL, unsigned lineNumber)
72 {
73     if (!sourceURL.isEmpty()) {
74         if (lineNumber > 0)
75             printf("%s:%d: ", sourceURL.utf8().data(), lineNumber);
76         else
77             printf("%s: ", sourceURL.utf8().data());
78     }
79 }
80 
printMessageSourceAndLevelPrefix(MessageSource source,MessageLevel level)81 static void printMessageSourceAndLevelPrefix(MessageSource source, MessageLevel level)
82 {
83     const char* sourceString;
84     switch (source) {
85     case HTMLMessageSource:
86         sourceString = "HTML";
87         break;
88     case WMLMessageSource:
89         sourceString = "WML";
90         break;
91     case XMLMessageSource:
92         sourceString = "XML";
93         break;
94     case JSMessageSource:
95         sourceString = "JS";
96         break;
97     case CSSMessageSource:
98         sourceString = "CSS";
99         break;
100     case OtherMessageSource:
101         sourceString = "OTHER";
102         break;
103     default:
104         ASSERT_NOT_REACHED();
105         sourceString = "UNKNOWN";
106         break;
107     }
108 
109     const char* levelString;
110     switch (level) {
111     case TipMessageLevel:
112         levelString = "TIP";
113         break;
114     case LogMessageLevel:
115         levelString = "LOG";
116         break;
117     case WarningMessageLevel:
118         levelString = "WARN";
119         break;
120     case ErrorMessageLevel:
121         levelString = "ERROR";
122         break;
123     case DebugMessageLevel:
124         levelString = "DEBUG";
125         break;
126     default:
127         ASSERT_NOT_REACHED();
128         levelString = "UNKNOWN";
129         break;
130     }
131 
132     printf("%s %s:", sourceString, levelString);
133 }
134 
addMessage(MessageSource source,MessageType type,MessageLevel level,const String & message,unsigned lineNumber,const String & sourceURL)135 void Console::addMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL)
136 {
137     addMessage(source, type, level, message, lineNumber, sourceURL, 0);
138 }
139 
addMessage(MessageSource source,MessageType type,MessageLevel level,const String & message,unsigned lineNumber,const String & sourceURL,PassRefPtr<ScriptCallStack> callStack)140 void Console::addMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL, PassRefPtr<ScriptCallStack> callStack)
141 {
142     Page* page = this->page();
143     if (!page)
144         return;
145 
146     page->chrome()->client()->addMessageToConsole(source, type, level, message, lineNumber, sourceURL);
147 
148     if (callStack)
149         InspectorInstrumentation::addMessageToConsole(page, source, type, level, message, 0, callStack);
150     else
151         InspectorInstrumentation::addMessageToConsole(page, source, type, level, message, lineNumber, sourceURL);
152 
153     if (!Console::shouldPrintExceptions())
154         return;
155 
156     printSourceURLAndLine(sourceURL, lineNumber);
157     printMessageSourceAndLevelPrefix(source, level);
158 
159     printf(" %s\n", message.utf8().data());
160 }
161 
addMessage(MessageType type,MessageLevel level,PassRefPtr<ScriptArguments> prpArguments,PassRefPtr<ScriptCallStack> prpCallStack,bool acceptNoArguments)162 void Console::addMessage(MessageType type, MessageLevel level, PassRefPtr<ScriptArguments> prpArguments,  PassRefPtr<ScriptCallStack> prpCallStack, bool acceptNoArguments)
163 {
164     RefPtr<ScriptArguments> arguments = prpArguments;
165     RefPtr<ScriptCallStack> callStack = prpCallStack;
166 
167     Page* page = this->page();
168     if (!page)
169         return;
170 
171     const ScriptCallFrame& lastCaller = callStack->at(0);
172 
173     if (!acceptNoArguments && !arguments->argumentCount())
174         return;
175 
176     if (Console::shouldPrintExceptions()) {
177         printSourceURLAndLine(lastCaller.sourceURL(), 0);
178         printMessageSourceAndLevelPrefix(JSMessageSource, level);
179 
180         for (unsigned i = 0; i < arguments->argumentCount(); ++i) {
181             String argAsString;
182             if (arguments->argumentAt(i).getString(arguments->globalState(), argAsString))
183                 printf(" %s", argAsString.utf8().data());
184         }
185         printf("\n");
186     }
187 
188     String message;
189     if (arguments->getFirstArgumentAsString(message))
190         page->chrome()->client()->addMessageToConsole(JSMessageSource, type, level, message, lastCaller.lineNumber(), lastCaller.sourceURL());
191 
192     InspectorInstrumentation::addMessageToConsole(page, JSMessageSource, type, level, message, arguments, callStack);
193 }
194 
debug(PassRefPtr<ScriptArguments> arguments,PassRefPtr<ScriptCallStack> callStack)195 void Console::debug(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
196 {
197     // In Firebug, console.debug has the same behavior as console.log. So we'll do the same.
198     log(arguments, callStack);
199 }
200 
error(PassRefPtr<ScriptArguments> arguments,PassRefPtr<ScriptCallStack> callStack)201 void Console::error(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
202 {
203     addMessage(LogMessageType, ErrorMessageLevel, arguments, callStack);
204 }
205 
info(PassRefPtr<ScriptArguments> arguments,PassRefPtr<ScriptCallStack> callStack)206 void Console::info(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
207 {
208     log(arguments, callStack);
209 }
210 
log(PassRefPtr<ScriptArguments> arguments,PassRefPtr<ScriptCallStack> callStack)211 void Console::log(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
212 {
213     addMessage(LogMessageType, LogMessageLevel, arguments, callStack);
214 }
215 
dir(PassRefPtr<ScriptArguments> arguments,PassRefPtr<ScriptCallStack> callStack)216 void Console::dir(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
217 {
218     addMessage(ObjectMessageType, LogMessageLevel, arguments, callStack);
219 }
220 
dirxml(PassRefPtr<ScriptArguments> arguments,PassRefPtr<ScriptCallStack> callStack)221 void Console::dirxml(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
222 {
223     // The standard behavior of our console.log will print the DOM tree for nodes.
224     log(arguments, callStack);
225 }
226 
trace(PassRefPtr<ScriptArguments> arguments,PassRefPtr<ScriptCallStack> prpCallStack)227 void Console::trace(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> prpCallStack)
228 {
229     RefPtr<ScriptCallStack> callStack = prpCallStack;
230     addMessage(TraceMessageType, LogMessageLevel, arguments, callStack, true);
231 
232     if (!shouldPrintExceptions())
233         return;
234 
235     printf("Stack Trace\n");
236     for (unsigned i = 0; i < callStack->size(); ++i) {
237         String functionName = String(callStack->at(i).functionName());
238         printf("\t%s\n", functionName.utf8().data());
239     }
240 }
241 
assertCondition(bool condition,PassRefPtr<ScriptArguments> arguments,PassRefPtr<ScriptCallStack> callStack)242 void Console::assertCondition(bool condition, PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
243 {
244     if (condition)
245         return;
246 
247     addMessage(AssertMessageType, ErrorMessageLevel, arguments, callStack, true);
248 }
249 
count(PassRefPtr<ScriptArguments> arguments,PassRefPtr<ScriptCallStack> callStack)250 void Console::count(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
251 {
252     InspectorInstrumentation::consoleCount(page(), arguments, callStack);
253 }
254 
markTimeline(PassRefPtr<ScriptArguments> arguments,PassRefPtr<ScriptCallStack>)255 void Console::markTimeline(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack>)
256 {
257     InspectorInstrumentation::consoleMarkTimeline(page(), arguments);
258 }
259 
260 #if ENABLE(JAVASCRIPT_DEBUGGER)
261 
profile(const String & title,ScriptState * state,PassRefPtr<ScriptCallStack> callStack)262 void Console::profile(const String& title, ScriptState* state, PassRefPtr<ScriptCallStack> callStack)
263 {
264     Page* page = this->page();
265     if (!page)
266         return;
267 
268     // FIXME: log a console message when profiling is disabled.
269     if (!InspectorInstrumentation::profilerEnabled(page))
270         return;
271 
272     String resolvedTitle = title;
273     if (title.isNull()) // no title so give it the next user initiated profile title.
274         resolvedTitle = InspectorInstrumentation::getCurrentUserInitiatedProfileName(page, true);
275 
276     ScriptProfiler::start(state, resolvedTitle);
277 
278     const ScriptCallFrame& lastCaller = callStack->at(0);
279     InspectorInstrumentation::addStartProfilingMessageToConsole(page, resolvedTitle, lastCaller.lineNumber(), lastCaller.sourceURL());
280 }
281 
profileEnd(const String & title,ScriptState * state,PassRefPtr<ScriptCallStack> callStack)282 void Console::profileEnd(const String& title, ScriptState* state, PassRefPtr<ScriptCallStack> callStack)
283 {
284     Page* page = this->page();
285     if (!page)
286         return;
287 
288     if (!InspectorInstrumentation::profilerEnabled(page))
289         return;
290 
291     RefPtr<ScriptProfile> profile = ScriptProfiler::stop(state, title);
292     if (!profile)
293         return;
294 
295     m_profiles.append(profile);
296     InspectorInstrumentation::addProfile(page, profile, callStack);
297 }
298 
299 #endif
300 
time(const String & title)301 void Console::time(const String& title)
302 {
303     InspectorInstrumentation::startConsoleTiming(page(), title);
304 }
305 
timeEnd(const String & title,PassRefPtr<ScriptArguments>,PassRefPtr<ScriptCallStack> callStack)306 void Console::timeEnd(const String& title, PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack> callStack)
307 {
308     InspectorInstrumentation::stopConsoleTiming(page(), title, callStack);
309 }
310 
group(PassRefPtr<ScriptArguments> arguments,PassRefPtr<ScriptCallStack> callStack)311 void Console::group(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
312 {
313     InspectorInstrumentation::addMessageToConsole(page(), JSMessageSource, StartGroupMessageType, LogMessageLevel, String(), arguments, callStack);
314 }
315 
groupCollapsed(PassRefPtr<ScriptArguments> arguments,PassRefPtr<ScriptCallStack> callStack)316 void Console::groupCollapsed(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
317 {
318     InspectorInstrumentation::addMessageToConsole(page(), JSMessageSource, StartGroupCollapsedMessageType, LogMessageLevel, String(), arguments, callStack);
319 }
320 
groupEnd()321 void Console::groupEnd()
322 {
323     InspectorInstrumentation::addMessageToConsole(page(), JSMessageSource, EndGroupMessageType, LogMessageLevel, String(), 0, String());
324 }
325 
shouldCaptureFullStackTrace() const326 bool Console::shouldCaptureFullStackTrace() const
327 {
328 #if ENABLE(INSPECTOR)
329     Page* page = this->page();
330     if (!page)
331         return false;
332 
333     return page->inspectorController()->hasFrontend();
334 #else
335     return false;
336 #endif
337 }
338 
warn(PassRefPtr<ScriptArguments> arguments,PassRefPtr<ScriptCallStack> callStack)339 void Console::warn(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
340 {
341     addMessage(LogMessageType, WarningMessageLevel, arguments, callStack);
342 }
343 
memory() const344 MemoryInfo* Console::memory() const
345 {
346     m_memory = MemoryInfo::create(m_frame);
347     return m_memory.get();
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