[banshee] [JavaScriptCore] Static function support, fixes



commit ef43527f78f6b0675aa42339cc4811d1abb8d646
Author: Aaron Bockover <abockover novell com>
Date:   Wed Nov 24 10:28:24 2010 -0500

    [JavaScriptCore] Static function support, fixes
    
    Static managed functions are now supported on JSClassDefinitions.
    These functions are defined in managed code with a specific signature
    (JSValue:JSObject,JSObject,JSValue[]) and flagged with a
    JSStaticFunction attribute that specifies the JavaScript name of
    the function.
    
    Various bug fixes are made and more code is covered in the tests.
    
    Additionally, the bridge part of the code was stubbed out a bit.

 .../Banshee.WebBrowser/Banshee.WebBrowser.csproj   |   11 ++
 .../JavaScriptCore.Bridge/Runtime.cs               |   78 ++++++++++
 .../JavaScriptCore.Bridge/Tests/RuntimeTests.cs    |   69 +++++++++
 .../JavaScriptCore/JSClassDefinition.cs            |  102 +++++++++++++-
 .../Banshee.WebBrowser/JavaScriptCore/JSContext.cs |    2 +-
 .../Banshee.WebBrowser/JavaScriptCore/JSError.cs   |   53 +++++++
 .../JavaScriptCore/JSErrorException.cs             |   40 +++++
 .../JavaScriptCore/JSException.cs                  |   13 ++-
 .../JavaScriptCore/JSFunction.cs                   |    2 +-
 .../JavaScriptCore/JSStaticFunction.cs             |   39 +++++
 .../JavaScriptCore/JSStaticFunctionAttribute.cs    |   49 ++++++
 .../Banshee.WebBrowser/JavaScriptCore/JSValue.cs   |    2 +-
 .../JavaScriptCore/Tests/JSClassTests.cs           |  156 ++++++++++++++++++++
 .../JavaScriptCore/Tests/JSFunctionTests.cs        |    2 +-
 src/Core/Banshee.WebBrowser/Makefile.am            |    7 +
 15 files changed, 616 insertions(+), 9 deletions(-)
---
diff --git a/src/Core/Banshee.WebBrowser/Banshee.WebBrowser.csproj b/src/Core/Banshee.WebBrowser/Banshee.WebBrowser.csproj
index a37a1ce..33c8bf5 100644
--- a/src/Core/Banshee.WebBrowser/Banshee.WebBrowser.csproj
+++ b/src/Core/Banshee.WebBrowser/Banshee.WebBrowser.csproj
@@ -20,6 +20,7 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <OutputPath>..\..\..\bin</OutputPath>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Windows|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -28,6 +29,7 @@
     <WarningLevel>4</WarningLevel>
     <Optimize>false</Optimize>
     <OutputPath>..\..\..\bin</OutputPath>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="gtk-sharp">
@@ -97,6 +99,8 @@
     <Folder Include="Banshee.WebBrowser\" />
     <Folder Include="JavaScriptCore\" />
     <Folder Include="JavaScriptCore\Tests\" />
+    <Folder Include="JavaScriptCore.Bridge\" />
+    <Folder Include="JavaScriptCore.Bridge\Tests\" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Banshee.WebBrowser\OssiferWebView.cs" />
@@ -127,5 +131,12 @@
     <Compile Include="JavaScriptCore\JSPropertyNameArray.cs" />
     <Compile Include="JavaScriptCore\JSFunction.cs" />
     <Compile Include="JavaScriptCore\Tests\JSFunctionTests.cs" />
