Home | History | Annotate | Download | only in page
      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 
     54 Console::Console(Frame* frame)
     55     : m_frame(frame)
     56 {
     57 }
     58 
     59 Frame* Console::frame() const
     60 {
     61     return m_frame;
     62 }
     63 
     64 void Console::disconnectFrame()
     65 {
     66     if (m_memory)
     67         m_memory = 0;
     68     m_frame = 0;
     69 }
     70 
     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 
     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 
    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 
    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 
    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 
    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 
    201 void Console::error(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
    202 {
    203     addMessage(LogMessageType, ErrorMessageLevel, arguments, callStack);
    204 }
    205 
    206 void Console::info(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
    207 {
    208     log(arguments, callStack);
    209 }
    210 
    211 void Console::log(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
    212 {
    213     addMessage(LogMessageType, LogMessageLevel, arguments, callStack);
    214 }
    215 
    216 void Console::dir(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
    217 {
    218     addMessage(ObjectMessageType, LogMessageLevel, arguments, callStack);
    219 }
    220 
    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 
    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 
    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 
    250 void Console::count(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
    251 {
    252     InspectorInstrumentation::consoleCount(page(), arguments, callStack);
    253 }
    254 
    255 void Console::markTimeline(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack>)
    256 {
    257     InspectorInstrumentation::consoleMarkTimeline(page(), arguments);
    258 }
    259 
    260 #if ENABLE(JAVASCRIPT_DEBUGGER)
    261 
    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 
    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 
    301 void Console::time(const String& title)
    302 {
    303     InspectorInstrumentation::startConsoleTiming(page(), title);
    304 }
    305 
    306 void Console::timeEnd(const String& title, PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack> callStack)
    307 {
    308     InspectorInstrumentation::stopConsoleTiming(page(), title, callStack);
    309 }
    310 
    311 void Console::group(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
    312 {
    313     InspectorInstrumentation::addMessageToConsole(page(), JSMessageSource, StartGroupMessageType, LogMessageLevel, String(), arguments, callStack);
    314 }
    315 
    316 void Console::groupCollapsed(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
    317 {
    318     InspectorInstrumentation::addMessageToConsole(page(), JSMessageSource, StartGroupCollapsedMessageType, LogMessageLevel, String(), arguments, callStack);
    319 }
    320 
    321 void Console::groupEnd()
    322 {
    323     InspectorInstrumentation::addMessageToConsole(page(), JSMessageSource, EndGroupMessageType, LogMessageLevel, String(), 0, String());
    324 }
    325 
    326 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 
    339 void Console::warn(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
    340 {
    341     addMessage(LogMessageType, WarningMessageLevel, arguments, callStack);
    342 }
    343 
    344 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 
    352 bool Console::shouldPrintExceptions()
    353 {
    354     return printExceptions;
    355 }
    356 
    357 void Console::setShouldPrintExceptions(bool print)
    358 {
    359     printExceptions = print;
    360 }
    361 
    362 Page* Console::page() const
    363 {
    364     if (!m_frame)
    365         return 0;
    366     return m_frame->page();
    367 }
    368 
    369 } // namespace WebCore
    370