]> spindle.queued.net Git - midori/commitdiff
Introduce GjsValue API
authorChristian Dywan <christian@twotoasts.de>
Mon, 21 Jul 2008 13:46:35 +0000 (15:46 +0200)
committerChristian Dywan <christian@twotoasts.de>
Mon, 21 Jul 2008 13:46:35 +0000 (15:46 +0200)
midori/gjs.c
midori/gjs.h

index b30a006b67c89490ff37af38b1be33a682277941..0d432f3974fbab481278590e07a7a1a6f06aad43 100644 (file)
 #include <gmodule.h>
 #include <glib/gi18n.h>
 
-#define G_OBJECT_NAME(object) G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object))
+struct _GjsValue
+{
+    GObject parent_instance;
+
+    JSContextRef js_context;
+    JSValueRef js_value;
+    gchar* string;
+};
+
+G_DEFINE_TYPE (GjsValue, gjs_value, G_TYPE_OBJECT)
+
+static void
+gjs_value_finalize (GObject* object)
+{
+    GjsValue* value = GJS_VALUE (object);
+
+    g_free (value->string);
+
+    G_OBJECT_CLASS (gjs_value_parent_class)->finalize (object);
+}
+
+static void
+gjs_value_class_init (GjsValueClass* class)
+{
+    GObjectClass* gobject_class = G_OBJECT_CLASS (class);
+    gobject_class->finalize = gjs_value_finalize;
+}
+
+static void
+gjs_value_init (GjsValue* value)
+{
+    value->js_context = NULL;
+    value->js_value = NULL;
+    value->string = NULL;
+}
+
+/**
+ * gjs_value_new:
+ * @js_context: a #JSContextRef
+ * @js_value: a #JSValueRef or %NULL
+ *
+ * Creates a new #GjsValue for a #JsValueRef. If @js_value
+ * is %NULL, the new value represents the global object.
+ *
+ * Return value: a new #GjsValue
+ **/
+GjsValue*
+gjs_value_new (JSContextRef js_context,
+               JSValueRef   js_value)
+{
+    GjsValue* value;
+
+    g_return_val_if_fail (js_context, NULL);
+
+    value = g_object_new (GJS_TYPE_VALUE, NULL);
+    value->js_context = js_context;
+    value->js_value = js_value ? js_value : JSContextGetGlobalObject (js_context);
+    return value;
+}
+
+/**
+ * gjs_value_is_valid:
+ * @value: a #GjsValue
+ *
+ * Determines whether the value is valid, with regard to
+ * its internal state. This is primarily useful for API
+ * to ensure that the value is in a defined condition.
+ *
+ * Return value: %TRUE if value is valid
+ **/
+gboolean
+gjs_value_is_valid (GjsValue* value)
+{
+    g_return_val_if_fail (GJS_IS_VALUE (value), FALSE);
+    g_return_val_if_fail (value->js_context, FALSE);
+    g_return_val_if_fail (value->js_value, FALSE);
+
+    return TRUE;
+}
+
+/**
+ * gjs_value_is_object:
+ * @value: a #GjsValue
+ *
+ * Determines whether the value is an object.
+ *
+ * Return value: %TRUE if value is an object
+ **/
+gboolean
+gjs_value_is_object (GjsValue* value)
+{
+    g_return_val_if_fail (gjs_value_is_valid (value), FALSE);
+
+    return JSValueIsObject (value->js_context, value->js_value) == true;
+}
+
+/**
+ * gjs_value_has_attribute:
+ * @value: a #GjsValue
+ * @name: the name of a attribute
+ *
+ * Determines whether the value has the specified attribute.
+ *
+ * This can only be used on object values.
+ *
+ * Return value: %TRUE if the specified attribute exists
+ **/
+gboolean
+gjs_value_has_attribute (GjsValue*    value,
+                         const gchar* name)
+{
+    JSObjectRef js_object;
+    JSStringRef js_name;
+    gboolean result;
+
+    g_return_val_if_fail (gjs_value_is_object (value), FALSE);
+    g_return_val_if_fail (name, FALSE);
+
+    js_object = JSValueToObject (value->js_context, value->js_value, NULL);
+    js_name = JSStringCreateWithUTF8CString (name);
+    result = JSObjectHasProperty (value->js_context, js_object, js_name) == true;
+    JSStringRelease (js_name);
+    return result;
+}
+
+/**
+ * gjs_value_get_attribute:
+ * @value: a #GjsValue
+ * @name: the name of a attribute
+ *
+ * Retrieves the specified attribute.
+ *
+ * This can only be used on object values.
+ *
+ * Return value: a new #GjsValue
+ **/
+GjsValue*
+gjs_value_get_attribute (GjsValue*    value,
+                         const gchar* name)
+{
+    JSObjectRef js_object;
+    JSStringRef js_name;
+    JSValueRef js_value;
+
+    g_return_val_if_fail (gjs_value_has_attribute (value, name), NULL);
+
+    js_object = JSValueToObject (value->js_context, value->js_value, NULL);
+    js_name = JSStringCreateWithUTF8CString (name);
+    js_value = JSObjectGetProperty (value->js_context, js_object, js_name, NULL);
+    JSStringRelease (js_name);
+
+    return gjs_value_new (value->js_context, js_value);
+}
+
+/**
+ * gjs_value_get_string:
+ * @value: a #GjsValue
+ *
+ * Retrieves the value in the form of a string.
+ *
+ * This can only be used on object values.
+ *
+ * Note: The string won't reflect changes to the value.
+ *
+ * Return value: the value as a string
+ **/
+const gchar*
+gjs_value_get_string (GjsValue* value)
+{
+    JSStringRef js_string;
+
+    g_return_val_if_fail (gjs_value_is_valid (value), NULL);
+
+    if (value->string)
+        return value->string;
+
+    js_string = JSValueToStringCopy (value->js_context, value->js_value, NULL);
+    value->string = gjs_string_utf8 (js_string);
+    JSStringRelease (js_string);
+    return value->string;
+}
+
+void
+gjs_value_weak_notify_cb (GjsValue* attribute,
+                          GjsValue* value)
+{
+    g_object_unref (attribute);
+}
+
+/**
+ * gjs_value_get_attribute_string:
+ * @value: a #GjsValue
+ * @name: the name of a attribute
+ *
+ * Retrieves the attribute of the value in the form of a string.
+ *
+ * This can only be used on object values.
+ *
+ * Note: The string won't reflect changes to the value.
+ *
+ * Return value: the value as a string
+ **/
+const gchar*
+gjs_value_get_attribute_string (GjsValue*    value,
+                                const gchar* name)
+{
+    GjsValue* attribute;
+
+    g_return_val_if_fail (gjs_value_has_attribute (value, name), NULL);
+
+    attribute = gjs_value_get_attribute (value, name);
+    g_object_weak_ref (G_OBJECT (value),
+        (GWeakNotify)gjs_value_weak_notify_cb, attribute);
+    return gjs_value_get_string (attribute);
+}
+
+/**
+ * gjs_value_foreach:
+ * @value: a #GjsValue
+ * @callback: a callback
+ * @user_data: user data
+ *
+ * Runs the specified callback for each attribute of the value.
+ *
+ * This can only be used on object values.
+ **/
+void
+gjs_value_foreach (GjsValue*   value,
+                   GjsCallback callback,
+                   gpointer    user_data)
+{
+    JSObjectRef js_object;
+    JSPropertyNameArrayRef js_properties;
+    size_t n_properties;
+    guint i;
+    JSStringRef js_property;
+    gchar* property;
+    GjsValue* attribute;
+
+    g_return_if_fail (gjs_value_is_object (value));
+
+    js_object = JSValueToObject (value->js_context, value->js_value, NULL);
+    js_properties = JSObjectCopyPropertyNames (value->js_context, js_object);
+    n_properties = JSPropertyNameArrayGetCount (js_properties);
+    for (i = 0; i < n_properties; i++)
+    {
+        js_property = JSPropertyNameArrayGetNameAtIndex (js_properties, i);
+        property = gjs_string_utf8 (js_property);
+        if (gjs_value_has_attribute (value, property))
+        {
+            attribute = gjs_value_get_attribute (value, property);
+            callback (attribute, user_data);
+            g_object_unref (attribute);
+        }
+        g_free (property);
+        JSStringRelease (js_property);
+    }
+    JSPropertyNameArrayRelease (js_properties);
+}
+
+/**
+ * gjs_value_get_by_name:
+ * @value: a #GjsValue
+ * @name: the name of an object
+ *
+ * Retrieves a value for the specified name,
+ * for example "document" or "document.body".
+ *
+ * Return value: the value, or %NULL
+ **/
+GjsValue*
+gjs_value_get_by_name (GjsValue*    value,
+                       const gchar* name)
+{
+    gchar* script;
+    GjsValue* elements;
+
+    g_return_val_if_fail (gjs_value_is_valid (value), NULL);
+    g_return_val_if_fail (name, NULL);
+
+    script = g_strdup_printf ("return %s;", name);
+    elements = gjs_value_execute (value, script, NULL);
+    g_free (script);
+    return elements;
+}
+
+/**
+ * gjs_value_get_elements_by_tag_name:
+ * @value: a #GjsValue
+ * @name: the tag name
+ *
+ * Retrieves all children with the specified tag name.
+ *
+ * This can only be used on object values.
+ *
+ * Return value: all matching elements
+ **/
+GjsValue*
+gjs_value_get_elements_by_tag_name (GjsValue*    value,
+                                    const gchar* name)
+{
+    gchar* script;
+    GjsValue* elements;
+
+    g_return_val_if_fail (gjs_value_is_valid (value), NULL);
+    g_return_val_if_fail (name, NULL);
+
+    script = g_strdup_printf ("return this.getElementsByTagName ('%s');", name);
+    elements = gjs_value_execute (value, script, NULL);
+    g_free (script);
+    return elements;
+}
+
+/**
+ * gjs_value_execute:
+ * @value: a #GjsValue
+ * @script: javascript code
+ *
+ * Executes a piece of javascript code. If @value is an object
+ * it can be referred to as 'this' in the code.
+ *
+ * A 'return' statement in the code will yield the result to
+ * the return value of this function.
+ *
+ * Return value: the return value, or %NULL
+ **/
+GjsValue*
+gjs_value_execute (GjsValue*    value,
+                   const gchar* script,
+                   gchar**      exception)
+{
+    JSStringRef js_script;
+    JSObjectRef js_function;
+    JSObjectRef js_object;
+    JSValueRef js_exception;
+    JSValueRef js_value;
+    JSStringRef js_message;
+
+    g_return_val_if_fail (gjs_value_is_valid (value), FALSE);
+    g_return_val_if_fail (script, FALSE);
+
+    js_script = JSStringCreateWithUTF8CString (script);
+    js_function = JSObjectMakeFunction (value->js_context, NULL, 0, NULL,
+                                        js_script, NULL, 1, NULL);
+    JSStringRelease (js_script);
+    js_object = JSValueToObject (value->js_context, value->js_value, NULL);
+    js_exception = NULL;
+    js_value = JSObjectCallAsFunction (value->js_context, js_function,
+                                       js_object, 0, NULL, &js_exception);
+    if (!js_value && exception)
+    {
+        js_message = JSValueToStringCopy (value->js_context, js_exception, NULL);
+        *exception = gjs_string_utf8 (js_message);
+        JSStringRelease (js_message);
+        return NULL;
+    }
+    return gjs_value_new (value->js_context, js_value);
+}
 
 JSValueRef
 gjs_script_eval (JSContextRef js_context,
@@ -93,12 +450,19 @@ gjs_script_from_file (JSContextRef js_context,
 gchar*
 gjs_string_utf8 (JSStringRef js_string)
 {
-    size_t size_utf8 = JSStringGetMaximumUTF8CStringSize (js_string);
-    gchar* string_utf8 = g_new (gchar, size_utf8);
+    size_t size_utf8;
+    gchar* string_utf8;
+
+    g_return_val_if_fail (js_string, NULL);
+
+    size_utf8 = JSStringGetMaximumUTF8CStringSize (js_string);
+    string_utf8 = g_new (gchar, size_utf8);
     JSStringGetUTF8CString (js_string, string_utf8, size_utf8);
     return string_utf8;
 }
 
+#define G_OBJECT_NAME(object) G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object))
+
 static void
 _js_class_get_property_names_cb (JSContextRef                 js_context,
                                  JSObjectRef                  js_object,
index 47e9fced2c05950048594f1a3b37ec4e0c7db206..47e2b0a30ef4ad93435a1b3107d6fad26a203a74 100644 (file)
 
 G_BEGIN_DECLS
 
+#define GJS_TYPE_VALUE \
+    (gjs_value_get_type ())
+#define GJS_VALUE(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GJS_TYPE_VALUE, GjsValue))
+#define GJS_VALUE_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), GJS_TYPE_VALUE, GjsValueClass))
+#define GJS_IS_VALUE(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GJS_TYPE_VALUE))
+#define GJS_IS_VALUE_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), GJS_TYPE_VALUE))
+#define GJS_VALUE_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), GJS_TYPE_VALUE, GjsValueClass))
+
+typedef struct _GjsValue GjsValue;
+typedef struct _GjsValueClass GjsValueClass;
+
+struct _GjsValueClass
+{
+    GObjectClass parent_class;
+};
+
+GType
+gjs_value_get_type (void);
+
+GjsValue*
+gjs_value_new (JSContextRef js_context,
+               JSValueRef   js_value);
+
+gboolean
+gjs_value_is_valid (GjsValue* value);
+
+gboolean
+gjs_value_is_object (GjsValue* value);
+
+gboolean
+gjs_value_has_attribute (GjsValue*    value,
+                         const gchar* name);
+
+GjsValue*
+gjs_value_get_attribute (GjsValue*    value,
+                         const gchar* name);
+
+const gchar*
+gjs_value_get_string (GjsValue* value);
+
+const gchar*
+gjs_value_get_attribute_string (GjsValue*    value,
+                                const gchar* name);
+
+typedef void
+(*GjsCallback) (GjsValue* value,
+                gpointer  user_data);
+
+void
+gjs_value_foreach (GjsValue*   value,
+                   GjsCallback callback,
+                   gpointer    user_data);
+
+GjsValue*
+gjs_value_get_by_name (GjsValue*    value,
+                       const gchar* name);
+
+GjsValue*
+gjs_value_get_elements_by_tag_name (GjsValue*    value,
+                                    const gchar* name);
+
+GjsValue*
+gjs_value_execute (GjsValue*    value,
+                   const gchar* script,
+                   gchar**      exception);
+
 JSValueRef
 gjs_script_eval (JSContextRef js_context,
                  const gchar* script,