webengine/osswebengine/WebKitTools/Drosera/DebuggerDocument.cpp
changeset 0 dd21522fd290
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     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 "DebuggerDocument.h"
       
    31 
       
    32 #include "DebuggerClient.h"
       
    33 
       
    34 #include <JavaScriptCore/JSContextRef.h>
       
    35 #include <JavaScriptCore/JSRetainPtr.h>
       
    36 #include <JavaScriptCore/JSStringRef.h>
       
    37 #include <JavaScriptCore/JSStringRefCF.h>
       
    38 #include <JavaScriptCore/RetainPtr.h>
       
    39 #include <JavaScriptCore/Vector.h>
       
    40 
       
    41 DebuggerDocument::DebuggerDocument(DebuggerClient* debugger)
       
    42     : m_debuggerClient(debugger)
       
    43 {
       
    44     ASSERT(m_debuggerClient);
       
    45 }
       
    46 
       
    47 //-- Callbacks
       
    48 
       
    49 JSValueRef DebuggerDocument::breakpointEditorHTMLCallback(JSContextRef context, JSObjectRef /*function*/, JSObjectRef /*thisObject*/, size_t /*argumentCount*/, const JSValueRef /*arguments*/[], JSValueRef* /*exception*/)
       
    50 {
       
    51     RetainPtr<CFURLRef> htmlURLRef(AdoptCF, ::CFBundleCopyResourceURL(::CFBundleGetBundleWithIdentifier(CFSTR("org.webkit.drosera")), CFSTR("breakpointEditor"), CFSTR("html"), 0));
       
    52     if (!htmlURLRef)
       
    53         return JSValueMakeUndefined(context);
       
    54 
       
    55     // FIXME: I'm open to a better way to do this.  We convert from UInt8 to CFString to JSString (3 string types!)
       
    56     RetainPtr<CFReadStreamRef> readStreamRef(AdoptCF, CFReadStreamCreateWithFile(0, htmlURLRef.get()));
       
    57     CFReadStreamRef readStream = readStreamRef.get();
       
    58 
       
    59     if (!CFReadStreamOpen(readStream))
       
    60         return JSValueMakeUndefined(context);
       
    61 
       
    62     // Large enough for current BreakPointEditor.html but won't need to be changed if that file changes 
       
    63     // because we loop over the entire file and read it in bufferLength pieces at a time
       
    64     const CFIndex bufferLength = 740;
       
    65     UInt8 buffer[bufferLength];
       
    66     Vector<UInt8, bufferLength> charBuffer;
       
    67     CFIndex readResult = bufferLength;
       
    68     while (readResult == bufferLength) {
       
    69         readResult = CFReadStreamRead(readStream, buffer, bufferLength);
       
    70 
       
    71         // Error condition (-1) will not copy any data
       
    72         for (int i = 0; i < readResult; i++)
       
    73             charBuffer.append(buffer[i]);
       
    74     }
       
    75 
       
    76     CFReadStreamClose(readStream);
       
    77     if (readResult == -1)
       
    78         return JSValueMakeUndefined(context);
       
    79 
       
    80     // FIXME: Is there a way to determine the encoding?
       
    81     RetainPtr<CFStringRef> fileContents(AdoptCF, CFStringCreateWithBytes(0, charBuffer.data(), charBuffer.size(), kCFStringEncodingUTF8, true));
       
    82     JSRetainPtr<JSStringRef> fileContentsJS(Adopt, JSStringCreateWithCFString(fileContents.get()));
       
    83     JSValueRef ret = JSValueMakeString(context, fileContentsJS.get());
       
    84 
       
    85     return ret;
       
    86 }
       
    87 
       
    88 JSValueRef DebuggerDocument::pauseCallback(JSContextRef context, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef /*arguments*/[], JSValueRef* /*exception*/)
       
    89 {
       
    90     DebuggerDocument* debuggerDocument = reinterpret_cast<DebuggerDocument*>(JSObjectGetPrivate(thisObject));
       
    91 
       
    92     debuggerDocument->platformPause();
       
    93     return JSValueMakeUndefined(context);
       
    94 }
       
    95 
       
    96 JSValueRef DebuggerDocument::resumeCallback(JSContextRef context, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef /*arguments*/[], JSValueRef* /*exception*/)
       
    97 {
       
    98     DebuggerDocument* debuggerDocument = reinterpret_cast<DebuggerDocument*>(JSObjectGetPrivate(thisObject));
       
    99     debuggerDocument->platformResume();
       
   100     return JSValueMakeUndefined(context);
       
   101 }
       
   102 
       
   103 JSValueRef DebuggerDocument::stepIntoCallback(JSContextRef context, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef /*arguments*/[], JSValueRef* /*exception*/)
       
   104 {
       
   105     DebuggerDocument* debuggerDocument = reinterpret_cast<DebuggerDocument*>(JSObjectGetPrivate(thisObject));
       
   106     debuggerDocument->platformStepInto();
       
   107     return JSValueMakeUndefined(context);
       
   108 }
       
   109 
       
   110 JSValueRef DebuggerDocument::evaluateScriptCallback(JSContextRef context, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
       
   111 {
       
   112     DebuggerDocument* debuggerDocument = reinterpret_cast<DebuggerDocument*>(JSObjectGetPrivate(thisObject));
       
   113     if (argumentCount < 2)
       
   114         return JSValueMakeUndefined(context);
       
   115 
       
   116     if (!JSValueIsNumber(context, arguments[1]))
       
   117         return JSValueMakeUndefined(context);
       
   118     
       
   119     double callFrame = JSValueToNumber(context, arguments[1], exception);
       
   120     ASSERT(!*exception);
       
   121 
       
   122     JSRetainPtr<JSStringRef> script(Adopt, JSValueToStringCopy(context, arguments[0], exception));
       
   123     ASSERT(!*exception);
       
   124 
       
   125     JSValueRef ret = debuggerDocument->platformEvaluateScript(context, script.get(), (int)callFrame);
       
   126 
       
   127     return ret;
       
   128 }
       
   129 
       
   130 JSValueRef DebuggerDocument::currentFunctionStackCallback(JSContextRef context, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef /*arguments*/[], JSValueRef* exception)
       
   131 {
       
   132     DebuggerDocument* debuggerDocument = reinterpret_cast<DebuggerDocument*>(JSObjectGetPrivate(thisObject));
       
   133     Vector<JSValueRef> stack;
       
   134     debuggerDocument->getPlatformCurrentFunctionStack(context, stack);
       
   135     return DebuggerDocument::toJSArray(context, stack, exception);
       
   136 }
       
   137 
       
   138 JSValueRef DebuggerDocument::localScopeVariableNamesForCallFrameCallback(JSContextRef context, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
       
   139 {
       
   140     DebuggerDocument* debuggerDocument = reinterpret_cast<DebuggerDocument*>(JSObjectGetPrivate(thisObject));
       
   141     if (argumentCount < 1)
       
   142         return JSValueMakeUndefined(context);
       
   143 
       
   144     if (!JSValueIsNumber(context, arguments[0]))
       
   145         return JSValueMakeUndefined(context);    
       
   146 
       
   147     double callFrame = JSValueToNumber(context, arguments[0], exception);
       
   148     ASSERT(!*exception);
       
   149 
       
   150     // Get the variable names
       
   151     Vector<JSValueRef> localVariableNames;
       
   152 
       
   153     debuggerDocument->getPlatformLocalScopeVariableNamesForCallFrame(context, static_cast<int>(callFrame), localVariableNames);
       
   154     return DebuggerDocument::toJSArray(context, localVariableNames, exception);
       
   155 }
       
   156 
       
   157 JSValueRef DebuggerDocument::valueForScopeVariableNamedCallback(JSContextRef context, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
       
   158 {
       
   159     DebuggerDocument* debuggerDocument = reinterpret_cast<DebuggerDocument*>(JSObjectGetPrivate(thisObject));
       
   160 
       
   161     if (argumentCount < 2)
       
   162         return JSValueMakeUndefined(context);
       
   163 
       
   164     if (!JSValueIsString(context, arguments[0]))
       
   165         return JSValueMakeUndefined(context);
       
   166 
       
   167     JSRetainPtr<JSStringRef> key(Adopt, JSValueToStringCopy(context, arguments[0], exception));
       
   168     ASSERT(!*exception);
       
   169 
       
   170     if (!JSValueIsNumber(context, arguments[1]))
       
   171         return JSValueMakeUndefined(context);
       
   172 
       
   173     double callFrame = JSValueToNumber(context, arguments[1], exception);
       
   174     ASSERT(!*exception);
       
   175 
       
   176     return debuggerDocument->platformValueForScopeVariableNamed(context, key.get(), (int)callFrame);
       
   177 }
       
   178 
       
   179 JSValueRef DebuggerDocument::logCallback(JSContextRef context, JSObjectRef /*function*/, JSObjectRef /*thisObject*/, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
       
   180 {
       
   181     if (argumentCount < 1)
       
   182         return JSValueMakeUndefined(context);
       
   183 
       
   184     if (!JSValueIsString(context, arguments[0]))
       
   185         return JSValueMakeUndefined(context);
       
   186 
       
   187     JSRetainPtr<JSStringRef> msg(Adopt, JSValueToStringCopy(context, arguments[0], exception));
       
   188     ASSERT(!*exception);
       
   189 
       
   190     DebuggerDocument::platformLog(msg.get());
       
   191     return JSValueMakeUndefined(context);
       
   192 }
       
   193 
       
   194 //-- These are the calls into the JS. --//    
       
   195 
       
   196 bool DebuggerDocument::isPaused(JSContextRef context) const
       
   197 {
       
   198     JSObjectRef globalObject = JSContextGetGlobalObject(context);
       
   199     JSRetainPtr<JSStringRef> string(Adopt, JSStringCreateWithUTF8CString("isPaused"));
       
   200     JSValueRef objectProperty = JSObjectGetProperty(context, globalObject, string.get(), 0);
       
   201     return JSValueToBoolean(context, objectProperty);
       
   202 }
       
   203 
       
   204 void DebuggerDocument::updateFileSource(JSContextRef context, JSStringRef documentSource, JSStringRef url)
       
   205 {
       
   206     JSValueRef documentSourceValue = JSValueMakeString(context, documentSource);
       
   207     JSValueRef urlValue = JSValueMakeString(context, url);
       
   208     JSValueRef forceValue = JSValueMakeBoolean(context, false);
       
   209 
       
   210     JSValueRef arguments[] = { documentSourceValue, urlValue, forceValue };
       
   211     int argumentsSize = sizeof(arguments)/sizeof(arguments[0]);
       
   212 
       
   213     DebuggerDocument::callGlobalFunction(context, "updateFileSource", argumentsSize, arguments);
       
   214 }
       
   215 
       
   216 void DebuggerDocument::didParseScript(JSContextRef context, JSStringRef source, JSStringRef documentSource, JSStringRef url, JSValueRef sourceId, JSValueRef baseLine)
       
   217 {
       
   218     JSValueRef sourceValue = JSValueMakeString(context, source);
       
   219     JSValueRef documentSourceValue = JSValueMakeString(context, documentSource);
       
   220     JSValueRef urlValue = JSValueMakeString(context, url);
       
   221 
       
   222     JSValueRef arguments[] = { sourceValue, documentSourceValue, urlValue, sourceId, baseLine };
       
   223     int argumentsSize = sizeof(arguments)/sizeof(arguments[0]);
       
   224 
       
   225     DebuggerDocument::callGlobalFunction(context, "didParseScript", argumentsSize, arguments);
       
   226 }
       
   227 
       
   228 void DebuggerDocument::willExecuteStatement(JSContextRef context, JSValueRef sourceId, JSValueRef lineno, JSValueRef* exception)
       
   229 {
       
   230     JSValueRef arguments[] = { sourceId, lineno };
       
   231     int argumentsSize = sizeof(arguments)/sizeof(arguments[0]);
       
   232 
       
   233     DebuggerDocument::callGlobalFunction(context, "willExecuteStatement", argumentsSize, arguments, exception);
       
   234     if (exception)
       
   235         logException(context, *exception);
       
   236 }
       
   237 
       
   238 void DebuggerDocument::didEnterCallFrame(JSContextRef context, JSValueRef sourceId, JSValueRef lineno, JSValueRef* exception)
       
   239 {
       
   240     JSValueRef arguments[] = { sourceId, lineno };
       
   241     int argumentsSize = sizeof(arguments)/sizeof(arguments[0]);
       
   242 
       
   243     DebuggerDocument::callGlobalFunction(context, "didEnterCallFrame", argumentsSize, arguments, exception);
       
   244     if (exception)
       
   245         logException(context, *exception);
       
   246 }
       
   247 
       
   248 void DebuggerDocument::willLeaveCallFrame(JSContextRef context, JSValueRef sourceId, JSValueRef lineno, JSValueRef* exception)
       
   249 {
       
   250     JSValueRef arguments[] = { sourceId, lineno };
       
   251     int argumentsSize = sizeof(arguments)/sizeof(arguments[0]);
       
   252 
       
   253     DebuggerDocument::callGlobalFunction(context, "willLeaveCallFrame", argumentsSize, arguments, exception);
       
   254     if (exception)
       
   255         logException(context, *exception);
       
   256 }
       
   257 
       
   258 void DebuggerDocument::exceptionWasRaised(JSContextRef context, JSValueRef sourceId, JSValueRef lineno, JSValueRef* exception)
       
   259 {
       
   260     JSValueRef arguments[] = { sourceId, lineno };
       
   261     int argumentsSize = sizeof(arguments)/sizeof(arguments[0]);
       
   262 
       
   263     DebuggerDocument::callGlobalFunction(context, "exceptionWasRaised", argumentsSize, arguments, exception);
       
   264 }
       
   265 
       
   266 void DebuggerDocument::windowScriptObjectAvailable(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
       
   267 {
       
   268     JSRetainPtr<JSStringRef> droseraStr(Adopt, JSStringCreateWithUTF8CString("DebuggerDocument"));
       
   269     JSValueRef droseraObject = JSObjectMake(context, getDroseraJSClass(), this);
       
   270 
       
   271     JSObjectSetProperty(context, windowObject, droseraStr.get(), droseraObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
       
   272     if (exception)
       
   273         logException(context, *exception);
       
   274 }
       
   275 
       
   276 JSValueRef DebuggerDocument::toJSArray(JSContextRef context, Vector<JSValueRef>& vectorValues, JSValueRef* exception)
       
   277 {
       
   278     JSObjectRef globalObject = JSContextGetGlobalObject(context);
       
   279     JSRetainPtr<JSStringRef> constructorString(Adopt, JSStringCreateWithUTF8CString("Array"));
       
   280     JSValueRef constructorProperty = JSObjectGetProperty(context, globalObject, constructorString.get(), exception);
       
   281     ASSERT(!*exception);
       
   282 
       
   283     JSObjectRef arrayConstructor = JSValueToObject(context, constructorProperty, exception);
       
   284     ASSERT(!*exception);
       
   285 
       
   286     JSObjectRef array = JSObjectCallAsConstructor(context, arrayConstructor, 0, 0, exception);
       
   287     ASSERT(!*exception);
       
   288 
       
   289     JSRetainPtr<JSStringRef> pushString(Adopt, JSStringCreateWithUTF8CString("push"));
       
   290     JSValueRef pushValue = JSObjectGetProperty(context, array, pushString.get(), exception);
       
   291     ASSERT(!*exception);
       
   292 
       
   293     JSObjectRef push = JSValueToObject(context, pushValue, exception);
       
   294     ASSERT(!*exception);
       
   295 
       
   296     for (Vector<JSValueRef>::iterator it = vectorValues.begin(); it != vectorValues.end(); ++it) {
       
   297         JSObjectCallAsFunction(context, push, array, 1, it, exception);
       
   298         ASSERT(!*exception);
       
   299     }
       
   300     
       
   301     return array;
       
   302 }
       
   303 
       
   304 // Private
       
   305 JSValueRef DebuggerDocument::callGlobalFunction(JSContextRef context, const char* functionName, int argumentCount, JSValueRef arguments[], JSValueRef* exception)
       
   306 {
       
   307     JSObjectRef globalObject = JSContextGetGlobalObject(context);
       
   308     return callFunctionOnObject(context, globalObject, functionName, argumentCount, arguments, exception);
       
   309 }
       
   310 
       
   311 JSValueRef DebuggerDocument::callFunctionOnObject(JSContextRef context, JSObjectRef object, const char* functionName, int argumentCount, JSValueRef arguments[], JSValueRef* exception)
       
   312 {
       
   313     JSRetainPtr<JSStringRef> string(Adopt, JSStringCreateWithUTF8CString(functionName));
       
   314     JSValueRef objectProperty = JSObjectGetProperty(context, object, string.get(), exception);
       
   315 
       
   316     JSObjectRef function = JSValueToObject(context, objectProperty, exception);
       
   317     ASSERT(JSObjectIsFunction(context, function));
       
   318  
       
   319     JSValueRef returnValue = JSObjectCallAsFunction(context, function, 0, argumentCount, arguments, exception);
       
   320     if (exception)
       
   321         logException(context, *exception);
       
   322 
       
   323     return returnValue;
       
   324 }
       
   325 
       
   326 JSClassRef DebuggerDocument::getDroseraJSClass()
       
   327 {
       
   328     static JSClassRef droseraClass = 0;
       
   329 
       
   330     if (!droseraClass) {
       
   331         JSClassDefinition classDefinition = {0};
       
   332         classDefinition.staticFunctions = DebuggerDocument::staticFunctions();
       
   333 
       
   334         droseraClass = JSClassCreate(&classDefinition);
       
   335     }
       
   336 
       
   337     return droseraClass;
       
   338 }
       
   339 
       
   340 JSStaticFunction* DebuggerDocument::staticFunctions()
       
   341 {
       
   342     static JSStaticFunction staticFunctions[] = {
       
   343         { "breakpointEditorHTML", DebuggerDocument::breakpointEditorHTMLCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
       
   344         { "currentFunctionStack", DebuggerDocument::currentFunctionStackCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
       
   345         { "evaluateScript", DebuggerDocument::evaluateScriptCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
       
   346         { "localScopeVariableNamesForCallFrame", DebuggerDocument::localScopeVariableNamesForCallFrameCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
       
   347         { "pause", DebuggerDocument::pauseCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
       
   348         { "resume", DebuggerDocument::resumeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
       
   349         { "stepInto", DebuggerDocument::stepIntoCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
       
   350         { "valueForScopeVariableNamed", DebuggerDocument::valueForScopeVariableNamedCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
       
   351         { "log", DebuggerDocument::logCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
       
   352         { 0, 0, 0 }
       
   353     };
       
   354 
       
   355     return staticFunctions;
       
   356 }
       
   357 
       
   358 void DebuggerDocument::logException(JSContextRef context, JSValueRef exception)
       
   359 {
       
   360     if (!exception)
       
   361         return;
       
   362     
       
   363     JSRetainPtr<JSStringRef> msg(Adopt, JSValueToStringCopy(context, exception, 0));
       
   364     DebuggerDocument::platformLog(msg.get());
       
   365 }
       
   366