+    <Compile Include="JavaScriptCore.Bridge\Runtime.cs" />
+    <Compile Include="JavaScriptCore.Bridge\Tests\RuntimeTests.cs" />
+    <Compile Include="JavaScriptCore\JSError.cs" />
+    <Compile Include="JavaScriptCore\JSErrorException.cs" />
+    <Compile Include="JavaScriptCore\JSStaticFunction.cs" />
+    <Compile Include="JavaScriptCore\JSStaticFunctionAttribute.cs" />
+    <Compile Include="JavaScriptCore\Tests\JSClassTests.cs" />
   </ItemGroup>
 </Project>
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore.Bridge/Runtime.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore.Bridge/Runtime.cs
new file mode 100644
index 0000000..e5fd004
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore.Bridge/Runtime.cs
@@ -0,0 +1,78 @@
+// 
+// Runtime.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+
+using JavaScriptCore;
+
+namespace JavaScriptCore.Bridge
+{
+    public static class Runtime
+    {
+        private class RuntimeClassDefinition : JSClassDefinition
+        {
+            private Dictionary<JSObject, JSValue> import_objects = new Dictionary<JSObject, JSValue> ();
+
+            public override string ClassName {
+                get { return "ManagedJavaScriptCore"; }
+            }
+
+            protected override bool OnJSDeleteProperty (JSObject obj, string propertyName)
+            {
+                throw new JSErrorException (obj.Context, "IllegalOperationError",
+                    "Deleting properties on this object is not allowed");
+            }
+
+            protected override bool OnJSSetProperty (JSObject obj, string propertyName, JSValue value)
+            {
+                throw new JSErrorException (obj.Context, "IllegalOperationError",
+                    "Setting properties on this object is not allowed");
+            }
+        }
+
+        private static RuntimeClassDefinition js_class_definition;
+        private static JSClass js_class;
+
+        static Runtime ()
+        {
+            js_class_definition = new RuntimeClassDefinition ();
+            js_class = js_class_definition.CreateClass ();
+        }
+
+        public static void BindManagedRuntime (this JSContext context)
+        {
+            if (context.GlobalObject.HasProperty ("mjsc")) {
+                throw new ApplicationException ("Cannot bind runtime to JSContext: " +
+                    "mjsc property already exists on context's global object.");
+            }
+
+            context.GlobalObject.SetProperty ("mjsc", new JSObject (context, js_class),
+                JSPropertyAttribute.DontDelete);
+        }
+    }
+}
+
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore.Bridge/Tests/RuntimeTests.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore.Bridge/Tests/RuntimeTests.cs
new file mode 100644
index 0000000..1ac4ca7
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore.Bridge/Tests/RuntimeTests.cs
@@ -0,0 +1,69 @@
+// 
+// RuntimeTests.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#if ENABLE_TESTS
+
+using System;
+using NUnit.Framework;
+
+using JavaScriptCore.Bridge;
+
+namespace JavaScriptCore.Bridge.Tests
+{
+    [TestFixture]
+    public class RuntimeTests
+    {
+        private JSContext context;
+
+        [TestFixtureSetUp]
+        public void Init ()
+        {
+            context = new JSContext ();
+            context.BindManagedRuntime ();
+        }
+
+        [Test]
+        public void TestExceptionBoundaryJsCatch ()
+        {
+            context.EvaluateScript ("try { mjsc.import = 'foo'; } catch (e) { this.p = e.toString (); }");
+            Assert.AreEqual ("IllegalOperationError: Setting properties on this object is not allowed",
+                context.GlobalObject.GetProperty ("p").StringValue);
+        }
+
+        [Test]
+        public void TestExceptionBoundaryRoundTrip ()
+        {
+            try {
+                context.EvaluateScript ("mjsc.import = 'foo'");
+            } catch (JSException e) {
+                Assert.AreEqual ("IllegalOperationError: Setting properties on this object is not allowed",
+                    e.Error.StringValue);
+            }
+        }
+    }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSClassDefinition.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSClassDefinition.cs
index 938679e..a7f48d2 100644
--- a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSClassDefinition.cs
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSClassDefinition.cs
@@ -26,6 +26,7 @@
 
 using System;
 using System.Reflection;
+using System.Collections.Generic;
 using System.Runtime.InteropServices;
 
 namespace JavaScriptCore
@@ -41,7 +42,7 @@ namespace JavaScriptCore
             public IntPtr parent_class;
 
             public IntPtr /* JSStaticValue[] */ static_values;
-            public IntPtr /* JSStaticFunction[] */ static_functions;
+            public IntPtr static_functions;
 
             public JSObject.InitializeCallback initialize;
             public JSObject.FinalizeCallback finalize;
@@ -57,6 +58,7 @@ namespace JavaScriptCore
         }
 
         private JSClassDefinitionNative raw;
+        private Dictionary<string, MethodInfo> static_methods;
 
         public virtual string ClassName {
             get { return GetType ().FullName.Replace (".", "_"); }
@@ -67,6 +69,12 @@ namespace JavaScriptCore
             raw = new JSClassDefinitionNative ();
             raw.class_name = Marshal.StringToHGlobalAnsi (ClassName);
 
+            InstallClassOverrides ();
+            InstallStaticMethods ();
+        }
+
+        private void InstallClassOverrides ()
+        {
             Override ("OnInitialize", () => raw.initialize = new JSObject.InitializeCallback (JSInitialize));
             Override ("OnFinalize", () => raw.finalize = new JSObject.FinalizeCallback (JSFinalize));
             Override ("OnJSHasProperty", () => raw.has_property = new JSObject.HasPropertyCallback (JSHasProperty));
@@ -76,6 +84,68 @@ namespace JavaScriptCore
             Override ("OnJSGetPropertyNames", () => raw.get_property_names = new JSObject.GetPropertyNamesCallback (JSGetPropertyNames));
         }
 
