[gtk+/wip/otte/shader: 147/269] gsksl: Add support for structs



commit da1a881dc52041a1b9f7e149c9c479441fe1438c
Author: Benjamin Otte <otte redhat com>
Date:   Thu Sep 28 02:45:43 2017 +0200

    gsksl: Add support for structs

 gsk/gskslexpression.c   |    7 +-
 gsk/gskslnode.c         |    4 +-
 gsk/gskslprogram.c      |    2 +-
 gsk/gskslscope.c        |   34 ++++
 gsk/gskslscopeprivate.h |    5 +
 gsk/gsksltype.c         |  409 ++++++++++++++++++++++++++++++++++++++++++++++-
 gsk/gsksltypeprivate.h  |   14 ++-
 7 files changed, 467 insertions(+), 8 deletions(-)
---
diff --git a/gsk/gskslexpression.c b/gsk/gskslexpression.c
index d647a20..b8f23f0 100644
--- a/gsk/gskslexpression.c
+++ b/gsk/gskslexpression.c
@@ -1116,6 +1116,9 @@ gsk_sl_expression_parse_primary (GskSlScope        *scope,
         GskSlVariable *variable;
         char *name;
         
+        if (gsk_sl_scope_lookup_type (scope, token->str))
+          goto its_a_type;
+
         name = g_strdup (token->str);
         gsk_sl_preprocessor_consume (stream, NULL);
 
@@ -1235,12 +1238,14 @@ gsk_sl_expression_parse_primary (GskSlScope        *scope,
     case GSK_SL_TOKEN_DMAT4X2:
     case GSK_SL_TOKEN_DMAT4X3:
     case GSK_SL_TOKEN_DMAT4X4:
+    case GSK_SL_TOKEN_STRUCT:
       {
         GskSlFunction *constructor;
         GskSlExpression *expression;
         GskSlType *type;
 
-        type = gsk_sl_type_new_parse (stream);
+its_a_type:
+        type = gsk_sl_type_new_parse (scope, stream);
         constructor = gsk_sl_function_new_constructor (type);
         expression = gsk_sl_expression_parse_function_call (scope, stream, constructor);
         gsk_sl_function_unref (constructor);
diff --git a/gsk/gskslnode.c b/gsk/gskslnode.c
index 662c044..8f50830 100644
--- a/gsk/gskslnode.c
+++ b/gsk/gskslnode.c
@@ -381,6 +381,8 @@ gsk_sl_node_parse_statement (GskSlScope        *scope,
     case GSK_SL_TOKEN_DMAT4X2:
     case GSK_SL_TOKEN_DMAT4X3:
     case GSK_SL_TOKEN_DMAT4X4:
+    case GSK_SL_TOKEN_STRUCT:
+    case GSK_SL_TOKEN_IDENTIFIER:
       {
         GskSlType *type;
         GskSlDecorations decoration;
@@ -389,7 +391,7 @@ gsk_sl_node_parse_statement (GskSlScope        *scope,
                                       preproc,
                                       &decoration);
 
-        type = gsk_sl_type_new_parse (preproc);
+        type = gsk_sl_type_new_parse (scope, preproc);
 
         token = gsk_sl_preprocessor_get (preproc);
 
diff --git a/gsk/gskslprogram.c b/gsk/gskslprogram.c
index 9220034..47b68be 100644
--- a/gsk/gskslprogram.c
+++ b/gsk/gskslprogram.c
@@ -145,7 +145,7 @@ gsk_sl_program_parse_declaration (GskSlProgram      *program,
                                 preproc,
                                 &decoration);
 
-  type = gsk_sl_type_new_parse (preproc);
+  type = gsk_sl_type_new_parse (scope, preproc);
 
   token = gsk_sl_preprocessor_get (preproc);
   if (gsk_sl_token_is (token, GSK_SL_TOKEN_SEMICOLON))
diff --git a/gsk/gskslscope.c b/gsk/gskslscope.c
index e75b444..03fc9a4 100644
--- a/gsk/gskslscope.c
+++ b/gsk/gskslscope.c
@@ -36,6 +36,7 @@ struct _GskSlScope
   
   GHashTable *variables;
   GHashTable *functions;
+  GHashTable *types;
 };
 
 GskSlScope *
@@ -56,6 +57,7 @@ gsk_sl_scope_new (GskSlScope *parent,
     scope->return_type = gsk_sl_type_ref (return_type);
   scope->variables = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) 
gsk_sl_variable_unref);
   scope->functions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) 
gsk_sl_function_unref);
+  scope->types = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) gsk_sl_type_unref);
 
   return scope;
 }
