]> gitweb.michael.orlitzky.com - libsvgtiny.git/commitdiff
Add svgtiny_list and convert gradient plotting to use it.
authorJames Bursa <james@netsurf-browser.org>
Sun, 30 Mar 2008 01:14:46 +0000 (01:14 -0000)
committerJames Bursa <james@netsurf-browser.org>
Sun, 30 Mar 2008 01:14:46 +0000 (01:14 -0000)
svn path=/trunk/libsvgtiny/; revision=4062

makefile
svgtiny_gradient.c
svgtiny_internal.h
svgtiny_list.c [new file with mode: 0644]

index 817f906b10e0cbdab7e56fed0b947ebdfe529d18..582a93b56a837c44d230a042fad05c043ed3ac01 100644 (file)
--- a/makefile
+++ b/makefile
@@ -5,7 +5,7 @@
 # Copyright 2008 James Bursa <james@semichrome.net>
 #
 
-SOURCE = svgtiny.c svgtiny_gradient.c colors.c
+SOURCE = svgtiny.c svgtiny_gradient.c svgtiny_list.c colors.c
 HDRS = svgtiny.h svgtiny_internal.h
 
 CFLAGS = -std=c99 -W -Wall -Wundef -Wpointer-arith -Wcast-qual \
@@ -18,8 +18,8 @@ INSTALL = install
 ifeq ($(TARGET),riscos)
 GCCSDK_INSTALL_CROSSBIN ?= /home/riscos/cross/bin
 GCCSDK_INSTALL_ENV ?= /home/riscos/env
-CC ?= $(GCCSDK_INSTALL_CROSSBIN)/gcc
-AR ?= $(GCCSDK_INSTALL_CROSSBIN)/ar
+CC = $(GCCSDK_INSTALL_CROSSBIN)/gcc
+AR = $(GCCSDK_INSTALL_CROSSBIN)/ar
 CFLAGS += -Driscos -mpoke-function-name -I$(GCCSDK_INSTALL_ENV)/include \
        -I$(GCCSDK_INSTALL_ENV)/include/libxml2
 LIBS = -L$(GCCSDK_INSTALL_ENV)/lib -lxml2 -lz
