output-item: Collapse the inheritance hierarchy into a single struct.
[pspp] / src / output / spv / spv.c
index b82b7693ed2718515f38a2915f5944aa71ddd768..fdafb5aba7c96c3ef3cb0ff9a815b2360257a96a 100644 (file)
@@ -31,7 +31,7 @@
 #include "libpspp/message.h"
 #include "libpspp/str.h"
 #include "libpspp/zip-reader.h"
-#include "output/page-setup-item.h"
+#include "output/page-setup.h"
 #include "output/pivot-table.h"
 #include "output/spv/detail-xml-parser.h"
 #include "output/spv/light-binary-parser.h"
@@ -39,6 +39,7 @@
 #include "output/spv/spv-legacy-data.h"
 #include "output/spv/spv-legacy-decoder.h"
 #include "output/spv/spv-light-decoder.h"
+#include "output/spv/spv-table-look.h"
 #include "output/spv/structure-xml-parser.h"
 
 #include "gl/c-ctype.h"
@@ -76,7 +77,7 @@ spv_item_type_to_string (enum spv_item_type type)
     case SPV_ITEM_TABLE: return "table";
     case SPV_ITEM_GRAPH: return "graph";
     case SPV_ITEM_MODEL: return "model";
-    case SPV_ITEM_OBJECT: return "object";
+    case SPV_ITEM_IMAGE: return "image";
     default: return "**error**";
     }
 }
@@ -101,7 +102,7 @@ spv_item_class_from_string (const char *name)
   SPV_CLASSES
 #undef SPV_CLASS
 
-  return SPV_N_CLASSES;
+  return (enum spv_item_class) SPV_N_CLASSES;
 }
 
 enum spv_item_type
@@ -139,7 +140,7 @@ spv_item_get_class (const struct spv_item *item)
     case SPV_ITEM_MODEL:
       return SPV_CLASS_MODELS;
 
-    case SPV_ITEM_OBJECT:
+    case SPV_ITEM_IMAGE:
       return SPV_CLASS_OTHER;
 
     case SPV_ITEM_TREE:
@@ -194,6 +195,51 @@ spv_item_get_text (const struct spv_item *item)
   return item->text;
 }
 