@@ -84,6 +86,7 @@ gsk_sl_scope_unref (GskSlScope *scope)
 
   g_hash_table_unref (scope->variables);
   g_hash_table_unref (scope->functions);
+  g_hash_table_unref (scope->types);
 
   if (scope->parent)
     scope->parent->children = g_slist_remove (scope->parent->children, scope);
@@ -102,6 +105,12 @@ gsk_sl_scope_get_return_type (const GskSlScope *scope)
   return scope->return_type;
 }
 
+gboolean
+gsk_sl_scope_is_global (const GskSlScope *scope)
+{
+  return scope->parent == NULL;
+}
+
 void
 gsk_sl_scope_add_variable (GskSlScope    *scope,
                            GskSlVariable *variable)
@@ -151,3 +160,28 @@ gsk_sl_scope_lookup_function (GskSlScope *scope,
 
   return NULL;
 }
+
+void
+gsk_sl_scope_add_type (GskSlScope *scope,
+                       GskSlType  *type)
+{
+  g_hash_table_replace (scope->types, (gpointer) gsk_sl_type_get_name (type), gsk_sl_type_ref (type));
+}
+
+GskSlType *
+gsk_sl_scope_lookup_type (GskSlScope *scope,
+                          const char *name)
+{
+  GskSlType *result;
+
+  for (;
+       scope != NULL;
+       scope = scope->parent)
+    {
+      result = g_hash_table_lookup (scope->types, name);
+      if (result)
+        return result;
+    }
+
+  return NULL;
+}
diff --git a/gsk/gskslscopeprivate.h b/gsk/gskslscopeprivate.h
index 869c94d..50e6120 100644
--- a/gsk/gskslscopeprivate.h
+++ b/gsk/gskslscopeprivate.h
@@ -32,6 +32,7 @@ GskSlScope *            gsk_sl_scope_ref                        (GskSlScope
 void                    gsk_sl_scope_unref                      (GskSlScope           *scope);
 
 GskSlType *             gsk_sl_scope_get_return_type            (const GskSlScope     *scope);
+gboolean                gsk_sl_scope_is_global                  (const GskSlScope     *scope);
 
 void                    gsk_sl_scope_add_variable               (GskSlScope           *scope,
                                                                  GskSlVariable        *variable);
@@ -41,6 +42,10 @@ void                    gsk_sl_scope_add_function               (GskSlScope
                                                                  GskSlFunction        *function);
 GskSlFunction *         gsk_sl_scope_lookup_function            (GskSlScope           *scope,
                                                                  const char           *name);
+void                    gsk_sl_scope_add_type                   (GskSlScope           *scope,
+                                                                 GskSlType            *type);
+GskSlType *             gsk_sl_scope_lookup_type                (GskSlScope           *scope,
+                                                                 const char           *name);
 
 G_END_DECLS
 
diff --git a/gsk/gsksltype.c b/gsk/gsksltype.c
index f458a09..94dfdf5 100644
--- a/gsk/gsksltype.c
+++ b/gsk/gsksltype.c
@@ -22,6 +22,8 @@
 
 #include "gsksltokenizerprivate.h"
 #include "gskslpreprocessorprivate.h"
+#include "gskslpreprocessorprivate.h"
+#include "gskslscopeprivate.h"
 #include "gskslvalueprivate.h"
 #include "gskspvwriterprivate.h"
 
@@ -312,6 +314,21 @@ struct {
 #undef SIMPLE_CONVERSION
 #undef CONVERSIONS
 
+static GskSlType *
+gsk_sl_type_alloc (const GskSlTypeClass *klass,
+                   gsize                 size)
+{
+  GskSlType *type;
+
+  type = g_slice_alloc0 (size);
+
+  type->class = klass;
+  type->ref_count = 1;
+
+  return type;
+}
+#define gsk_sl_type_new(_name, _klass) ((_name *) gsk_sl_type_alloc ((_klass), sizeof (_name)))
+
 /* SCALAR */
 
 typedef struct _GskSlTypeScalar GskSlTypeScalar;
@@ -836,13 +853,291 @@ static const GskSlTypeClass GSK_SL_TYPE_MATRIX = {
   gsk_sl_type_matrix_write_value_spv
 };
 
+/* STRUCT */
+
+typedef struct _GskSlTypeMember GskSlTypeMember;
+typedef struct _GskSlTypeStruct GskSlTypeStruct;
+
+struct _GskSlTypeMember {
+  GskSlType *type;
+  char *name;
+  gsize offset;
+};
+
+struct _GskSlTypeStruct {
+  GskSlType parent;
+
+  char *name;
+  gsize size;
+
+  GskSlTypeMember *members;
+  guint n_members;
+};
+
+static void
+gsk_sl_type_struct_free (GskSlType *type)
+{
+  GskSlTypeStruct *struc = (GskSlTypeStruct *) type;
+  guint i;
+
+  for (i = 0; i < struc->n_members; i++)
+    {
+      gsk_sl_type_unref (struc->members[i].type);
+      g_free (struc->members[i].name);
+    }
+
+  g_free (struc->members);
+  g_free (struc->name);
+
+  g_slice_free (GskSlTypeStruct, struc);
+}
+
+static const char *
+gsk_sl_type_struct_get_name (GskSlType *type)
+{
+  GskSlTypeStruct *struc = (GskSlTypeStruct *) type;
+
+  return struc->name;
+}
+
+static GskSlScalarType
+gsk_sl_type_struct_get_scalar_type (GskSlType *type)
+{
+  return GSK_SL_VOID;
+}
+
+static GskSlType *
+gsk_sl_type_struct_get_index_type (GskSlType *type)
+{
+  return NULL;
+}
+
+static gsize
+gsk_sl_type_struct_get_index_stride (GskSlType *type)
+{
+  return 0;
+}
+
+static guint
+gsk_sl_type_struct_get_length (GskSlType *type)
+{
+  return 0;
+}
+
+static gsize
+gsk_sl_type_struct_get_size (GskSlType *type)
+{
+  GskSlTypeStruct *struc = (GskSlTypeStruct *) type;
+
+  return struc->size;
+}
+
+static gboolean
+gsk_sl_type_struct_can_convert (GskSlType *target,
+                                GskSlType *source)
+{
+  return gsk_sl_type_equal (target, source);
+}
+
+static guint32
+gsk_sl_type_struct_write_spv (const GskSlType *type,
+                              GskSpvWriter    *writer)
+{
+  GskSlTypeStruct *struc = (GskSlTypeStruct *) type;
+  guint32 ids[struc->n_members + 1];
+  guint i;
+
+  ids[0] = gsk_spv_writer_next_id (writer);
+
+  for (i = 0; i < struc->n_members; i++)
+    {
+      ids[i + 1] = gsk_spv_writer_get_id_for_type (writer, struc->members[i].type);
+    }
+
+  gsk_spv_writer_add (writer,
+                      GSK_SPV_WRITER_SECTION_DECLARE,
+                      2 + struc->n_members, GSK_SPV_OP_TYPE_STRUCT,
+                      ids);
+  
+  return ids[0];
+}
+
+static void
+gsk_sl_type_struct_print_value (const GskSlType *type,
+                                GString         *string,
+                                gpointer         value)
+{
+  GskSlTypeStruct *struc = (GskSlTypeStruct *) type;
+  guint i;
+
+  g_string_append (string, struc->name);
+  g_string_append (string, "(");
+
+  for (i = 0; i < struc->n_members; i++)
+    {
+      if (i > 0)
+        g_string_append (string, ", ");
+      gsk_sl_type_print_value (struc->members[i].type,
+                               string,
+                               (guchar *) value + struc->members[i].offset);
+    }
+
+  g_string_append (string, ")");
+}
+
+static guint32
+gsk_sl_type_struct_write_value_spv (GskSlType    *type,
+                                    GskSpvWriter *writer,
+                                    gpointer      value)
+{
+  GskSlTypeStruct *struc = (GskSlTypeStruct *) type;
+  guint32 ids[struc->n_members + 2];
+  GskSlType *vector_type;
+  GskSlValue *v;
+  guchar *data;
+  guint i;
+
+  data = value;
+  vector_type = gsk_sl_type_get_index_type (type);
+
+  ids[0] = gsk_spv_writer_get_id_for_type (writer, type);
+  for (i = 0; i < struc->n_members; i++)
+    {
+      v = gsk_sl_value_new_for_data (struc->members[i].type,
+                                     (guchar *) value + struc->members[i].offset,
+                                     NULL, NULL);
+      ids[2 + i] = gsk_spv_writer_get_id_for_value (writer, v);
+      gsk_sl_value_free (v);
+      data += gsk_sl_type_get_size (vector_type);
+    }
+
+  ids[1] = gsk_spv_writer_next_id (writer);
+
+  gsk_spv_writer_add (writer,
+                      GSK_SPV_WRITER_SECTION_DECLARE,
+                      3 + struc->n_members,
+                      GSK_SPV_OP_CONSTANT_COMPOSITE,
+                      ids);
+  
+  return ids[1];
+}
+
+static const GskSlTypeClass GSK_SL_TYPE_STRUCT = {
+  gsk_sl_type_struct_free,
+  gsk_sl_type_struct_get_name,
+  gsk_sl_type_struct_get_scalar_type,
+  gsk_sl_type_struct_get_index_type,
+  gsk_sl_type_struct_get_index_stride,
+  gsk_sl_type_struct_get_length,
+  gsk_sl_type_struct_get_size,
+  gsk_sl_type_struct_can_convert,
+  gsk_sl_type_struct_write_spv,
+  gsk_sl_type_struct_print_value,
+  gsk_sl_type_struct_write_value_spv
+};
+
+/* API */
+
+static GskSlType *
+gsk_sl_type_parse_struct (GskSlScope        *scope,
+                          GskSlPreprocessor *preproc)
+{
+  GskSlType *type;
+  const GskSlToken *token;
+  GskSlTypeBuilder *builder;
+  gboolean add_type = FALSE;
+
+  /* the struct token */
+  gsk_sl_preprocessor_consume (preproc, NULL);
+
+  token = gsk_sl_preprocessor_get (preproc);
+  if (gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER))
+    {    
+      if (gsk_sl_scope_is_global (scope))
+        {
+          add_type = TRUE;
+          builder = gsk_sl_type_builder_new_struct (token->str);
+        }
+      else
+        {
+          builder = gsk_sl_type_builder_new_struct (NULL);
+        }
+      gsk_sl_preprocessor_consume (preproc, NULL);
+    }
+  else
+    {
+      builder = gsk_sl_type_builder_new_struct (NULL);
+    }
+
+  token = gsk_sl_preprocessor_get (preproc);
+  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_BRACE))
+    {
+      gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected opening \"{\" after struct declaration.");
+      goto out;
+    }
+  gsk_sl_preprocessor_consume (preproc, NULL);
+
+  for (token = gsk_sl_preprocessor_get (preproc);
+       !gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_BRACE) && !gsk_sl_token_is (token, GSK_SL_TOKEN_EOF);
+       token = gsk_sl_preprocessor_get (preproc))
+    {
+      type = gsk_sl_type_new_parse (scope, preproc);
+
+      while (TRUE)
+        {
+          token = gsk_sl_preprocessor_get (preproc);
+          if (!gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER))
+            {
+              gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected identifier for type name.");
+              break;
+            }
+          if (gsk_sl_type_builder_has_member (builder, token->str))
+            gsk_sl_preprocessor_error (preproc, DECLARATION, "struct already has a member named \"%s\".", 
token->str);
+          else
+            gsk_sl_type_builder_add_member (builder, type, token->str);
+          gsk_sl_preprocessor_consume (preproc, NULL);
+
+          token = gsk_sl_preprocessor_get (preproc);
+          if (!gsk_sl_token_is (token, GSK_SL_TOKEN_COMMA))
+            break;
+
+          gsk_sl_preprocessor_consume (preproc, NULL);
+        }
+      gsk_sl_type_unref (type);
+
+      if (!gsk_sl_token_is (token, GSK_SL_TOKEN_SEMICOLON))
+        gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected semicolon after struct member declaration.");
+      else
+        gsk_sl_preprocessor_consume (preproc, NULL);
+    }
+
+  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_BRACE))
+    gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected closing \"}\" after struct declaration.");
+  else
+    gsk_sl_preprocessor_consume (preproc, NULL);
+  
+out:
+  type = gsk_sl_type_builder_free (builder);
+  if (add_type)
+    {
+      if (gsk_sl_scope_lookup_type (scope, gsk_sl_type_get_name (type)))
+        gsk_sl_preprocessor_error (preproc, DECLARATION, "Redefinition of struct \"%s\".", 
gsk_sl_type_get_name (type));
+      else if (gsk_sl_scope_lookup_function (scope, gsk_sl_type_get_name (type)))
+        gsk_sl_preprocessor_error (preproc, DECLARATION, "Constructor name \"%s\" would override function of 
same name.", gsk_sl_type_get_name (type));
+      else
+        gsk_sl_scope_add_type (scope, type);
+    }
+  return type;
+}
+
 GskSlType *