+        private void InstallStaticMethods ()
+        {
+            List<JSStaticFunction> methods = null;
+
+            foreach (var method in GetType ().GetMethods (
+                BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic)) {
+                foreach (var _attr in method.GetCustomAttributes (typeof (JSStaticFunctionAttribute), false)) {
+                    var attr = (JSStaticFunctionAttribute)_attr;
+                    var p = method.GetParameters ();
+
+                    if (method.ReturnType != typeof (JSValue) || p.Length != 3 &&
+                        p[0].ParameterType != typeof (JSObject) ||
+                        p[1].ParameterType != typeof (JSObject) ||
+                        p[2].ParameterType != typeof (JSValue [])) {
+                        throw new Exception (String.Format ("Invalid signature for method annotated " +
+                            "with JSStaticFunctionAttribute: {0}:{1} ('{2}'); signature should be " +
+                            "'JSValue:JSFunction,JSObject,JSValue[]'",
+                                GetType ().FullName, method.Name, attr.Name));
+                    }
+
+                    if (static_methods == null) {
+                        static_methods = new Dictionary<string, MethodInfo> ();
+                    } else if (static_methods.ContainsKey (attr.Name)) {
+                        throw new Exception ("Class already contains static method named '" + attr.Name  + "'");
+                    }
+
+                    static_methods.Add (attr.Name, method);
+
+                    if (methods == null) {
+                        methods = new List<JSStaticFunction> ();
+                    }
+
+                    methods.Add (new JSStaticFunction () {
+                        Name = attr.Name,
+                        Attributes = attr.Attributes,
+                        Callback = OnStaticFunctionCallback
+                    });
+                }
+            }
+
+            if (methods != null && methods.Count > 0) {
+                var size = Marshal.SizeOf (typeof (JSStaticFunction));
+                var ptr = Marshal.AllocHGlobal (size * (methods.Count + 1));
+
+                Console.WriteLine ("ALLOC {0} bytes ({1}b x {2}) @ {3}",
+                    size * (methods.Count + 1), size, methods.Count + 1, ptr);
+
+                for (int i = 0; i < methods.Count; i++) {
+                    Console.WriteLine ("STRUCT [{0}] @ {1}",
+                        methods[i].Name, new IntPtr (ptr.ToInt64 () + size * i));
+                    Marshal.StructureToPtr (methods[i],
+                        new IntPtr (ptr.ToInt64 () + size * i), false);
+                }
+
+                Console.WriteLine ("EMPTY @ {0}", new IntPtr (ptr.ToInt64 () + size * methods.Count));
+                Marshal.StructureToPtr (new JSStaticFunction (),
+                    new IntPtr (ptr.ToInt64 () + size * methods.Count), false);
+
+                raw.static_functions = ptr;
+            }
+        }
+
         private void Override (string methodName, Action handler)
         {
             var method = GetType ().GetMethod (methodName, BindingFlags.Instance | BindingFlags.NonPublic);
@@ -92,6 +162,29 @@ namespace JavaScriptCore
             return new JSClass (JSClassCreate (ref raw));
         }
 
