summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile4
-rw-r--r--src/pencil_build.c272
-rw-r--r--src/pencil_internal.h73
-rw-r--r--src/pencil_save.c533
4 files changed, 882 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..99d4a1a
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,4 @@
+# Sources
+DIR_SOURCES := pencil_build.c pencil_save.c
+
+include build/makefiles/Makefile.subdir
diff --git a/src/pencil_build.c b/src/pencil_build.c
new file mode 100644
index 0000000..460b0af
--- /dev/null
+++ b/src/pencil_build.c
@@ -0,0 +1,272 @@
+/*
+ * This file is part of Pencil
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license
+ * Copyright 2005 James Bursa <james@semichrome.net>
+ */
+
+#define _GNU_SOURCE /* for strndup */
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include "pencil_internal.h"
+
+
+static struct pencil_item *pencil_new_item(pencil_item_type type);
+static void pencil_append_child(struct pencil_item *group,
+ struct pencil_item *child);
+static void pencil_free_item(struct pencil_item *item);
+static void pencil_dump_item(struct pencil_item *item, unsigned int depth);
+
+
+struct pencil_diagram *pencil_create(void)
+{
+ struct pencil_diagram *diagram;
+ struct pencil_item *root_group;
+
+ diagram = malloc(sizeof *diagram);
+ root_group = pencil_new_item(pencil_GROUP);
+ if (!diagram || !root_group) {
+ free(root_group);
+ free(diagram);
+ return 0;
+ }
+
+ root_group->group_name = strdup("root group");
+ if (!root_group->group_name) {
+ free(root_group);
+ free(diagram);
+ return 0;
+ }
+
+ diagram->root = root_group;
+ diagram->current_group = root_group;
+
+ return diagram;
+}
+
+
+pencil_code pencil_text(struct pencil_diagram *diagram,
+ int x, int y,
+ const char *font_family, rufl_style font_style,
+ unsigned int font_size,
+ const char *string, size_t length,
+ pencil_colour colour)
+{
+ struct pencil_item *item;
+
+ item = pencil_new_item(pencil_TEXT);
+ if (!item)
+ return pencil_OUT_OF_MEMORY;
+
+ item->x = x;
+ item->y = y;
+ item->fill_colour = colour;
+ item->font_family = font_family;
+ item->font_style = font_style;
+ item->font_size = font_size;
+ item->text = strndup(string, length);
+ if (!item->text) {
+ free(item);
+ return pencil_OUT_OF_MEMORY;
+ }
+
+ pencil_append_child(diagram->current_group, item);
+
+ return pencil_OK;
+}
+
+
+pencil_code pencil_path(struct pencil_diagram *diagram,
+ const int *path, unsigned int n,
+ pencil_colour fill_colour, pencil_colour outline_colour,
+ int thickness, pencil_join join,
+ pencil_cap start_cap, pencil_cap end_cap,
+ int cap_width, int cap_length,
+ bool even_odd, pencil_pattern pattern)
+
+{
+ struct pencil_item *item;
+
+ item = pencil_new_item(pencil_PATH);
+ if (!item)
+ return pencil_OUT_OF_MEMORY;
+
+ item->fill_colour = fill_colour;
+ item->outline_colour = outline_colour;
+ item->path = malloc(sizeof path[0] * n);
+ if (!item->path) {
+ free(item);
+ return pencil_OUT_OF_MEMORY;
+ }
+ memcpy(item->path, path, sizeof path[0] * n);
+ item->path_size = n;
+ item->thickness = thickness;
+ item->join = join;
+ item->start_cap = start_cap;
+ item->end_cap = end_cap;
+ item->cap_width = cap_width;
+ item->cap_length = cap_length;
+ item->even_odd = even_odd;
+ item->pattern = pattern;
+
+ pencil_append_child(diagram->current_group, item);
+
+ return pencil_OK;
+}
+
+
+pencil_code pencil_sprite(struct pencil_diagram *diagram,
+ int x, int y, int width, int height,
+ const char *sprite)
+{
+ struct pencil_item *item;
+
+ item = pencil_new_item(pencil_SPRITE);
+ if (!item)
+ return pencil_OUT_OF_MEMORY;
+
+ item->x = x;
+ item->y = y;
+ item->width = width;
+ item->height = height;
+ item->sprite = sprite;
+
+ pencil_append_child(diagram->current_group, item);
+
+ return pencil_OK;
+}
+
+
+pencil_code pencil_group_start(struct pencil_diagram *diagram,
+ const char *name)
+{
+ struct pencil_item *item;
+
+ item = pencil_new_item(pencil_GROUP);
+ if (!item)
+ return pencil_OUT_OF_MEMORY;
+
+ item->group_name = strdup(name);
+ if (!item->group_name) {
+ free(item);
+ return pencil_OUT_OF_MEMORY;
+ }
+
+ pencil_append_child(diagram->current_group, item);
+
+ diagram->current_group = item;
+
+ return pencil_OK;
+}
+
+
+pencil_code pencil_group_end(struct pencil_diagram *diagram)
+{
+ diagram->current_group = diagram->current_group->parent;
+
+ return pencil_OK;
+}
+
+
+struct pencil_item *pencil_new_item(pencil_item_type type)
+{
+ struct pencil_item *item;
+
+ item = malloc(sizeof *item);
+ if (!item)
+ return 0;
+
+ item->type = type;
+ item->group_name = 0;
+ item->text = 0;
+ item->path = 0;
+ item->parent = item->next = item->children = item->last = 0;
+
+ return item;
+}
+
+
+void pencil_append_child(struct pencil_item *group,
+ struct pencil_item *child)
+{
+ child->parent = group;
+ if (group->children) {
+ assert(group->last);
+ group->last->next = child;
+ } else {
+ group->children = child;
+ }
+ group->last = child;
+}
+
+
+void pencil_free(struct pencil_diagram *diagram)
+{
+ pencil_free_item(diagram->root);
+ free(diagram);
+}
+
+
+void pencil_free_item(struct pencil_item *item)
+{
+ for (struct pencil_item *child = item->children; child;
+ child = child->next)
+ pencil_free_item(child);
+ free(item->group_name);
+ free(item->text);
+ free(item->path);
+ free(item);
+}
+
+
+void pencil_dump(struct pencil_diagram *diagram)
+{
+ printf("diagram %p: current group %p\n",
+ (void *) diagram, (void *) diagram->current_group);
+ pencil_dump_item(diagram->root, 0);
+}
+
+
+void pencil_dump_item(struct pencil_item *item, unsigned int depth)
+{
+ for (unsigned int i = 0; i != depth; i++)
+ printf(" ");
+
+ printf("%p ", (void *) item);
+ switch (item->type) {
+ case pencil_GROUP:
+ printf("GROUP");
+ break;
+ case pencil_TEXT:
+ printf("TEXT (%i %i) font %s %i %i, text \"%s\"",
+ item->x, item->y,
+ item->font_family, item->font_style,
+ item->font_size, item->text);
+ break;
+ case pencil_PATH:
+ printf("PATH (");
+ for (unsigned int i = 0; i != item->path_size; i++)
+ printf("%i ", item->path[i]);
+ printf(") thickness %i, join %i, caps %i %i %i %i, ",
+ item->thickness, item->join,
+ item->start_cap, item->end_cap,
+ item->cap_width, item->cap_length);
+ if (item->even_odd)
+ printf("even-odd, ");
+ printf("pattern %i", item->pattern);
+ break;
+ case pencil_SPRITE:
+ printf("SPRITE (%i %i) (%i x %i)\n", item->x, item->y,
+ item->width, item->height);
+ break;
+ default:
+ printf("UNKNOWN");
+ }
+ printf("\n");
+
+ for (struct pencil_item *child = item->children; child;
+ child = child->next)
+ pencil_dump_item(child, depth + 1);
+}
diff --git a/src/pencil_internal.h b/src/pencil_internal.h
new file mode 100644
index 0000000..49aabf0
--- /dev/null
+++ b/src/pencil_internal.h
@@ -0,0 +1,73 @@
+/*
+ * This file is part of Pencil
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license
+ * Copyright 2005 James Bursa <james@semichrome.net>
+ */
+
+#ifndef PENCIL_INTERNAL_H
+#define PENCIL_INTERNAL_H
+
+#include <stdbool.h>
+#include "pencil.h"
+
+
+struct pencil_item;
+
+
+struct pencil_diagram {
+ struct pencil_item *root;
+ struct pencil_item *current_group;
+};
+
+typedef enum {
+ pencil_GROUP,
+ pencil_TEXT,
+ pencil_PATH,
+ pencil_SPRITE,
+} pencil_item_type;
+
+struct pencil_item {
+ pencil_item_type type;
+
+ pencil_colour fill_colour;
+ pencil_colour outline_colour;
+
+ char *group_name;
+
+ int x, y;
+
+ const char *font_family;
+ rufl_style font_style;
+ unsigned int font_size;
+ char *text;
+
+ int *path;
+ unsigned int path_size;
+ int thickness;
+ pencil_join join;
+ pencil_cap start_cap;
+ pencil_cap end_cap;
+ int cap_width;
+ int cap_length;
+ bool even_odd;
+ pencil_pattern pattern;
+
+ int width, height;
+ const void *sprite;
+
+ struct {
+ int x0;
+ int y0;
+ int x1;
+ int y1;
+ } bbox;
+
+ struct pencil_item *parent;
+ struct pencil_item *next;
+ struct pencil_item *children;
+ struct pencil_item *last;
+};
+
+
+#endif
diff --git a/src/pencil_save.c b/src/pencil_save.c
new file mode 100644
index 0000000..f5c23fb
--- /dev/null
+++ b/src/pencil_save.c
@@ -0,0 +1,533 @@
+/*
+ * This file is part of Pencil
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license
+ * Copyright 2005 James Bursa <james@semichrome.net>
+ */
+
+/** \file
+ * Saving as a DrawFile (implementation).
+ *
+ * Two passes over the diagram tree are made. The first pass computes the size
+ * that will be required and enumerates the fonts. The second pass creates the
+ * DrawFile in a buffer.
+ */
+
+#define _GNU_SOURCE /* for strndup */
+#include <assert.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <oslib/drawfile.h>
+#include <oslib/osspriteop.h>
+#include <rufl.h>
+#include "pencil_internal.h"
+
+/* Maximum grouping depth (too deep crashes Draw). */
+#define MAX_DEPTH 10
+
+
+struct pencil_save_context {
+ pencil_code code;
+ struct pencil_diagram *diagram;
+ size_t size;
+ char **font_list;
+ unsigned int font_count;
+ struct pencil_item *item;
+ void *buffer;
+ void *b;
+ os_box bbox;
+};
+
+
+static void pencil_save_pass1(struct pencil_save_context *context,
+ struct pencil_item *item, unsigned int depth);
+static void pencil_save_pass1_text_callback(void *c,
+ const char *font_name, unsigned int font_size,
+ const char *s8, unsigned short *s16, unsigned int n,
+ int x, int y);
+static void pencil_save_pass2(struct pencil_save_context *context,
+ struct pencil_item *item, unsigned int depth);
+static void pencil_save_pass2_text_callback(void *c,
+ const char *font_name, unsigned int font_size,
+ const char *s8, unsigned short *s16, unsigned int n,
+ int x, int y);
+
+
+pencil_code pencil_save_drawfile(struct pencil_diagram *diagram,
+ const char *source,
+ char **drawfile_buffer, size_t *drawfile_size)
+{
+ struct pencil_save_context context =
+ { pencil_OK, diagram, 0, 0, 0, 0, 0, 0,
+ { INT_MAX, INT_MAX, INT_MIN, INT_MIN } };
+ unsigned int i;
+ size_t size, font_table_size;
+ void *buffer, *b;
+ drawfile_diagram *header;
+ drawfile_object *font_table;
+ char *f;
+
+ *drawfile_buffer = 0;
+ *drawfile_size = 0;
+
+ /* pass 1 */
+ pencil_save_pass1(&context, diagram->root, 0);
+ if (context.code != pencil_OK) {
+ for (i = 0; i != context.font_count; i++)
+ free(context.font_list[i]);
+ free(context.font_list);
+ return context.code;
+ }
+
+ /* find font table size */
+ font_table_size = 8;
+ for (i = 0; i != context.font_count; i++)
+ font_table_size += 1 + strlen(context.font_list[i]) + 1;
+ font_table_size = (font_table_size + 3) & ~3;
+
+ size = 40 + font_table_size + context.size;
+
+ /* use calloc to prevent information leakage */
+ buffer = calloc(size, 1);
+ if (!buffer) {
+ for (i = 0; i != context.font_count; i++)
+ free(context.font_list[i]);
+ free(context.font_list);
+ return pencil_OUT_OF_MEMORY;
+ }
+
+ /* file headers */
+ header = (drawfile_diagram *) buffer;
+ header->tag[0] = 'D';
+ header->tag[1] = 'r';
+ header->tag[2] = 'a';
+ header->tag[3] = 'w';
+ header->major_version = 201;
+ header->minor_version = 0;
+ strncpy(header->source, source, 12);
+ for (i = strlen(source); i < 12; i++)
+ header->source[i] = ' ';
+ header->bbox = context.bbox;
+ b = (char *) buffer + sizeof(drawfile_diagram_base);
+
+ /* font table */
+ font_table = (drawfile_object *) b;
+ font_table->type = drawfile_TYPE_FONT_TABLE;
+ font_table->size = font_table_size;
+ f = (char *) b + 8;
+ for (i = 0; i != context.font_count; i++) {
+ *f++ = i + 1;
+ strcpy(f, context.font_list[i]);
+ f += strlen(context.font_list[i]) + 1;
+ }
+ b = (char *) b + font_table_size;
+
+ /* pass 2 */
+ context.buffer = buffer;
+ context.b = b;
+ pencil_save_pass2(&context, diagram->root, 0);
+
+ /* free font list */
+ for (i = 0; i != context.font_count; i++)
+ free(context.font_list[i]);
+ free(context.font_list);
+
+ if (context.code != pencil_OK) {
+ free(buffer);
+ return context.code;
+ }
+
+ assert(context.b == buffer + size);
+
+ *drawfile_buffer = buffer;
+ *drawfile_size = size;
+ return pencil_OK;
+}
+
+
+void pencil_save_pass1(struct pencil_save_context *context,
+ struct pencil_item *item, unsigned int depth)
+{
+ rufl_code code;
+ struct pencil_item *child;
+
+ assert(item);
+
+ /* Initialise item bounding box */
+ item->bbox.x0 = INT_MAX;
+ item->bbox.y0 = INT_MAX;
+ item->bbox.x1 = INT_MIN;
+ item->bbox.y1 = INT_MIN;
+
+ for (child = item->children; child; child = child->next) {
+ pencil_save_pass1(context, child, depth + 1);
+ if (context->code != pencil_OK)
+ return;
+
+ /* Update item bounding box to include child */
+ if (child->bbox.x0 < item->bbox.x0)
+ item->bbox.x0 = child->bbox.x0;
+ if (child->bbox.y0 < item->bbox.y0)
+ item->bbox.y0 = child->bbox.y0;
+ if (child->bbox.x1 > item->bbox.x1)
+ item->bbox.x1 = child->bbox.x1;
+ if (child->bbox.y1 > item->bbox.y1)
+ item->bbox.y1 = child->bbox.y1;
+ }
+
+ switch (item->type) {
+ case pencil_GROUP:
+ if (!item->children || MAX_DEPTH <= depth ||
+ (item->bbox.x0 == INT_MAX &&
+ item->bbox.y0 == INT_MAX &&
+ item->bbox.x1 == INT_MIN &&
+ item->bbox.y1 == INT_MIN))
+ break;
+
+ context->size += 36;
+
+ break;
+ case pencil_TEXT:
+ {
+ int bbox[4];
+ int width;
+
+ code = rufl_paint_callback(item->font_family, item->font_style,
+ item->font_size, item->text, strlen(item->text),
+ item->x, item->y,
+ pencil_save_pass1_text_callback, context);
+ if (code != rufl_OK)
+ context->code = code;
+ if (context->code != pencil_OK)
+ return;
+
+ code = rufl_font_bbox(item->font_family, item->font_style,
+ item->font_size, bbox);
+ if (code != rufl_OK)
+ context->code = code;
+ if (context->code != pencil_OK)
+ return;
+
+ code = rufl_width(item->font_family, item->font_style,
+ item->font_size, item->text, strlen(item->text),
+ &width);
+ if (code != rufl_OK)
+ context->code = code;
+ if (context->code != pencil_OK)
+ return;
+
+ item->bbox.x0 = item->x * 256;
+ item->bbox.y0 = item->y * 256;
+ item->bbox.x1 = (item->x + width) * 256;
+ item->bbox.y1 = (item->y + (bbox[3] - bbox[1])) * 256;
+ }
+ break;
+ case pencil_PATH:
+ context->size += 24 + 16 + item->path_size * 4;
+ if (item->pattern != pencil_SOLID)
+ context->size += 12;
+
+ /* Calculate bounding box */
+ for (unsigned int i = 0; i != item->path_size; ) {
+ switch (item->path[i]) {
+ case 0:
+ case 5:
+ i++;
+ break;
+ case 2:
+ case 6:
+ case 8:
+ {
+ int points = item->path[i++] == 6 ? 3 : 1;
+
+ for (; points > 0; points--) {
+ int x = item->path[i++] * 256;
+ int y = item->path[i++] * 256;
+
+ if (x < item->bbox.x0)
+ item->bbox.x0 = x;
+ if (y < item->bbox.y0)
+ item->bbox.y0 = y;
+ if (x > item->bbox.x1)
+ item->bbox.x1 = x;
+ if (y > item->bbox.y1)
+ item->bbox.y1 = y;
+ }
+ }
+ break;
+ default:
+ assert(0);
+ }
+ }
+ break;
+ case pencil_SPRITE:
+ context->size += 24 + ((const osspriteop_header *)
+ item->sprite)->size;
+
+ item->bbox.x0 = item->x * 256;
+ item->bbox.y0 = item->y * 256;
+ item->bbox.x1 = (item->x + item->width) * 256;
+ item->bbox.y1 = (item->y + item->height) * 256;
+ break;
+ default:
+ assert(0);
+ }
+
+ /* Update global bounding box */
+ if (item->bbox.x0 < context->bbox.x0)
+ context->bbox.x0 = item->bbox.x0;
+ if (item->bbox.y0 < context->bbox.y0)
+ context->bbox.y0 = item->bbox.y0;
+ if (item->bbox.x1 > context->bbox.x1)
+ context->bbox.x1 = item->bbox.x1;
+ if (item->bbox.y1 > context->bbox.y1)
+ context->bbox.y1 = item->bbox.y1;
+}
+
+
+void pencil_save_pass1_text_callback(void *c,
+ const char *font_name, unsigned int font_size,
+ const char *s8, unsigned short *s16, unsigned int n,
+ int x, int y)
+{
+ struct pencil_save_context *context = c;
+ unsigned int i;
+ char **font_list;
+
+ (void) font_size; /* unused */
+ (void) x; /* unused */
+ (void) y; /* unused */
+
+ assert(s8 || s16);
+
+ /* check if the font name is new */
+ for (i = 0; i != context->font_count &&
+ strcmp(context->font_list[i], font_name) != 0; i++)
+ ;
+ if (i == context->font_count) {
+ /* add to list of fonts */
+ font_list = realloc(context->font_list,
+ sizeof context->font_list[0] *
+ (context->font_count + 1));
+ if (!font_list) {
+ context->code = pencil_OUT_OF_MEMORY;
+ return;
+ }
+ font_list[context->font_count] = strdup(font_name);
+ if (!font_list[context->font_count]) {
+ context->code = pencil_OUT_OF_MEMORY;
+ return;
+ }
+ context->font_list = font_list;
+ context->font_count++;
+ }
+
+ /* compute size of transformed text object */
+ if (s8) {
+ context->size += 24 + 56 + ((n + 4) & ~3);
+ } else {
+ unsigned int utf8_length = 0;
+ for (i = 0; i != n; i++) {
+ if (s16[i] < 0x80)
+ utf8_length += 1;
+ else if (s16[i] < 0x800)
+ utf8_length += 2;
+ else
+ utf8_length += 3;
+ }
+ context->size += 24 + 56 + ((utf8_length + 4) & ~3);
+ }
+}
+
+
+void pencil_save_pass2(struct pencil_save_context *context,
+ struct pencil_item *item, unsigned int depth)
+{
+ drawfile_object *object = (drawfile_object *) context->b;
+ bool group = false;
+ rufl_code code;
+ int *path;
+ unsigned int i;
+ struct pencil_item *child;
+
+ assert(item);
+
+ switch (item->type) {
+ case pencil_GROUP:
+ if (!item->children || MAX_DEPTH <= depth ||
+ (item->bbox.x0 == INT_MAX &&
+ item->bbox.y0 == INT_MAX &&
+ item->bbox.x1 == INT_MIN &&
+ item->bbox.y1 == INT_MIN))
+ break;
+
+ group = true;
+ object->type = drawfile_TYPE_GROUP;
+ object->size = 36;
+ strncpy(object->data.group.name, item->group_name, 12);
+ for (i = strlen(item->group_name); i < 12; i++)
+ object->data.group.name[i] = ' ';
+ object->data.group.bbox.x0 = item->bbox.x0;
+ object->data.group.bbox.y0 = item->bbox.y0;
+ object->data.group.bbox.x1 = item->bbox.x1;
+ object->data.group.bbox.y1 = item->bbox.y1;
+ context->b = (char *) context->b + object->size;
+ break;
+ case pencil_TEXT:
+ context->item = item;
+ code = rufl_paint_callback(item->font_family, item->font_style,
+ item->font_size, item->text, strlen(item->text),
+ item->x, item->y,
+ pencil_save_pass2_text_callback, context);
+ if (code != rufl_OK)
+ context->code = code;
+ if (context->code != pencil_OK)
+ return;
+ break;
+ case pencil_PATH:
+ object->type = drawfile_TYPE_PATH;
+ object->size = 24 + 16 + item->path_size * 4;
+ object->data.path.bbox.x0 = item->bbox.x0;
+ object->data.path.bbox.y0 = item->bbox.y0;
+ object->data.path.bbox.x1 = item->bbox.x1;
+ object->data.path.bbox.y1 = item->bbox.y1;
+ object->data.path.fill = item->fill_colour;
+ object->data.path.outline = item->outline_colour;
+ object->data.path.width = item->thickness * 256;
+ object->data.path.style.flags = 0;
+ object->data.path.style.cap_width = item->cap_width;
+ object->data.path.style.cap_length = item->cap_length;
+ if (item->pattern != pencil_SOLID) {
+ object->size += 12;
+ object->data.path_with_pattern.pattern.start = 0;
+ object->data.path_with_pattern.pattern.
+ element_count = 1;
+ if (item->pattern != pencil_DOTTED)
+ object->data.path_with_pattern.pattern.
+ elements[0] = 512 * item->thickness;
+ else if (item->pattern != pencil_DASHED)
+ object->data.path_with_pattern.pattern.
+ elements[0] = 1536 * item->thickness;
+ }
+ path = (int *) (void *) ((char *) context->b + object->size -
+ item->path_size * 4);
+ for (i = 0; i != item->path_size; ) {
+ switch (item->path[i]) {
+ case 0:
+ case 5:
+ path[i] = item->path[i]; i++;
+ break;
+ case 2:
+ case 8:
+ path[i] = item->path[i]; i++;
+ path[i] = item->path[i] * 256; i++;
+ path[i] = item->path[i] * 256; i++;
+ break;
+ case 6:
+ path[i] = item->path[i]; i++;
+ path[i] = item->path[i] * 256; i++;
+ path[i] = item->path[i] * 256; i++;
+ path[i] = item->path[i] * 256; i++;
+ path[i] = item->path[i] * 256; i++;
+ path[i] = item->path[i] * 256; i++;
+ path[i] = item->path[i] * 256; i++;
+ break;
+ default:
+ assert(0);
+ }
+ }
+ context->b = (char *) context->b + object->size;
+ break;
+ case pencil_SPRITE:
+ object->type = drawfile_TYPE_SPRITE;
+ object->size = 24 + ((const osspriteop_header *)
+ item->sprite)->size;
+ object->data.sprite.bbox.x0 = item->bbox.x0;
+ object->data.sprite.bbox.y0 = item->bbox.y0;
+ object->data.sprite.bbox.x1 = item->bbox.x1;
+ object->data.sprite.bbox.y1 = item->bbox.y1;
+ memcpy(&object->data.sprite.header, item->sprite,
+ object->size - 24);
+ context->b = (char *) context->b + object->size;
+ break;
+ default:
+ assert(0);
+ }
+
+ for (child = item->children; child; child = child->next) {
+ pencil_save_pass2(context, child, depth + 1);
+ if (context->code != pencil_OK)
+ return;
+ }
+
+ if (group)
+ object->size = (char *) context->b - (char *) object;
+}
+
+
+void pencil_save_pass2_text_callback(void *c,
+ const char *font_name, unsigned int font_size,
+ const char *s8, unsigned short *s16, unsigned int n,
+ int x, int y)
+{
+ struct pencil_save_context *context = c;
+ drawfile_object *object = (drawfile_object *) context->b;
+ unsigned int i;
+
+ assert(s8 || s16);
+
+ /* find font index */
+ for (i = 0; i != context->font_count &&
+ strcmp(context->font_list[i], font_name) != 0; i++)
+ ;
+ assert(i != context->font_count);
+
+ object->type = drawfile_TYPE_TRFM_TEXT;
+ object->data.trfm_text.bbox.x0 = context->item->bbox.x0;
+ object->data.trfm_text.bbox.y0 = context->item->bbox.y0;
+ object->data.trfm_text.bbox.x1 = context->item->bbox.x1;
+ object->data.trfm_text.bbox.y1 = context->item->bbox.y1;
+ object->data.trfm_text.trfm.entries[0][0] = 0x10000;
+ object->data.trfm_text.trfm.entries[0][1] = 0;
+ object->data.trfm_text.trfm.entries[1][0] = 0;
+ object->data.trfm_text.trfm.entries[1][1] = 0x10000;
+ object->data.trfm_text.trfm.entries[2][0] = 0;
+ object->data.trfm_text.trfm.entries[2][1] = 0;
+ object->data.trfm_text.flags = drawfile_TEXT_KERN;
+ object->data.trfm_text.fill = context->item->fill_colour;
+ object->data.trfm_text.bg_hint = os_COLOUR_WHITE;
+ object->data.trfm_text.style.font_index = i + 1;
+ object->data.trfm_text.xsize = font_size * 40;
+ object->data.trfm_text.ysize = font_size * 40;
+ object->data.trfm_text.base.x = x * 256;
+ object->data.trfm_text.base.y = y * 256;
+
+ if (s8) {
+ strncpy(object->data.trfm_text.text, s8, n);
+ object->size = 24 + 56 + ((n + 4) & ~3);
+ } else {
+ char *z = object->data.trfm_text.text;
+ unsigned int utf8_length = 0;
+ for (i = 0; i != n; i++) {
+ if (s16[i] < 0x80) {
+ *z++ = s16[i];
+ utf8_length += 1;
+ } else if (s16[i] < 0x800) {
+ *z++ = 0xc0 | ((s16[i] >> 6) & 0x1f);
+ *z++ = 0x80 | (s16[i] & 0x3f);
+ utf8_length += 2;
+ } else {
+ *z++ = 0xe0 | (s16[i] >> 12);
+ *z++ = 0x80 | ((s16[i] >> 6) & 0x3f);
+ *z++ = 0x80 | (s16[i] & 0x3f);
+ utf8_length += 3;
+ }
+ }
+ object->size = 24 + 56 + ((utf8_length + 4) & ~3);
+ }
+
+ context->b = (char *) context->b + object->size;
+}