-gsk_sl_type_new_parse (GskSlPreprocessor *stream)
+gsk_sl_type_new_parse (GskSlScope        *scope,
+                       GskSlPreprocessor *preproc)
 {
   GskSlType *type;
   const GskSlToken *token;
 
-  token = gsk_sl_preprocessor_get (stream);
+  token = gsk_sl_preprocessor_get (preproc);
 
   switch ((guint) token->type)
   {
@@ -969,12 +1264,25 @@ gsk_sl_type_new_parse (GskSlPreprocessor *stream)
     case GSK_SL_TOKEN_DMAT4X4:
       type = gsk_sl_type_ref (gsk_sl_type_get_matrix (GSK_SL_DOUBLE, 4, 4));
       break;
+    case GSK_SL_TOKEN_STRUCT:
+      return gsk_sl_type_parse_struct (scope, preproc);
+    case GSK_SL_TOKEN_IDENTIFIER:
+      {
+        type = gsk_sl_scope_lookup_type (scope, token->str);
+
+        if (type)
+          {
+            type = gsk_sl_type_ref (type);
+            break;
+          }
+      }
+      /* fall through */
     default:
-      gsk_sl_preprocessor_error (stream, SYNTAX, "Expected type specifier");
+      gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected type specifier");
       return gsk_sl_type_ref (gsk_sl_type_get_scalar (GSK_SL_FLOAT));
   }
 
-  gsk_sl_preprocessor_consume (stream, NULL);
+  gsk_sl_preprocessor_consume (preproc, NULL);
 
   return type;
 }