+        private IntPtr OnStaticFunctionCallback (IntPtr ctx, IntPtr function, IntPtr thisObject,
+            IntPtr argumentCount, IntPtr arguments, ref IntPtr exception)
+        {
+            var context = new JSContext (ctx);
+            var fn = new JSObject (ctx, function);
+
+            MethodInfo method = null;
+            if (!static_methods.TryGetValue (fn.GetProperty ("name").StringValue, out method)) {
+                return IntPtr.Zero;
+            }
+
+            var args = new JSValue[argumentCount.ToInt32 ()];
+
+            for (int i = 0; i < args.Length; i++) {
+                args[i] = new JSValue (context, Marshal.ReadIntPtr (arguments, i * IntPtr.Size));
+            }
+
+            var result = method.Invoke (null, new object [] { fn, new JSObject (context, thisObject), args });
+            return result == null
+                ? JSValue.NewUndefined (context).Raw
+                : ((JSValue)result).Raw;
+        }
+
         private void JSInitialize (IntPtr ctx, IntPtr obj)
         {
             OnJSInitialize (new JSObject (ctx, obj));
@@ -136,7 +229,12 @@ namespace JavaScriptCore
             IntPtr value, ref IntPtr exception)
         {
             var context = new JSContext (ctx);
-            return OnJSSetProperty (new JSObject (context, obj), propertyName.Value, new JSValue (context, value));
+            try {
+                return OnJSSetProperty (new JSObject (context, obj), propertyName.Value, new JSValue (context, value));
+            } catch (JSErrorException e) {
+                exception = e.Error.Raw;
+                return false;
+            }
         }
 
         protected virtual bool OnJSSetProperty (JSObject obj, string propertyName, JSValue value)
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSContext.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSContext.cs
index c2484a8..89a2157 100644
--- a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSContext.cs
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSContext.cs
@@ -65,7 +65,7 @@ namespace JavaScriptCore
                 thisObject == null ? IntPtr.Zero : thisObject.Raw,
                 sourceUrl, startingLineNumber, ref exception);
             JSException.Proxy (this, exception);