+bool
+spv_item_is_image (const struct spv_item *item)
+{
+  return item->type == SPV_ITEM_IMAGE;
+}
+
+static cairo_status_t
+read_from_zip_member (void *zm_, unsigned char *data, unsigned int length)
+{
+  struct zip_member *zm = zm_;
+  if (!zm)
+    return CAIRO_STATUS_READ_ERROR;
+
+  while (length > 0)
+    {
+      int n = zip_member_read (zm, data, length);
+      if (n <= 0)
+        return CAIRO_STATUS_READ_ERROR;
+
+      data += n;
+      length -= n;
+    }
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_surface_t *
+spv_item_get_image (const struct spv_item *item_)
+{
+  struct spv_item *item = CONST_CAST (struct spv_item *, item_);
+  assert (spv_item_is_image (item));
+
+  if (!item->image)
+    {
+      struct zip_member *zm = zip_member_open (item->spv->zip,
+                                               item->png_member);
+      item->image = cairo_image_surface_create_from_png_stream (
+        read_from_zip_member, zm);
+      if (zm)
+        zip_member_finish (zm);
+    }
+
+  return item->image;
+}
+
 struct spv_item *
 spv_item_next (const struct spv_item *item)
 {
@@ -259,15 +305,16 @@ spv_item_destroy (struct spv_item *item)
       free (item->children);
 
       pivot_table_unref (item->table);
-      spv_legacy_properties_destroy (item->legacy_properties);
+      pivot_table_look_unref (item->table_look);
       free (item->bin_member);
       free (item->xml_member);
       free (item->subtype);
 
       pivot_value_destroy (item->text);
 
-      free (item->object_type);
-      free (item->uri);
+      free (item->png_member);
+      if (item->image)
+        cairo_surface_destroy (item->image);
 
       free (item);
     }
@@ -572,6 +619,8 @@ spv_item_load (const struct spv_item *item)
 {
   if (spv_item_is_table (item))
     spv_item_get_table (item);
+  else if (spv_item_is_image (item))
+    spv_item_get_image (item);
 }
 
 bool
@@ -605,7 +654,7 @@ spv_item_get_light_table (const struct spv_item *item,
   struct spvbin_input input;
   spvbin_input_init (&input, data, size);
 
-  struct spvlb_table *table;
+  struct spvlb_table *table = NULL;
   error = (!size
            ? xasprintf ("light table member is empty")
            : !spvlb_parse_table (&input, &table)
@@ -827,7 +876,7 @@ pivot_table_open_legacy (struct spv_item *item)
   error = spvxml_context_finish (&ctx, &v->node_);
 
   if (!error)
-    error = decode_spvdx_table (v, item->subtype, item->legacy_properties,
+    error = decode_spvdx_table (v, item->subtype, item->table_look,
                                 &data, &item->table);
 
   if (error)
@@ -848,7 +897,7 @@ pivot_table_open_legacy (struct spv_item *item)
   return error;
 }
 
-struct pivot_table *
+const struct pivot_table *
 spv_item_get_table (const struct spv_item *item_)
 {
   struct spv_item *item = CONST_CAST (struct spv_item *, item_);
@@ -905,8 +954,10 @@ spv_decode_container (const struct spvsx_container *c,
       if (ts->path)
         {
           item->xml_member = ts->path ? xstrdup (ts->path->text) : NULL;
-          char *error = decode_spvsx_legacy_properties (
-            table->table_properties, &item->legacy_properties);
+          char *error = (table->table_properties
+                         ? spv_table_look_decode (table->table_properties,
+                                                  &item->table_look)
+                         : xstrdup ("Legacy table lacks tableProperties"));
           if (error)
             {
               spv_item_destroy (item);
@@ -931,24 +982,17 @@ spv_decode_container (const struct spvsx_container *c,
   else if (spvsx_is_object (content))
     {
       struct spvsx_object *object = spvsx_cast_object (content);
-      item->type = SPV_ITEM_OBJECT;
-      item->object_type = xstrdup (object->type);
-      item->uri = xstrdup (object->uri);
+      item->type = SPV_ITEM_IMAGE;
+      item->png_member = xstrdup (object->uri);
     }
   else if (spvsx_is_image (content))
     {
       struct spvsx_image *image = spvsx_cast_image (content);
-      item->type = SPV_ITEM_OBJECT;
-      item->object_type = xstrdup ("image");
-      item->uri = xstrdup (image->data_path->text);
+      item->type = SPV_ITEM_IMAGE;
+      item->png_member = xstrdup (image->data_path->text);
     }
   else if (spvsx_is_tree (content))
-    {
-      struct spvsx_tree *tree = spvsx_cast_tree (content);
-      item->type = SPV_ITEM_TREE;
-      item->object_type = xstrdup ("tree");
-      item->uri = xstrdup (tree->data_path->text);
-    }
+    item->type = SPV_ITEM_TREE;
   else
     NOT_REACHED ();
 
@@ -965,7 +1009,7 @@ spv_decode_children (struct spv_reader *spv, const char *structure_member,
     {
       const struct spvxml_node *node = seq[i];
 
-      char *error;
+      char *error = NULL;
       if (spvsx_is_container (node))
         {
           const struct spvsx_container *container
@@ -1184,6 +1228,24 @@ spv_close (struct spv_reader *spv)
     }
 }
 
+void
+spv_item_set_table_look (struct spv_item *item,
+                         const struct pivot_table_look *look)
+{
+  /* If this is a table, install the table look in it.
+
+     (We can't just set item->table_look because light tables ignore it and
+     legacy tables sometimes override it.) */
+  if (spv_item_is_table (item))
+    {
+      spv_item_load (item);
+      pivot_table_set_look (item->table, look);
+    }
+
+  for (size_t i = 0; i < item->n_children; i++)
+    spv_item_set_table_look (item->children[i], look);
+}
+
 char * WARN_UNUSED_RESULT
 spv_decode_fmt_spec (uint32_t u32, struct fmt_spec *out)
 {