home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Acorn User 10
/
AU_CD10.iso
/
Archived
/
Updates
/
Flash
/
writeflash
/
!MakeFlash
/
c
/
fonttext
< prev
next >
Wrap
Text File
|
2000-04-23
|
13KB
|
487 lines
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//
#include "proto.h"
#include "bucket.h"
#include "bitcount.h"
#include "matrix.h"
#include "rectangle.h"
#include "main.h"
#include "bbox.h"
#include "flash.h"
#include "fonttext.h"
#include "preprocess.h"
#define MAXFONTS 64
static int fontcount = 0;
static FONT *fontlist[MAXFONTS+1];
static int glyph_index(FONT *font, U8 letter, int *write);
static int is_glyph_used(FONT *font, U8 glyph);
int add_glyph_shape(GLYPH *glyph, GLYPHSHAPE *shape) {
if (!glyph->shapes) {
glyph->shapes = malloc(sizeof(GLYPHSHAPE));
if (!glyph->shapes) {
fprintf(stderr, "No room\n");
return 1;
}
glyph->shapecount = 0;
} else {
GLYPHSHAPE *newshapes;
newshapes = realloc(glyph->shapes, (glyph->shapecount+1)*sizeof(GLYPHSHAPE));
if (!newshapes) {
fprintf(stderr, "No room\n");
return 1;
}
glyph->shapes = newshapes;
}
memcpy(glyph->shapes + glyph->shapecount, shape, sizeof(GLYPHSHAPE));
glyph->shapecount++;
return 0;
}
int add_glyph(FONT *font, GLYPH *glyph) {
if (font->glyphcount == 255) {
fprintf(stderr, "Too many glyphs\n");
return 1;
}
if (!font->glyphs) {
font->glyphs = malloc(sizeof(GLYPH));
if (!font->glyphs) {
fprintf(stderr, "No room\n");
return 1;
}
font->glyphcount = 0;
} else {
GLYPH *newglyphs;
newglyphs = realloc(font->glyphs, (font->glyphcount+1)*sizeof(GLYPH));
if (!newglyphs) {
fprintf(stderr, "No room\n");
return 1;
}
font->glyphs = newglyphs;
}
memcpy(font->glyphs + font->glyphcount, glyph, sizeof(GLYPH));
font->glyphcount++;
return 0;
}
int add_text_record(TEXT *text, TEXTREC *rec) {
if (!text->records) {
text->records = malloc(sizeof(TEXTREC));
if (!text->records) {
fprintf(stderr, "No room\n");
return 1;
}
text->recordcount = 0;
} else {
TEXTREC *newrecords;
newrecords = realloc(text->records, (text->recordcount+1)*sizeof(TEXTREC));
if (!newrecords) {
fprintf(stderr, "No room\n");
return 1;
}
text->records = newrecords;
}
memcpy(text->records + text->recordcount, rec, sizeof(TEXTREC));
text->recordcount++;
return 0;
}
int fonttext_read_font() {
return 0;
}
int fonttext_write_font(FONT *font) {
U32 ptr, i, glyphoffsets, usedglyphs, gi;
U8 *buffer;
U16 *offsets;
int allglyphs;
if (font->glyphcount == 0) {
fprintf(stderr, "Empty font\n");
return 1;
}
if (find_macro("INCLUDE_ALL_GLYPHS") >= 0)
allglyphs = 1;
else
allglyphs = 0;
// count no. of glyphs to write (== no. of used glyphs)
if (allglyphs)
usedglyphs = font->glyphcount;
else {
usedglyphs = 0;
for (gi = 0; gi < font->glyphcount; gi++)
if (is_glyph_used(font, gi)) usedglyphs++;
if (usedglyphs == 0) return 0;
}
if (flush_bucket()) return 1;
ptr = read_position(NULL);
if (write_ushort(0)) return 1;
if (write_ushort(font->id)) return 1;
if (flush_bucket()) return 1;
// write empty glyph-offset-table
glyphoffsets = read_position(&buffer);
for (i = 0; i < usedglyphs; i++)
if (write_ushort(0)) return 1;
offsets = (U16 *)(buffer+glyphoffsets);
for (gi = 0; gi < font->glyphcount; gi++) {
GLYPH *glyph;
GLYPHSHAPE *shapes;
U32 n;
if ((is_glyph_used(font, gi)) || (allglyphs)) {
glyph = font->glyphs + gi;
shapes = glyph->shapes;
if (flush_bucket()) return 1;
*offsets++ = read_position(NULL) - glyphoffsets;
// bits used for fill and linestyles
if (write_ubits(4, 1)) return 1;
if (write_ubits(4, 1)) return 1;
// select fillstyle1 = 1
if (write_ubits(1, 0)) return 1;
if (write_ubits(5, SHAPERECORD_STYLE_FILL1)) return 1;
if (write_ubits(1, 1)) return 1; // fillstyle1
for (n = 0; n < glyph->shapecount; n++) {
int bits;
GLYPHSHAPE *rec;
rec = shapes+n;
switch (rec->type) {
case GLYPHSHAPE_MOVE:
if ((rec->x) || (rec->y)) {
if (write_ubits(1, 0)) return 1;
if (write_ubits(5, SHAPERECORD_STYLE_MOVE)) return 1;
bits = bitcount_signed(rec->x, rec->y, 0, 0);
if (write_ubits(5, bits)) return 1;
if (write_bits(bits, rec->x)) return 1;
if (write_bits(bits, rec->y)) return 1;
}
break;
case GLYPHSHAPE_LINE:
if ((rec->x) || (rec->y)) {
if (write_ubits(1, 1)) return 1;
if (write_ubits(1, 1)) return 1;
bits = bitcount_signed(rec->x, rec->y, 0, 0);
if (bits < 2) bits = 2;
if (write_ubits(4, bits-2)) return 1;
if ((rec->x == 0) || (rec->y == 0)) {
if (write_ubits(1, 0)) return 1;
if (rec->y == 0) {
if (write_ubits(1, 0)) return 1;
if (write_bits(bits, rec->x)) return 1;
} else {
if (write_ubits(1, 1)) return 1;
if (write_bits(bits, rec->y)) return 1;
}
} else {
if (write_ubits(1, 1)) return 1;
if (write_bits(bits, rec->x)) return 1;
if (write_bits(bits, rec->y)) return 1;
}
}
break;
case GLYPHSHAPE_CURVE:
if (write_ubits(1, 1)) return 1;
if (write_ubits(1, 0)) return 1;
bits = bitcount_signed(rec->x, rec->y, rec->ctrlx, rec->ctrly);
if (bits < 2) bits = 2;
if (write_ubits(4, bits-2)) return 1;
if (write_bits(bits, rec->ctrlx)) return 1;
if (write_bits(bits, rec->ctrly)) return 1;
if (write_bits(bits, rec->x)) return 1;
if (write_bits(bits, rec->y)) return 1;
break;
}
}
if (write_ubits(1, 0)) return 1;
if (write_ubits(5, 0)) return 1;
}
}
return update_record_header(stagDefineFont, ptr);
}
int fonttext_write_text(TEXT *text) {
U32 ptr, gbits, abits, i, allglyphs, maxglyphs;
S32 maxadv;
FONT *font;
U16 fontsize;
RECT bbox;
font = NULL;
fontsize = 0;
if (find_macro("INCLUDE_ALL_GLYPHS") >= 0)
allglyphs = 1;
else
allglyphs = 0;
if (flush_bucket()) return 1;
ptr = read_position(NULL);
if (write_ushort(0)) return 1;
if (write_ushort(text->id)) return 1;
// text bbox
if (string_bbox(text, &bbox, &maxadv)) return 1;
if (rect_write(&bbox)) return 1;
if (matrix_write(&text->matrix)) return 1;
// gbits = 8;
// abits = 16;
maxglyphs = 0;
i = 0;
do {
if (fontlist[i]) {
if (fontlist[i]->glyphcount > maxglyphs)
maxglyphs = fontlist[i]->glyphcount;
i++;
}
} while (fontlist[i]);
gbits = bitcount(maxglyphs, 0, 0, 0);
abits = 1 + bitcount(maxadv, 0, 0, 0);
if (write_ubyte(gbits)) return 1;
if (write_ubyte(abits)) return 1;
for (i = 0; i < text->recordcount; i++) {
TEXTREC *rec;
rec = text->records + i;
if (rec->flags == TEXTREC_STRING) {
int g;
if ((font == NULL) || (fontsize == 0)) {
fprintf(stderr, "No font has been selected, or illegal fontsize\n");
return 1;
}
if (write_ubyte(rec->data.text.length)) return 1;
for (g = 0; g < rec->data.text.length; g++) {
int gi, adv, write;
GLYPH *glyph;
gi = glyph_index(font, rec->data.text.text[g], &write);
// gi is the glyph index in the font in memory
// write is the glyph index in the font when written to the file
if (gi < 0) return 1;
if (allglyphs) write = gi;
if (write_ubits(gbits, write)) return 1;
glyph = font->glyphs + gi;
adv = ((font->spacing + glyph->bbox.maxx - glyph->bbox.minx) * fontsize )/1024;
if (write_bits(abits, adv)) return 1;
}
} else {
U8 flags;
flags = 128;
if (rec->flags & TEXTREC_MOVE) {
if (rec->data.style.x) flags |= 1;
if (rec->data.style.y) flags |= 2;
}
if (rec->flags & TEXTREC_COLOUR) flags |= 4;
if (rec->flags & TEXTREC_SIZE) {
flags |= 8;
fontsize = rec->data.style.size;
}
if (rec->flags & TEXTREC_FONT) {
int i;
flags |= 8;
font = NULL;
i = find_font(rec->data.style.font);
if (i == -1) {
fprintf(stderr, "Font id %d not found\n", rec->data.style.font);
return 1;
}
font = fontlist[i];
}
if (write_ubyte(flags)) return 1;
if (flags & 8)
if (write_ushort(font->id)) return 1;
if (flags & 4)
if (write_uint(rec->data.style.colour)) return 1;
if (flags & 1)
if (write_short(rec->data.style.x)) return 1;
if (flags & 2)
if (write_short(rec->data.style.y)) return 1;
if (flags & 8)
if (write_ushort(fontsize)) return 1;
}
}
if (write_ubyte(0)) return 1;
return update_record_header(stagDefineText2, ptr);
}
int string_bbox(TEXT *text, RECT *bbox, S32 *advance) {
int i, fontsize, context;
FONT *font;
S32 plotx, ploty;
font = NULL;
fontsize = 0;
*advance = 0;
bbox_init(bbox, &context);
plotx = ploty = 0;
for (i = 0; i < text->recordcount; i++) {
TEXTREC *rec;
rec = text->records + i;
if (rec->flags == TEXTREC_STRING) {
int g;
for (g = 0; g < rec->data.text.length; g++) {
int gi, adv, write;
GLYPH *glyph;
RECT gb;
gi = glyph_index(font, rec->data.text.text[g], &write);
if (gi < 0) return 1;
glyph = font->glyphs + gi;
gb.minx = plotx+glyph->bbox.minx*fontsize/1024;
gb.miny = ploty+glyph->bbox.miny*fontsize/1024;
gb.maxx = plotx+glyph->bbox.maxx*fontsize/1024;
gb.maxy = ploty+glyph->bbox.maxy*fontsize/1024;
bbox_add_bbox(bbox, &context, &gb);
// calculate advance value
adv = ((font->spacing + glyph->bbox.maxx - glyph->bbox.minx) * fontsize )/1024;
if (adv > *advance) *advance = adv;
if (-adv > *advance) *advance = -adv;
plotx += adv;
}
} else {
if (rec->flags & TEXTREC_MOVE) {
plotx += rec->data.style.x;
ploty += rec->data.style.y;
}
if (rec->flags & TEXTREC_SIZE) fontsize = rec->data.style.size;
if (rec->flags & TEXTREC_FONT) {
U16 id;
unsigned int i;
id = rec->data.style.font;
i = 0;
font = NULL;
do {
if (!fontlist[i]) return 1;
if (fontlist[i]->id == id) font = fontlist[i];
i++;
} while (!font);
}
}
}
return 0;
}
int mark_glyphs_as_used(int fontindex, U8 *string, int n) {
int i, gi;
FONT *font;
font = fontlist[fontindex];
for (i = 0; i < n; i++) {
gi = glyph_index(font, string[i], NULL);
if (gi == -1)
return 1;
else
font->usedglyphs[gi>>5] |= 1<<(gi &31);
}
return 0;
}
int find_font(U16 id) {
int i;
for (i = 0; i < fontcount; i++)
if (fontlist[i]->id == id) return i;
return -1;
}
int add_font(FONT *font) {
if (fontcount == MAXFONTS) {
fprintf(stderr, "Too many fonts\n");
return 1;
}
fontlist[fontcount++] = font;
fontlist[fontcount] = NULL;
return 0;
}
// ----------------------------------------------------------
int glyph_index(FONT *font, U8 letter, int *write) {
U32 n;
if (!font) return -1;
if (write) *write = 0;
for (n = 0; n < font->glyphcount; n++) {
if (font->glyphs[n].letter == letter) return n;
if (write)
if (is_glyph_used(font, n)) *write += 1;
}
fprintf(stderr, "Letter '%c' not defined in the selected font\n", letter);
return -1;
}
int is_glyph_used(FONT *font, U8 glyph) {
if (font->usedglyphs[glyph>>5] & (1<<(glyph &31))) return 1;
return 0;
}