-            return new JSValue (result);
+            return new JSValue (this, result);
         }
 
         public JSValue EvaluateScript (string script, JSObject thisObject, string sourceUrl, int startingLineNumber)
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSError.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSError.cs
new file mode 100644
index 0000000..1a8d6c4
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSError.cs
@@ -0,0 +1,53 @@
+// 
+// JSError.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace JavaScriptCore
+{
+    public class JSError : JSObject
+    {
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSObjectMakeError (IntPtr ctx,
+            IntPtr argumentCount, IntPtr args, ref IntPtr exception);
+
+        public JSError (JSContext context, string name, string message) : base (context, IntPtr.Zero)
+        {
+            var exception = IntPtr.Zero;
+            Raw = JSObjectMakeError (context.Raw, IntPtr.Zero, IntPtr.Zero, ref exception);
+            JSException.Proxy (context, exception);
+
+            if (name != null) {
+                SetProperty ("name", new JSValue (context, name));
+            }
+
+            if (message != null) {
+                SetProperty ("message", new JSValue (context, message));
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSErrorException.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSErrorException.cs
new file mode 100644
index 0000000..618b0b9
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSErrorException.cs
@@ -0,0 +1,40 @@
+// 
+// JSErrorException.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+
+namespace JavaScriptCore
+{
+    public class JSErrorException : Exception
+    {
+        public JSError Error { get; set; }
+
+        public JSErrorException (JSContext context, string name, string message)
+        {
+            Error = new JSError (context, name, message);
+        }
+    }
+}
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSException.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSException.cs
index fb2a970..01678db 100644
--- a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSException.cs
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSException.cs
@@ -31,15 +31,22 @@ namespace JavaScriptCore
     public class JSException : Exception
     {
         public JSContext Context { get; private set; }
+        public JSValue Error { get; private set; }
 
-        internal JSException (JSContext context, string message)
-            : base (message)
+        internal JSException (JSContext context, JSValue error)
+            : base ("JSON: " + error.ToString ())
+        {
+            Error = error;
+            Context = context;
+        }
+
+        internal JSException (JSContext context, string message) : base (message)
         {
             Context = context;
         }
 
         internal JSException (JSContext context, IntPtr exception)
-            : this (context, "JSON: " + new JSValue (context, exception).ToJsonString ())
+            : this (context, new JSValue (context, exception))
         {
         }
 
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSFunction.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSFunction.cs
index b26023a..767de00 100644
--- a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSFunction.cs
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSFunction.cs
@@ -29,7 +29,7 @@ using System.Runtime.InteropServices;
 
 namespace JavaScriptCore
 {
-    public delegate JSValue JSFunctionHandler (JSFunction function, JSObject thisObject, JSValue [] args);
+    public delegate JSValue JSFunctionHandler (JSObject function, JSObject thisObject, JSValue [] args);
 
     public class JSFunction : JSObject
     {
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSStaticFunction.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSStaticFunction.cs
new file mode 100644
index 0000000..a099423
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSStaticFunction.cs
@@ -0,0 +1,39 @@
+// 
+// JSStaticFunction.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace JavaScriptCore
+{
+    [StructLayout (LayoutKind.Sequential)]
+    public struct JSStaticFunction
+    {
+        public string Name;
+        public JSObject.CallAsFunctionCallback Callback;
+        public JSPropertyAttribute Attributes;
+    }
+}
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSStaticFunctionAttribute.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSStaticFunctionAttribute.cs
new file mode 100644
index 0000000..5c1c769
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSStaticFunctionAttribute.cs
@@ -0,0 +1,49 @@
+// 
+// JSStaticFunctionAttribute.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+
+namespace JavaScriptCore
+{
+    public class JSStaticFunctionAttribute : Attribute
+    {
+        public string Name { get; set; }
+        public JSPropertyAttribute Attributes { get; set; }
+        
+        public JSStaticFunctionAttribute () : this (null, JSPropertyAttribute.None)
+        {
+        }
+
+        public JSStaticFunctionAttribute (string name) : this (name, JSPropertyAttribute.None)
+        {
+        }
+
+        public JSStaticFunctionAttribute (string name, JSPropertyAttribute attributes)
+        {
+            Name = name;
+            Attributes = attributes;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSValue.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSValue.cs
index d6246d3..ae14e57 100644
--- a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSValue.cs
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSValue.cs
@@ -236,7 +236,7 @@ namespace JavaScriptCore
                 var exception = IntPtr.Zero;
                 var result = JSValueToObject (Context.Raw, Raw, ref exception);
                 JSException.Proxy (Context, exception);
-                return new JSObject (result);
+                return new JSObject (Context, result);
             }
         }
 
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore/Tests/JSClassTests.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore/Tests/JSClassTests.cs
new file mode 100644
index 0000000..f460e53
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore/Tests/JSClassTests.cs
@@ -0,0 +1,156 @@
+//
+// JSClassTests.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#if ENABLE_TESTS
+
+using System;
+using NUnit.Framework;
+
+namespace JavaScriptCore.Tests
+{
+    [TestFixture]
+    public class JSClassTests
+    {
+        private JSContext context;
+
+        private class JSClassTest : JSClassDefinition
+        {
+            [JSStaticFunction ("return_managed_null")]
+            private static JSValue ReturnManagedNull (JSObject function, JSObject thisObject, JSValue [] args)
+            {
+                return null;
+            }
+
+            [JSStaticFunction ("return_js_undefined")]
+            private static JSValue ReturnJSUndefined (JSObject function, JSObject thisObject, JSValue [] args)
+            {
+                return JSValue.NewUndefined (function.Context);
+            }
+
+            [JSStaticFunction ("return_js_null")]
+            private static JSValue ReturnJSNull (JSObject function, JSObject thisObject, JSValue [] args)
+            {
+                return JSValue.NewNull (function.Context);
+            }
+
+            [JSStaticFunction ("return_js_number")]
+            private static JSValue ReturnJSNumber (JSObject function, JSObject thisObject, JSValue [] args)
+            {
+                return new JSValue (function.Context, 3920.6);
+            }
+
+            [JSStaticFunction ("return_js_string")]
+            private static JSValue ReturnJSString (JSObject function, JSObject thisObject, JSValue [] args)
+            {
+                return new JSValue (function.Context, "hello world");
+            }
+
+            [JSStaticFunction ("this_object")]
+            private static JSValue ThisObject (JSObject function, JSObject thisObject, JSValue [] args)
+            {
+                return thisObject.GetProperty ("name");
+            }
+
+            [JSStaticFunction ("args")]
+            private static JSValue TestArgs (JSObject function, JSObject thisObject, JSValue [] args)
+            {
+                Assert.AreEqual (6, args.Length);
+
+                Assert.AreEqual (JSType.Boolean, args[0].JSType);
+                Assert.AreEqual (JSType.Number, args[1].JSType);
+                Assert.AreEqual (JSType.String, args[2].JSType);
+                Assert.AreEqual (JSType.Object, args[3].JSType);
+                Assert.AreEqual (JSType.Null, args[4].JSType);
+                Assert.AreEqual (JSType.Undefined, args[5].JSType);
+
+                Assert.AreEqual (true, args[0].BooleanValue);
+                Assert.AreEqual (42, args[1].NumberValue);
+                Assert.AreEqual ("banshee", args[2].StringValue);
+                Assert.IsTrue (args[3].ObjectValue.IsFunction);
+                Assert.AreEqual ("args", args[3].ObjectValue.GetProperty ("name").StringValue);
+
+                return null;
+            }
+        }
+
+        [TestFixtureSetUp]
+        public void Init ()
+        {
+            context = new JSContext ();
+            context.GlobalObject.SetProperty ("x", new JSObject (context, new JSClassTest ().CreateClass ()));
+        }
+
+        [Test]
+        public void TestEnsureJavaScriptCoreVoidReturnIsUndefined ()
+        {
+            Assert.AreEqual (JSType.Undefined, context.EvaluateScript ("(function f () { })()").JSType);
+        }
+
+        [Test]
+        public void TestStaticReturnManagedNull ()
+        {
+            Assert.AreEqual (JSType.Undefined, context.EvaluateScript ("x.return_managed_null ()").JSType);
+        }
+
+        [Test]
+        public void TestStaticReturnJSUndefined ()
+        {
+            Assert.AreEqual (JSType.Undefined, context.EvaluateScript ("x.return_js_undefined ()").JSType);
+        }
+
+        [Test]
+        public void TestStaticReturnJSNull ()
+        {
+            Assert.AreEqual (JSType.Null, context.EvaluateScript ("x.return_js_null ()").JSType);
+        }
+
+        [Test]
+        public void TestStaticReturnJSNumber ()
+        {
+            Assert.AreEqual (3920.6, context.EvaluateScript ("x.return_js_number ()").NumberValue);
+        }
+
+        [Test]
+        public void TestStaticReturnJSString ()
+        {
+            Assert.AreEqual ("hello world", context.EvaluateScript ("x.return_js_string ()").StringValue);
+        }
+
+        [Test]
+        public void TestStaticThisObject ()
+        {
+            Assert.AreEqual ("flipper", context.EvaluateScript ("x.this_object.call ({name:'flipper'})").StringValue);
+        }
+
+        [Test]
+        public void TestStaticArgs ()
+        {
+            context.EvaluateScript ("x.args (true, 42, 'banshee', x.args, null, undefined)");
+        }
+    }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore/Tests/JSFunctionTests.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore/Tests/JSFunctionTests.cs
index af0e1f2..9463887 100644
--- a/src/Core/Banshee.WebBrowser/JavaScriptCore/Tests/JSFunctionTests.cs
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore/Tests/JSFunctionTests.cs
@@ -83,7 +83,7 @@ namespace JavaScriptCore.Tests
             Assert.AreEqual (42, go.NumberValue);
         }
 
-        private JSValue Fib_1 (JSFunction function, JSObject @this, JSValue [] args)
+        private JSValue Fib_1 (JSObject function, JSObject @this, JSValue [] args)
         {
             return args[0].NumberValue <= 1 ? new JSValue (@this.Context, 1) : new JSValue (@this.Context,
                 Fib_1 (function, @this, new [] { new JSValue (@this.Context, args[0].NumberValue - 1) }).NumberValue +
diff --git a/src/Core/Banshee.WebBrowser/Makefile.am b/src/Core/Banshee.WebBrowser/Makefile.am
index 24857e1..b1c0006 100644
--- a/src/Core/Banshee.WebBrowser/Makefile.am
+++ b/src/Core/Banshee.WebBrowser/Makefile.am
@@ -16,20 +16,27 @@ SOURCES =  \
 	Banshee.WebSource/WebBrowserShell.cs \
 	Banshee.WebSource/WebSource.cs \
 	Banshee.WebSource/WebView.cs \
+	JavaScriptCore.Bridge/Runtime.cs \
+	JavaScriptCore.Bridge/Tests/RuntimeTests.cs \
 	JavaScriptCore/JSClass.cs \
 	JavaScriptCore/JSClassAttribute.cs \
 	JavaScriptCore/JSClassDefinition.cs \
 	JavaScriptCore/JSContext.cs \
+	JavaScriptCore/JSError.cs \
+	JavaScriptCore/JSErrorException.cs \
 	JavaScriptCore/JSException.cs \
 	JavaScriptCore/JSFunction.cs \
 	JavaScriptCore/JSObject.cs \
 	JavaScriptCore/JSPropertyAttribute.cs \
 	JavaScriptCore/JSPropertyNameAccumulator.cs \
 	JavaScriptCore/JSPropertyNameArray.cs \
+	JavaScriptCore/JSStaticFunction.cs \
+	JavaScriptCore/JSStaticFunctionAttribute.cs \
 	JavaScriptCore/JSString.cs \
 	JavaScriptCore/JSType.cs \
 	JavaScriptCore/JSValue.cs \
 	JavaScriptCore/ManagedPropertyBagClass.cs \
+	JavaScriptCore/Tests/JSClassTests.cs \
 	JavaScriptCore/Tests/JSFunctionTests.cs \
 	JavaScriptCore/Tests/JSObjectTests.cs \
 	JavaScriptCore/Tests/JSStringTests.cs \



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]