index 31dba1e313b1b5f07e3b54cbd312d6b59055d330..be4f2565cceee90cae88e6d56176d5a5ba14ea52 100644 (file)
@@ -288,10 +288,10 @@ svgtiny_code svgtiny_add_path_linear_gradient(float *p, unsigned int n,
        struct grad_point {
                float x, y, r;
        };
-       struct grad_point *pts = malloc(n * steps * sizeof pts[0]);
+       struct svgtiny_list *pts = svgtiny_list_create(
+                       sizeof (struct grad_point));
        if (!pts)
                return svgtiny_OUT_OF_MEMORY;
-       unsigned int pts_count = 0;
        float min_r = 1000;
        unsigned int min_pt = 0;
        for (unsigned int j = 0; j != n; ) {
@@ -314,14 +314,18 @@ svgtiny_code svgtiny_add_path_linear_gradient(float *p, unsigned int n,
                r0 = ((x0_trans - gradient_x0) * gradient_dx +
                                (y0_trans - gradient_y0) * gradient_dy) /
                                gradient_norm_squared;
-               pts[pts_count].x = x0;
-               pts[pts_count].y = y0;
-               pts[pts_count].r = r0;
+               struct grad_point *point = svgtiny_list_push(pts);
+               if (!point) {
+                       svgtiny_list_free(pts);
+                       return svgtiny_OUT_OF_MEMORY;
+               }
+               point->x = x0;
+               point->y = y0;
+               point->r = r0;
                if (r0 < min_r) {
                        min_r = r0;
-                       min_pt = pts_count;
+                       min_pt = svgtiny_list_size(pts) - 1;
                }
-               pts_count++;
 
                /* end point (x1, y1) */
                if (segment_type == svgtiny_PATH_LINE) {
@@ -377,14 +381,18 @@ svgtiny_code svgtiny_add_path_linear_gradient(float *p, unsigned int n,
                                        (y_trans - gradient_y0) * gradient_dy) /
                                        gradient_norm_squared;
                        fprintf(stderr, "(%g %g [%g]) ", x, y, r);
-                       pts[pts_count].x = x;
-                       pts[pts_count].y = y;
-                       pts[pts_count].r = r;
+                       struct grad_point *point = svgtiny_list_push(pts);
+                       if (!point) {
+                               svgtiny_list_free(pts);
+                               return svgtiny_OUT_OF_MEMORY;
+                       }
+                       point->x = x;
+                       point->y = y;
+                       point->r = r;
                        if (r < min_r) {
                                min_r = r;
-                               min_pt = pts_count;
+                               min_pt = svgtiny_list_size(pts) - 1;
                        }
-                       pts_count++;
                }
                fprintf(stderr, "\n");
 
@@ -392,8 +400,8 @@ svgtiny_code svgtiny_add_path_linear_gradient(float *p, unsigned int n,
                x0 = x1;
                y0 = y1;
        }
-       fprintf(stderr, "pts_count %i, min_pt %i, min_r %.3f\n",
-                       pts_count, min_pt, min_r);
+       fprintf(stderr, "pts size %i, min_pt %i, min_r %.3f\n",
+                       svgtiny_list_size(pts), min_pt, min_r);
 
        /* render triangles */
        unsigned int stop_count = state->linear_gradient_stop_count;
@@ -407,10 +415,13 @@ svgtiny_code svgtiny_add_path_linear_gradient(float *p, unsigned int n,
        blue0 = blue1 = svgtiny_BLUE(state->gradient_stop[0].color);
        unsigned int t, a, b;
        t = min_pt;
-       a = (min_pt + 1) % pts_count;
-       b = min_pt == 0 ? pts_count - 1 : min_pt - 1;
+       a = (min_pt + 1) % svgtiny_list_size(pts);
+       b = min_pt == 0 ? svgtiny_list_size(pts) - 1 : min_pt - 1;
        while (a != b) {
-               float mean_r = (pts[t].r + pts[a].r + pts[b].r) / 3;
+               struct grad_point *point_t = svgtiny_list_get(pts, t);
+               struct grad_point *point_a = svgtiny_list_get(pts, a);
+               struct grad_point *point_b = svgtiny_list_get(pts, b);
+               float mean_r = (point_t->r + point_a->r + point_b->r) / 3;
                /*fprintf(stderr, "triangle: t %i %.3f a %i %.3f b %i %.3f "
                                "mean_r %.3f\n",
                                t, pts[t].r, a, pts[a].r, b, pts[b].r,
@@ -436,14 +447,14 @@ svgtiny_code svgtiny_add_path_linear_gradient(float *p, unsigned int n,
                if (!p)
                        return svgtiny_OUT_OF_MEMORY;
                p[0] = svgtiny_PATH_MOVE;
-               p[1] = pts[t].x;
-               p[2] = pts[t].y;
+               p[1] = point_t->x;
+               p[2] = point_t->y;
                p[3] = svgtiny_PATH_LINE;
-               p[4] = pts[a].x;
-               p[5] = pts[a].y;
+               p[4] = point_a->x;
+               p[5] = point_a->y;
                p[6] = svgtiny_PATH_LINE;
-               p[7] = pts[b].x;
-               p[8] = pts[b].y;
+               p[7] = point_b->x;
+               p[8] = point_b->y;
                p[9] = svgtiny_PATH_CLOSE;
                svgtiny_transform_path(p, 10, state);
                struct svgtiny_shape *shape = svgtiny_add_shape(state);
@@ -472,12 +483,12 @@ svgtiny_code svgtiny_add_path_linear_gradient(float *p, unsigned int n,
                shape->stroke = svgtiny_RGB(0, 0, 0xff);
                #endif
                state->diagram->shape_count++;
-               if (pts[a].r < pts[b].r) {
+               if (point_a->r < point_b->r) {
                        t = a;
-                       a = (a + 1) % pts_count;
+                       a = (a + 1) % svgtiny_list_size(pts);
                } else {
                        t = b;
-                       b = b == 0 ? pts_count - 1 : b - 1;
+                       b = b == 0 ? svgtiny_list_size(pts) - 1 : b - 1;
                }
        }
 
@@ -510,19 +521,20 @@ svgtiny_code svgtiny_add_path_linear_gradient(float *p, unsigned int n,
 
        /* render triangle vertices with r values for debugging */
        #ifdef GRADIENT_DEBUG
-       for (unsigned int i = 0; i != pts_count; i++) {
+       for (unsigned int i = 0; i != pts->size; i++) {
+               struct grad_point *point = svgtiny_list_get(pts, i);
                struct svgtiny_shape *shape = svgtiny_add_shape(state);
                if (!shape)
                        return svgtiny_OUT_OF_MEMORY;
                char *text = malloc(20);
                if (!text)
                        return svgtiny_OUT_OF_MEMORY;
-               sprintf(text, "%i=%.3f", i, pts[i].r);
+               sprintf(text, "%i=%.3f", i, point->r);
                shape->text = text;
-               shape->text_x = state->ctm.a * pts[i].x +
-                               state->ctm.c * pts[i].y + state->ctm.e;
-               shape->text_y = state->ctm.b * pts[i].x +
-                               state->ctm.d * pts[i].y + state->ctm.f;
+               shape->text_x = state->ctm.a * point->x +
+                               state->ctm.c * point->y + state->ctm.e;
+               shape->text_y = state->ctm.b * point->x +
+                               state->ctm.d * point->y + state->ctm.f;
                shape->fill = svgtiny_RGB(0, 0, 0);
                shape->stroke = svgtiny_TRANSPARENT;
                state->diagram->shape_count++;
@@ -542,8 +554,12 @@ svgtiny_code svgtiny_add_path_linear_gradient(float *p, unsigned int n,
                shape->path_length = n;
                shape->fill = svgtiny_TRANSPARENT;
                state->diagram->shape_count++;
+       } else {
+               free(p);
        }
 
+       svgtiny_list_free(pts);
+
        return svgtiny_OK;
 }
 
index a729f253ff4e2f2234a1c78051f9178ae82d9da1..f07f4308a181420b42d2c2e50a99c773d7997202 100644 (file)
@@ -47,6 +47,7 @@ struct svgtiny_parse_state {
        } gradient_transform;
 };
 
+struct svgtiny_list;
 
 /* svgtiny.c */
 float svgtiny_parse_length(const char *s, int viewport_size,
@@ -65,6 +66,16 @@ svgtiny_code svgtiny_add_path_linear_gradient(float *p, unsigned int n,
                struct svgtiny_parse_state *state);
 xmlNode *svgtiny_find_element_by_id(xmlNode *node, const char *id);
 
+/* svgtiny_list.c */
+struct svgtiny_list *svgtiny_list_create(size_t item_size);
+unsigned int svgtiny_list_size(struct svgtiny_list *list);
+svgtiny_code svgtiny_list_resize(struct svgtiny_list *list,
+               unsigned int new_size);
+void *svgtiny_list_get(struct svgtiny_list *list,
+               unsigned int i);
+void *svgtiny_list_push(struct svgtiny_list *list);
+void svgtiny_list_free(struct svgtiny_list *list);
+
 /* colors.gperf */
 const struct svgtiny_named_color *
                svgtiny_color_lookup(register const char *str,
diff --git a/svgtiny_list.c b/svgtiny_list.c
new file mode 100644 (file)
index 0000000..53cfb34
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * This file is part of Libsvgtiny
+ * Licensed under the MIT License,
+ *                http://opensource.org/licenses/mit-license.php
+ * Copyright 2008 James Bursa <james@semichrome.net>
+ */
+
+/**
+ * A svgtiny_list is a managed array of objects. It grows in chunks to reduce
+ * calls to realloc(), but keeps wasted space low.
+ */
+
+#include <assert.h>
+#include "svgtiny.h"
+#include "svgtiny_internal.h"
+
+
+struct svgtiny_list {
+       unsigned int size;      /* number of slots used */
+       unsigned int allocated; /* number of slots allocated (>= size) */
+       size_t item_size;       /* size of each slot / bytes */
+       char *items;            /* array of slots */
+};
+
+
+/**
+ * Create an empty svgtiny_list.
+ */
+
+struct svgtiny_list *svgtiny_list_create(size_t item_size)
+{
+       struct svgtiny_list *list = malloc(sizeof *list);
+       if (!list)
+               return 0;
+       list->size = 0;
+       list->allocated = 0;
+       list->item_size = item_size;
+       list->items = 0;
+       return list;
+}
+
+
+/**
+ * Return the number of objects in a list.
+ */
+
+unsigned int svgtiny_list_size(struct svgtiny_list *list)
+{
+       return list->size;
+}
+
+
+/**
+ * Set the number of objects in a list. If the size is increased, the new
+ * objects are not initialized in any way.
+ *
+ * The allocation size formula is taken from Python's list:
+ * http://svn.python.org/view/python/trunk/Objects/listobject.c?view=markup
+ *
+ * Objects may have moved after this call. Use svgtiny_list_get() to get new
+ * pointers.
+ */
+
+svgtiny_code svgtiny_list_resize(struct svgtiny_list *list,
+               unsigned int new_size)
+{
+       unsigned int new_allocated;
+       void *new_items;
+
+       if (new_size <= list->allocated) {
+               list->size = new_size;
+               return svgtiny_OK;
+       }
+
+       new_allocated = (new_size >> 3) + (new_size < 9 ? 3 : 6) + new_size;
+       if (new_size == 0)
+               new_allocated = 0;
+       new_items = realloc(list->items, new_allocated * list->item_size);
+       if (!new_items)
+               return svgtiny_OUT_OF_MEMORY;
+
+       list->size = new_size;
+       list->allocated = new_allocated;
+       list->items = new_items;
+
+       return svgtiny_OK;
+}
+
+
+/**
+ * Return a pointer to an object in a list.
+ */
+
+void *svgtiny_list_get(struct svgtiny_list *list,
+               unsigned int i)
+{
+       assert(i < list->size);
+       return (void *) (list->items + i * list->item_size);
+}
+
+
+/**
+ * Add space for one object to a list and return a pointer to it.
+ */
+
+void *svgtiny_list_push(struct svgtiny_list *list)
+{
+       svgtiny_code code;
+       code = svgtiny_list_resize(list, list->size + 1);
+       if (code != svgtiny_OK)
+               return 0;
+       return svgtiny_list_get(list, list->size - 1);
+}
+
+
+/**
+ * Free an entire list.
+ */
+
+void svgtiny_list_free(struct svgtiny_list *list)
+{
+       free(list->items);
+       free(list);
+}
+