@@ -1138,6 +1446,12 @@ gsk_sl_type_is_matrix (const GskSlType *type)
   return type->class == &GSK_SL_TYPE_MATRIX;
 }
 
+gboolean
+gsk_sl_type_is_struct (const GskSlType *type)
+{
+  return type->class == &GSK_SL_TYPE_STRUCT;
+}
+
 GskSlScalarType
 gsk_sl_type_get_scalar_type (const GskSlType *type)
 {
@@ -1245,3 +1559,90 @@ gsk_sl_type_write_value_spv (GskSlType     *type,
 {
   return type->class->write_value_spv (type, writer, value);
 }
+
+struct _GskSlTypeBuilder {
+  char *name;
+  gsize size;
+  GArray *members;
+};
+
+GskSlTypeBuilder *
+gsk_sl_type_builder_new_struct (const char *name)
+{
+  GskSlTypeBuilder *builder;
+
+  builder = g_slice_new0 (GskSlTypeBuilder);
+
+  builder->name = g_strdup (name);
+  builder->members = g_array_new (FALSE, FALSE, sizeof (GskSlTypeMember));
+
+  return builder;
+}
+
+static char *
+gsk_sl_type_builder_generate_name (GskSlTypeBuilder *builder)
+{
+  GString *string = g_string_new ("struct { ");
+  guint i;
+
+  for (i = 0; i < builder->members->len; i++)
+    {
+      GskSlTypeMember *m = &g_array_index (builder->members, GskSlTypeMember, i);
+      g_string_append (string, gsk_sl_type_get_name (m->type));
+      g_string_append (string, " ");
+      g_string_append (string, m->name);
+      g_string_append (string, "; ");
+    }
+  g_string_append (string, "}");
+
+  return g_string_free (string, FALSE);
+}
+
+GskSlType *
+gsk_sl_type_builder_free (GskSlTypeBuilder *builder)
+{
+  GskSlTypeStruct *result;
+
+  result = gsk_sl_type_new (GskSlTypeStruct, &GSK_SL_TYPE_STRUCT);
+
+  if (builder->name)
+    result->name = builder->name;
+  else
+    result->name = gsk_sl_type_builder_generate_name (builder);
+  result->size = builder->size;
+  result->n_members = builder->members->len;
+  result->members = (GskSlTypeMember *) g_array_free (builder->members, FALSE);
+
+  g_slice_free (GskSlTypeBuilder, builder);
+
+  return &result->parent;
+}
+
+void
+gsk_sl_type_builder_add_member (GskSlTypeBuilder *builder,
+                                GskSlType        *type,
+                                const char       *name)
+{
+  g_array_append_vals (builder->members,
+                       &(GskSlTypeMember) {
+                           gsk_sl_type_ref (type),
+                           g_strdup (name),
+                           builder->size }, 1);
+  builder->size += gsk_sl_type_get_size (type);
+}
+
+gboolean
+gsk_sl_type_builder_has_member (GskSlTypeBuilder *builder,
+                                const char       *name)
+{
+  guint i;
+
+  for (i = 0; i < builder->members->len; i++)
+    {
+      if (g_str_equal (g_array_index (builder->members, GskSlTypeMember, i).name, name))
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
diff --git a/gsk/gsksltypeprivate.h b/gsk/gsksltypeprivate.h
index a23f3be..c07d8d6 100644
--- a/gsk/gsksltypeprivate.h
+++ b/gsk/gsksltypeprivate.h
@@ -34,7 +34,10 @@ typedef enum {
   GSK_SL_BOOL
 } GskSlScalarType;
 
-GskSlType *             gsk_sl_type_new_parse                   (GskSlPreprocessor   *stream);
+typedef struct _GskSlTypeBuilder GskSlTypeBuilder;
+
+GskSlType *             gsk_sl_type_new_parse                   (GskSlScope          *scope,
+                                                                 GskSlPreprocessor   *preproc);
 GskSlType *             gsk_sl_type_get_scalar                  (GskSlScalarType      scalar);
 GskSlType *             gsk_sl_type_get_vector                  (GskSlScalarType      scalar,
                                                                  guint                length);
@@ -48,6 +51,7 @@ void                    gsk_sl_type_unref                       (GskSlType
 gboolean                gsk_sl_type_is_scalar                   (const GskSlType     *type);
 gboolean                gsk_sl_type_is_vector                   (const GskSlType     *type);
 gboolean                gsk_sl_type_is_matrix                   (const GskSlType     *type);
+gboolean                gsk_sl_type_is_struct                   (const GskSlType     *type);
 
 const char *            gsk_sl_type_get_name                    (const GskSlType     *type);
 GskSlScalarType         gsk_sl_type_get_scalar_type             (const GskSlType     *type);
@@ -78,6 +82,14 @@ void                    gsk_sl_scalar_type_convert_value        (GskSlScalarType
                                                                  GskSlScalarType      source_type,
                                                                  gconstpointer        source_value);
 
+GskSlTypeBuilder *      gsk_sl_type_builder_new_struct          (const char          *name);
+GskSlType *             gsk_sl_type_builder_free                (GskSlTypeBuilder    *builder);
+void                    gsk_sl_type_builder_add_member          (GskSlTypeBuilder    *builder,
+                                                                 GskSlType           *type,
+                                                                 const char          *name);
+gboolean                gsk_sl_type_builder_has_member          (GskSlTypeBuilder    *builder,
+                                                                 const char          *name);
+
 G_END_DECLS
 
 #endif /* __GSK_SL_TYPE_PRIVATE_H__ */


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