#include <stdlib.h>
#include <stdio.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include "fonttosfnt.h"
FontPtr
makeFont()
{
FontPtr font;
font = malloc(sizeof(FontRec));
if(font == NULL)
return NULL;
font->numNames = 0;
font->names = NULL;
font->flags = 0;
font->weight = 500;
font->width = 5;
font->italicAngle = 0;
font->underlinePosition = - TWO_SIXTEENTH;
font->underlineThickness = TWO_SIXTEENTH;
font->foundry = makeName("UNKN");
font->strikes = NULL;
return font;
}
StrikePtr
makeStrike(FontPtr font, int sizeX, int sizeY)
{
StrikePtr strike, last_strike;
strike = font->strikes;
last_strike = NULL;
while(strike) {
if(strike->sizeX == sizeX && strike->sizeY == sizeY)
return strike;
last_strike = strike;
strike = strike->next;
}
strike = malloc(sizeof(StrikeRec));
if(strike == NULL)
return NULL;
strike->sizeX = sizeX;
strike->sizeY = sizeY;
strike->bitmaps =
calloc(FONT_CODES / FONT_SEGMENT_SIZE, sizeof(BitmapPtr*));
if(strike->bitmaps == NULL) {
free(strike);
return NULL;
}
strike->numSbits = 0;
strike->next = NULL;
strike->bitmapSizeTableLocation = 0xDEADFACE;
strike->indexSubTables = NULL;
if(last_strike)
last_strike->next = strike;
else
font->strikes = strike;
return strike;
}
BitmapPtr
makeBitmap(StrikePtr strike, int code,
int advanceWidth, int horiBearingX, int horiBearingY,
int width, int height, int stride, unsigned char *raster, int crop)
{
BitmapPtr bitmap;
int i, j, x, y;
int dx, dy, new_width, new_height;
bitmap = malloc(sizeof(BitmapRec));
if(bitmap == NULL)
return NULL;
bitmap->index = -1;
bitmap->width = 0;
bitmap->height = 0;
bitmap->stride = 0;
bitmap->raster = NULL;
bitmap->location = 0xDEADFACE;
i = code / FONT_SEGMENT_SIZE;
j = code % FONT_SEGMENT_SIZE;
if(strike->bitmaps[i] == NULL) {
strike->bitmaps[i] = calloc(FONT_SEGMENT_SIZE, sizeof(BitmapPtr));
}
if(strike->bitmaps[i] == NULL) {
free(bitmap);
return NULL;
}
if(strike->bitmaps[i][j] != NULL) {
if(verbose_flag)
fprintf(stderr, "Duplicate bitmap %d.\n", code);
free(bitmap);
return strike->bitmaps[i][j];
}
dx = 0;
dy = 0;
new_width = width;
new_height = height;
if(crop) {
int empty;
while(new_width > 0) {
empty = 1;
x = new_width - 1;
for(y = 0; y < new_height; y++) {
if(BITREF(raster, stride, x + dx, y + dy)) {
empty = 0;
break;
}
}
if(empty)
new_width--;
else
break;
}
while(new_height > 0) {
empty = 1;
y = new_height - 1;
for(x = 0; x < new_width; x++) {
if(BITREF(raster, stride, x + dx, y + dy)) {
empty = 0;
break;
}
}
if(empty)
new_height--;
else
break;
}
while(new_width > 0) {
empty = 1;
x = 0;
for(y = 0; y < new_height; y++) {
if(BITREF(raster, stride, x + dx, y + dy)) {
empty = 0;
break;
}
}
if(empty) {
dx++;
new_width--;
} else
break;
}
while(new_height > 0) {
empty = 1;
y = 0;
for(x = 0; x < new_width; x++) {
if(BITREF(raster, stride, x + dx, y + dy)) {
empty = 0;
break;
}
}
if(empty) {
dy++;
new_height--;
} else
break;
}
}
bitmap->advanceWidth = advanceWidth;
bitmap->horiBearingX = horiBearingX + dx;
bitmap->horiBearingY = horiBearingY - dy;
bitmap->width = new_width;
bitmap->height = new_height;
bitmap->stride = (new_width + 7) / 8;
bitmap->raster = malloc(bitmap->height * bitmap->stride);
if(bitmap->raster == NULL) {
free(bitmap);
return NULL;
}
memset(bitmap->raster, 0, bitmap->height * bitmap->stride);
for(y = 0; y < new_height; y++) {
for(x = 0; x < new_width; x++) {
if(BITREF(raster, stride, x + dx, y + dy))
bitmap->raster[y * bitmap->stride + x / 8] |=
1 << (7 - (x % 8));
}
}
strike->bitmaps[i][j] = bitmap;
strike->numSbits++;
return bitmap;
}
IndexSubTablePtr
makeIndexSubTables(StrikePtr strike, CmapPtr cmap)
{
IndexSubTablePtr table, first, last;
BitmapPtr bitmap0, bitmap;
int index, n;
first = NULL;
last = NULL;
index = 0;
while(index < 0xFFFF) {
int constantMetrics = 1;
bitmap0 = strikeBitmapIndex(strike, cmap, index);
if(bitmap0 == NULL) {
index++;
continue;
}
n = 1;
while((bitmap = strikeBitmapIndex(strike, cmap, index + n)) != NULL) {
if(constantMetrics) {
if(!SAME_METRICS(bitmap0, bitmap)) {
if(bit_aligned_flag && n >= 4)
break;
else
constantMetrics = 0;
}
} else if(bit_aligned_flag) {
BitmapPtr b1 = strikeBitmapIndex(strike, cmap, index + n + 1);
BitmapPtr b2 = strikeBitmapIndex(strike, cmap, index + n + 2);
BitmapPtr b3 = strikeBitmapIndex(strike, cmap, index + n + 3);
BitmapPtr b4 = strikeBitmapIndex(strike, cmap, index + n + 4);
if(b1 && b2 && b3 && b4 &&
SAME_METRICS(bitmap, b1) &&
SAME_METRICS(bitmap, b2) &&
SAME_METRICS(bitmap, b3) &&
SAME_METRICS(bitmap, b4)) {
break;
}
}
n++;
}
if(n <= 1)
constantMetrics = 0;
table = malloc(sizeof(IndexSubTableRec));
table->firstGlyphIndex = index;
table->lastGlyphIndex = index + n - 1;
table->constantMetrics = constantMetrics;
table->location = 0xDEADFACE;
table->lastLocation = 0xDEADFACE;
table->next = NULL;
if(first == NULL) {
first = table;
last = table;
} else {
last->next = table;
last = table;
}
index += n;
}
return first;
}
int
fontIndex(FontPtr font, int code)
{
StrikePtr strike;
BitmapPtr bitmap;
if(code == 0)
return 0;
strike = font->strikes;
while(strike) {
bitmap = STRIKE_BITMAP(strike, code);
if(bitmap)
return bitmap->index;
strike = strike->next;
}
return -1;
}
CmapPtr
makeCmap(FontPtr font)
{
CmapPtr cmap_head = NULL;
CmapPtr cmap_last = NULL;
CmapPtr cmap;
int code, i, index, maxindex = 0;
code = 0;
while(code < FONT_CODES) {
index = fontIndex(font, code);
if(index < 0) {
code++;
continue;
}
i = 1;
while(code + i < FONT_CODES &&
fontIndex(font, code + i) == index + i) {
i++;
}
cmap = malloc(sizeof(CmapRec));
if(cmap == NULL)
return NULL;
cmap->startCode = code;
cmap->endCode = code + i - 1;
cmap->index = index;
cmap->next = NULL;
cmap->maxindex = 0;
if(maxindex < index + i - 1)
maxindex = index + i - 1;
if(cmap_head == NULL)
cmap_head = cmap;
else
cmap_last->next = cmap;
cmap_last = cmap;
code += i;
}
cmap_head->maxindex = maxindex;
cmap_head->inverse = calloc(maxindex + 1, sizeof(int));
cmap = cmap_head;
while(cmap) {
for(i = cmap->index;
i <= cmap->endCode - cmap->startCode + cmap->index; i++) {
cmap_head->inverse[i] =
i - cmap->index + cmap->startCode;
}
cmap = cmap->next;
}
return cmap_head;
}
int
findIndex(CmapPtr cmap_head, int code)
{
CmapPtr cmap;
cmap = cmap_head;
while(cmap) {
if(cmap->endCode > code)
return -1;
if(cmap->startCode <= code)
return cmap->index + code - cmap->startCode;
cmap = cmap->next;
}
return -1;
}
int
findCode(CmapPtr cmap_head, int index)
{
if(index < 0 || index > cmap_head->maxindex)
return -1;
return cmap_head->inverse[index];
}
int
maxIndex(CmapPtr cmap_head)
{
return cmap_head->maxindex;
}
BitmapPtr
strikeBitmapIndex(StrikePtr strike, CmapPtr cmap, int index)
{
int code = findCode(cmap, index);
if(code < 0)
return NULL;
return STRIKE_BITMAP(strike, code);
}
void
strikeMetrics(StrikePtr strike,
int *width_max_return,
int *x_min_return, int *y_min_return,
int *x_max_return, int *y_max_return)
{
BitmapPtr bitmap;
int i;
int width_max = 0;
int x_min = 10000;
int y_min = 10000;
int x_max = -10000;
int y_max = -10000;
for(i = 0; i < FONT_CODES; i++) {
bitmap = STRIKE_BITMAP(strike, i);
if(!bitmap)
continue;
if(bitmap->advanceWidth > width_max)
width_max = bitmap->advanceWidth;
if(bitmap->horiBearingX < x_min)
x_min = bitmap->horiBearingX;
if(bitmap->horiBearingY > y_max)
y_max = bitmap->horiBearingY;
if(bitmap->horiBearingX + bitmap->width > x_max)
x_max = bitmap->horiBearingX + bitmap->width;
if(bitmap->horiBearingY - bitmap->height < y_min)
y_min = bitmap->horiBearingY - bitmap->height;
}
if(width_max_return) *width_max_return = width_max;
if(x_min_return) *x_min_return = x_min;
if(y_min_return) *y_min_return = y_min;
if(x_max_return) *x_max_return = x_max;
if(y_max_return) *y_max_return = y_max;
}
int
glyphMetrics(FontPtr font, int code,
int *width_return,
int *x_min_return, int *y_min_return,
int *x_max_return, int *y_max_return)
{
StrikePtr strike;
BitmapPtr bitmap;
strike = font->strikes;
while(strike) {
bitmap = STRIKE_BITMAP(strike, code);
if(bitmap) {
if(width_return)
*width_return =
(((float)bitmap->advanceWidth + 0.5) / strike->sizeX) *
TWO_SIXTEENTH;
if(x_min_return)
*x_min_return =
((float)bitmap->horiBearingX / strike->sizeX) *
TWO_SIXTEENTH;
if(y_min_return)
*y_min_return =
(((float)bitmap->horiBearingY - bitmap->height)
/ strike->sizeY) * TWO_SIXTEENTH;
if(x_max_return)
*x_max_return =
(((float)bitmap->horiBearingX + bitmap->width + 0.5)
/ strike->sizeX) * TWO_SIXTEENTH;
if(y_max_return)
*y_max_return =
(((float)bitmap->horiBearingY + 0.5) / strike->sizeY) *
TWO_SIXTEENTH;
return 1;
}
strike = strike->next;
}
return -1;
}
void
fontMetrics(FontPtr font,
int *max_awidth_return,
int *min_x_return, int *min_y_return,
int *max_x_return, int *max_y_return)
{
int i, rc;
int max_awidth = 0;
int min_x = 10000 << 16, min_y = 10000 << 16;
int max_x = -10000 << 16, max_y = -10000 << 16;
for(i = 0; i < FONT_CODES; i++) {
int awidth, x0, y0, x1, y1;
rc = glyphMetrics(font, i, &awidth, &x0, &y0, &x1, &y1);
if(rc < 0)
continue;
if(awidth > max_awidth)
max_awidth = awidth;
if(x0 < min_x) min_x = x0;
if(y0 < min_y) min_y = y0;
if(x1 > max_x) max_x = x1;
if(y1 > max_y) max_y = y1;
}
if(max_awidth_return) *max_awidth_return = max_awidth;
if(min_x_return) *min_x_return = min_x;
if(min_y_return) *min_y_return = min_y;
if(max_x_return) *max_x_return = max_x;
if(max_y_return) *max_y_return = max_y;
}