summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Bursa <james@netsurf-browser.org>2005-11-20 20:04:28 (GMT)
committer James Bursa <james@netsurf-browser.org>2005-11-20 20:04:28 (GMT)
commitdfce56be0d92c9859cb6ee5462dc7ce695311d8d (patch)
tree38493167a8a21e9530f04a02b822fd1048033188
downloadlibpencil-dfce56be0d92c9859cb6ee5462dc7ce695311d8d.tar.gz
libpencil-dfce56be0d92c9859cb6ee5462dc7ce695311d8d.tar.bz2
[project @ 2005-11-20 20:04:28 by bursa]
Initial revision svn path=/import/pencil/; revision=2475
-rw-r--r--makefile27
-rw-r--r--pencil.h86
-rw-r--r--pencil_build.c239
-rw-r--r--pencil_internal.h61
-rw-r--r--pencil_save.c400
-rw-r--r--pencil_test.c104
6 files changed, 917 insertions, 0 deletions
diff --git a/makefile b/makefile
new file mode 100644
index 0000000..5160b9d
--- a/dev/null
+++ b/makefile
@@ -0,0 +1,27 @@
+#
+# 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>
+#
+
+SOURCE = pencil_build.c pencil_save.c
+
+CC = /home/riscos/cross/bin/gcc
+CFLAGS = -std=c99 -O3 -W -Wall -Wundef -Wpointer-arith -Wcast-qual \
+ -Wcast-align -Wwrite-strings -Wstrict-prototypes \
+ -Wmissing-prototypes -Wmissing-declarations \
+ -Wnested-externs -Winline -Wno-cast-align \
+ -mpoke-function-name -I/home/riscos/env/include
+LIBS = -L/home/riscos/env/lib -loslib -lrufl
+
+all: pencil.o pencil_test,ff8
+
+pencil.o: $(SOURCE) pencil.h pencil_internal.h
+ $(CC) $(CFLAGS) -c -o $@ $(SOURCE)
+
+pencil_test,ff8: pencil_test.c pencil.o
+ $(CC) $(CFLAGS) $(LIBS) -o $@ $^
+
+clean:
+ -rm pencil.o pencil_test,ff8
diff --git a/pencil.h b/pencil.h
new file mode 100644
index 0000000..0b6e108
--- a/dev/null
+++ b/pencil.h
@@ -0,0 +1,86 @@
+/*
+ * 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_H
+#define PENCIL_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "rufl.h"
+
+
+struct pencil_diagram;
+
+
+typedef enum {
+ pencil_OK,
+ pencil_OUT_OF_MEMORY = rufl_OUT_OF_MEMORY,
+ pencil_FONT_MANAGER_ERROR = rufl_FONT_MANAGER_ERROR,
+ pencil_FONT_NOT_FOUND = rufl_FONT_NOT_FOUND,
+ pencil_IO_ERROR = rufl_IO_ERROR,
+ pencil_IO_EOF = rufl_IO_EOF,
+} pencil_code;
+
+/** A colour as 0xRRGGBB. */
+typedef uint32_t pencil_colour;
+
+#define pencil_TRANSPARENT 0xffffffff
+
+typedef enum {
+ pencil_JOIN_MITRED,
+ pencil_JOIN_ROUND,
+ pencil_JOIN_BEVELLED,
+} pencil_join;
+
+typedef enum {
+ pencil_CAP_BUTT,
+ pencil_CAP_ROUND,
+ pencil_CAP_SQUARE,
+ pencil_CAP_TRIANGLE,
+} pencil_cap;
+
+typedef enum {
+ pencil_SOLID,
+ pencil_DOTTED,
+ pencil_DASHED,
+} pencil_pattern;
+
+
+struct pencil_diagram *pencil_create(void);
+
+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);
+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);
+
+pencil_code pencil_group_start(struct pencil_diagram *diagram,
+ const char *name);
+pencil_code pencil_group_end(struct pencil_diagram *diagram);
+
+pencil_code pencil_clip_start(struct pencil_diagram *diagram,
+ int x0, int y0, int x1, int y1);
+pencil_code pencil_clip_end(struct pencil_diagram *diagram);
+
+pencil_code pencil_save_drawfile(struct pencil_diagram *diagram,
+ const char *source,
+ char **drawfile_buffer, size_t *drawfile_size);
+
+void pencil_free(struct pencil_diagram *diagram);
+
+void pencil_dump(struct pencil_diagram *diagram);
+
+
+#endif
diff --git a/pencil_build.c b/pencil_build.c
new file mode 100644
index 0000000..d550f95
--- a/dev/null
+++ b/pencil_build.c
@@ -0,0 +1,239 @@
+/*
+ * 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;
+ }
+
+ 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_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",
+ diagram, 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 ", 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;
+ 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/pencil_internal.h b/pencil_internal.h
new file mode 100644
index 0000000..0081ccc
--- a/dev/null
+++ b/pencil_internal.h
@@ -0,0 +1,61 @@
+/*
+ * 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_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;
+
+ struct pencil_item *parent;
+ struct pencil_item *next;
+ struct pencil_item *children;
+ struct pencil_item *last;
+};
+
+
+#endif
diff --git a/pencil_save.c b/pencil_save.c
new file mode 100644
index 0000000..3d33950
--- a/dev/null
+++ b/pencil_save.c
@@ -0,0 +1,400 @@
+/*
+ * 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 <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <oslib/drawfile.h>
+#include <rufl.h>
+#include "pencil_internal.h"
+
+
+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;
+ char *buffer;
+ char *b;
+};
+
+
+static void pencil_save_pass1(struct pencil_save_context *context,
+ struct pencil_item *item);
+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);
+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 };
+ unsigned int i;
+ size_t size, font_table_size;
+ char *buffer;
+ drawfile_diagram *header;
+ drawfile_object *font_table;
+ char *b, *f;
+
+ *drawfile_buffer = 0;
+ *drawfile_size = 0;
+
+ /* pass 1 */
+ pencil_save_pass1(&context, diagram->root);
+ 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] = ' ';
+ b = buffer + 40;
+
+ /* font table */
+ font_table = (drawfile_object *) b;
+ font_table->type = drawfile_TYPE_FONT_TABLE;
+ font_table->size = font_table_size;
+ f = 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 += font_table_size;
+
+ /* pass 2 */
+ context.buffer = buffer;
+ context.b = b;
+ pencil_save_pass2(&context, diagram->root);
+
+ /* 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)
+{
+ rufl_code code;
+ struct pencil_item *child;
+
+ assert(item);
+
+ switch (item->type) {
+ case pencil_GROUP:
+ context->size += 36;
+ break;
+ case pencil_TEXT:
+ 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;
+ break;
+ case pencil_PATH:
+ context->size += 24 + 16 + item->path_size * 4;
+ if (item->pattern != pencil_SOLID)
+ context->size += 12;
+ break;
+ default:
+ assert(0);
+ }
+
+ for (child = item->children; child; child = child->next) {
+ pencil_save_pass1(context, child);
+ if (context->code != pencil_OK)
+ return;
+ }
+}
+
+
+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)
+{
+ drawfile_object *object = (drawfile_object *) context->b;
+ rufl_code code;
+ int *path;
+ unsigned int i;
+ struct pencil_item *child;
+
+ assert(item);
+
+ switch (item->type) {
+ case pencil_GROUP:
+ 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] = ' ';
+ 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 = 0;
+ object->data.path.bbox.y0 = 0;
+ object->data.path.bbox.x1 = 0;
+ object->data.path.bbox.y1 = 0;
+ 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 *) (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 += object->size;
+ break;
+ default:
+ assert(0);
+ }
+
+ for (child = item->children; child; child = child->next) {
+ pencil_save_pass2(context, child);
+ if (context->code != pencil_OK)
+ return;
+ }
+
+ if (item->type == pencil_GROUP) {
+ object->size = 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 = x * 256;
+ object->data.trfm_text.bbox.y0 = y * 256;
+ object->data.trfm_text.bbox.x1 = x * 256;
+ object->data.trfm_text.bbox.y1 = y * 256;
+ 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 += object->size;
+}
diff --git a/pencil_test.c b/pencil_test.c
new file mode 100644
index 0000000..b1c26d4
--- a/dev/null
+++ b/pencil_test.c
@@ -0,0 +1,104 @@
+/*
+ * 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>
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <oslib/osfile.h>
+#include <rufl.h>
+#include "pencil.h"
+
+
+static void test_pencil(void);
+
+
+int main(int argc, char *argv[])
+{
+ rufl_code code;
+
+ code = rufl_init();
+ if (code != rufl_OK) {
+ printf("rufl_init failed: %i\n", code);
+ return 1;
+ }
+
+ test_pencil();
+
+ rufl_quit();
+
+ return 0;
+}
+
+
+void test_pencil(void)
+{
+ struct pencil_diagram *diagram;
+ pencil_code code;
+ int path[] = {2, 100, 40, 8, 100, 400, 8, 300, 300, 0};
+ char utf8_test[] = "Hello, world! ὕαλον "
+ "Uherské Hradiště. 𐀀";
+ char *drawfile_buffer;
+ size_t drawfile_size;
+ os_error *error;
+
+ diagram = pencil_create();
+ if (!diagram) {
+ printf("pencil_create failed\n");
+ return;
+ }
+
+ code = pencil_text(diagram,
+ 100, 40,
+ "Homerton", rufl_REGULAR,
+ 320,
+ "Hello, world!", 13,
+ 0x000000);
+ if (code != pencil_OK) {
+ printf("pencil_text failed: %i\n", code);
+ return;
+ }
+
+ code = pencil_path(diagram,
+ path, sizeof path / sizeof path[0],
+ 0x00ff00, 0x0000ff,
+ 5, pencil_JOIN_ROUND,
+ pencil_CAP_BUTT, pencil_CAP_TRIANGLE,
+ 15, 20,
+ false, pencil_SOLID);
+ if (code != pencil_OK) {
+ printf("pencil_path failed: %i\n", code);
+ return;
+ }
+
+ code = pencil_text(diagram,
+ 100, 400,
+ "NewHall", rufl_REGULAR,
+ 320,
+ utf8_test, sizeof utf8_test,
+ 0xff0000);
+ if (code != pencil_OK) {
+ printf("pencil_text failed: %i\n", code);
+ return;
+ }
+
+ pencil_dump(diagram);
+
+ code = pencil_save_drawfile(diagram, "Pencil-Test",
+ &drawfile_buffer, &drawfile_size);
+ if (code != pencil_OK) {
+ printf("pencil_save_drawfile failed: %i\n", code);
+ return;
+ }
+ assert(drawfile_buffer);
+
+ error = xosfile_save_stamped("DrawFile", osfile_TYPE_DRAW,
+ drawfile_buffer, drawfile_buffer + drawfile_size);
+ if (error) {
+ printf("xosfile_save_stamped failed: 0x%x: %s\n",
+ error->errnum, error->errmess);
+ return;
+ }
+}