Replace Windows font utility with native utilities

To generate new fonts, the freetype2 library is required. This
can now be specified by configure in the usual way. If it's missing,
new fonts cannot be generated.
This commit is contained in:
matt335672
2022-08-10 14:54:51 +01:00
parent 70622bf92b
commit ae6a55dbac
14 changed files with 1678 additions and 8 deletions
+34
View File
@@ -0,0 +1,34 @@
EXTRA_DIST = windows
# Some programs need freetype2 to build
if USE_FREETYPE2
MKFV1 = xrdp-mkfv1
else
MKFV1 =
endif
AM_CPPFLAGS = \
-I$(top_builddir) \
-I$(top_srcdir)/common \
$(FREETYPE2_CFLAGS)
bin_PROGRAMS = \
$(MKFV1) \
xrdp-dumpfv1
xrdp_mkfv1_SOURCES = \
mkfv1.c \
fv1.c \
fv1.h
xrdp_mkfv1_LDADD = \
$(top_builddir)/common/libcommon.la \
$(FREETYPE2_LIBS)
xrdp_dumpfv1_SOURCES = \
dumpfv1.c \
fv1.c \
fv1.h
xrdp_dumpfv1_LDADD = \
$(top_builddir)/common/libcommon.la
+413
View File
@@ -0,0 +1,413 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2004-2022
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* fonts
*/
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#include <limits.h>
#include <unistd.h>
#include <ctype.h>
#include "list.h"
#include "os_calls.h"
#include "parse.h"
#include "string_calls.h"
#include "fv1.h"
/**
* What the program is doing
*/
enum program_mode
{
PM_UNSPECIFIED = 0,
PM_INFO,
PM_GLYPH_INFO_TABLE,
PM_SHOW_CHAR
};
/**
* Parsed program arguments
*/
struct program_args
{
const char *font_file;
enum program_mode mode;
int ucode; /* Unicode character to display in 'c' mode */
};
/**************************************************************************//**
* Parses the program args
*
* @param argc Passed to main
* @param @argv Passed to main
* @param pa program_pargs structure for resulting values
* @return !=0 for success
*/
static int
parse_program_args(int argc, char *argv[], struct program_args *pa)
{
int params_ok = 1;
int opt;
pa->font_file = NULL;
pa->mode = PM_UNSPECIFIED;
pa->ucode = 0;
while ((opt = getopt(argc, argv, "c:it")) != -1)
{
switch (opt)
{
case 'i':
if (pa->mode == PM_UNSPECIFIED)
{
pa->mode = PM_INFO;
}
else
{
LOG(LOG_LEVEL_ERROR, "Can't have two modes set");
params_ok = 0;
}
break;
case 't':
if (pa->mode == PM_UNSPECIFIED)
{
pa->mode = PM_GLYPH_INFO_TABLE;
}
else
{
LOG(LOG_LEVEL_ERROR, "Can't have two modes set");
params_ok = 0;
}
break;
case 'c':
if (pa->mode == PM_UNSPECIFIED)
{
pa->mode = PM_SHOW_CHAR;
if (toupper(optarg[0]) == 'U' && optarg[1] == '+')
{
char *hex = g_strdup(optarg);
hex[0] = '0';
hex[1] = 'x';
pa->ucode = g_atoix(hex);
g_free(hex);
}
else if (optarg[0] == '@')
{
pa->ucode = optarg[1];
}
else
{
pa->ucode = g_atoix(optarg);
}
}
else
{
LOG(LOG_LEVEL_ERROR, "Can't have two modes set");
params_ok = 0;
}
break;
default:
LOG(LOG_LEVEL_ERROR, "Unrecognised switch '%c'", (char)opt);
params_ok = 0;
}
}
if (argc <= optind)
{
LOG(LOG_LEVEL_ERROR, "No font file specified");
params_ok = 0;
}
else if ((argc - optind) > 1)
{
LOG(LOG_LEVEL_ERROR, "Unexpected arguments after font file");
params_ok = 0;
}
else
{
pa->font_file = argv[optind];
}
return params_ok;
}
/**************************************************************************//**
* Displays information about a font file
*
* @param fv1 loaded font file
*/
static void
display_font_file_info(const struct fv1_file *fv1)
{
g_printf("Font name : %s\n", fv1->font_name);
g_printf("Point size (%d DPI) : %d\n", FV1_DEVICE_DPI, fv1->point_size);
g_printf("Style : %d\n", fv1->style);
if (fv1->body_height == 0 && fv1->glyphs->count > 0)
{
const struct fv1_glyph *g =
(const struct fv1_glyph *)fv1->glyphs->items[0];
g_printf("Body height : %d (from 1st glyph)\n", -g->baseline + 1);
}
else
{
g_printf("Body height : %d\n", fv1->body_height);
}
g_printf("Descender : %d\n", fv1->min_descender);
if (fv1->glyphs->count == 0)
{
g_printf("\nFile contains no glyphs\n");
}
else
{
g_printf("Min glyph index : U+%04X\n", FV1_MIN_CHAR);
g_printf("Max glyph index : U+%04X\n", FV1_GLYPH_END(fv1) - 1);
/* Work out the statistics */
unsigned short max_width = 0;
int max_width_ucode = 0;
unsigned short max_height = 0;
int max_height_ucode = 0;
short min_baseline = 0;
int min_baseline_ucode = 0;
short min_offset = 0;
int min_offset_ucode = 0;
short max_offset = 0;
int max_offset_ucode = 0;
unsigned short max_inc_by = 0;
int max_inc_by_ucode = 0;
/* Derived quantities */
short min_y_descender = SHRT_MAX;
int min_y_descender_ucode = 0;
int max_datasize = -1;
int max_datasize_ucode = 0;
/* Loop and output macros */
#define SET_MIN(ucode,field,val) \
if ((field) < (val)) \
{ \
val = (field); \
val##_ucode = (ucode); \
}
#define SET_MAX(ucode,field,val) \
if ((field) > (val)) \
{ \
val = (field); \
val##_ucode = (ucode); \
}
#define OUTPUT_INFO(string, val) \
if (val##_ucode > 0) \
{ \
g_printf(string, val, val##_ucode); \
}
int u;
for (u = FV1_MIN_CHAR ; u < FV1_GLYPH_END(fv1); ++u)
{
const struct fv1_glyph *g = FV1_GET_GLYPH(fv1, u);
if (g != NULL)
{
short y_descender = - (g->baseline + g->height);
int datasize = FONT_DATASIZE(g);
SET_MAX(u, g->width, max_width);
SET_MAX(u, g->height, max_height);
SET_MIN(u, g->baseline, min_baseline);
SET_MIN(u, g->offset, min_offset);
SET_MAX(u, g->offset, max_offset);
SET_MAX(u, g->inc_by, max_inc_by);
SET_MIN(u, y_descender, min_y_descender);
SET_MAX(u, datasize, max_datasize);
}
}
OUTPUT_INFO("Max glyph width : %d (U+%04X)\n", max_width);
OUTPUT_INFO("Max glyph height : %d (U+%04X)\n", max_height);
OUTPUT_INFO("Min glyph y-baseline : %d (U+%04X)\n", min_baseline);
OUTPUT_INFO("Min glyph y-descender : %d (U+%04X)\n", min_y_descender);
OUTPUT_INFO("Min glyph x-offset : %d (U+%04X)\n", min_offset);
OUTPUT_INFO("Max glyph x-offset : %d (U+%04X)\n", max_offset);
OUTPUT_INFO("Max glyph x-inc_by : %d (U+%04X)\n", max_inc_by);
OUTPUT_INFO("Max glyph datasize : %d (U+%04X)\n", max_datasize);
#undef SET_MIN
#undef SET_MAX
#undef OUTPUT_INFO
}
}
/**************************************************************************//**
* Display info in a table about all the glyphs
* @param fv1 font file
*/
static void
display_glyph_info_table(const struct fv1_file *fv1)
{
int u;
g_printf("character,width,height,baseline,offset,inc_by,datasize\n");
for (u = FV1_MIN_CHAR; u < FV1_GLYPH_END(fv1); ++u)
{
const struct fv1_glyph *g = FV1_GET_GLYPH(fv1, u);
if (g != NULL)
{
int datasize = FONT_DATASIZE(g);
g_printf("%d,%hu,%hu,%hd,%hd,%hu,%d\n",
u, g->width, g->height, g->baseline,
g->offset, g->inc_by, datasize);
}
}
}
/**************************************************************************//**
* Converts a font data row to a printable string
*
* @param rowdata Pointer to the first byte of the row data
* @param width Number of pixels in the row
* @param out Output buffer. Must be sized by the caller to be at
* least width+1 bytes
*/
static void
row_to_str(const unsigned char *rowdata, int width, char *out)
{
int x;
int mask = 1 << 7;
for (x = 0 ; x < width ; ++x)
{
out[x] = ((*rowdata & mask) != 0) ? 'X' : '.';
mask >>= 1;
if (mask == 0)
{
mask = 1 << 7;
++rowdata;
}
}
out[width] = '\0';
}
/**************************************************************************//**
* Display info about a specific glyph
* @param ucode Unicode character value
* @param g Glyph
*/
static void
display_glyph_info(int ucode, const struct fv1_glyph *g)
{
char *row_buffer = (char *)g_malloc(g->width + 1, 0);
if (row_buffer == NULL)
{
g_printf("<No memory>\n");
}
else
{
g_printf("Glyph : U+%04X\n", ucode);
g_printf(" Width : %d\n", g->width);
g_printf(" Height : %d\n", g->height);
g_printf(" Baseline : %d\n", g->baseline);
g_printf(" Offset : %d\n", g->offset);
g_printf(" Inc By : %d\n", g->inc_by);
g_printf(" Data :\n");
int y;
const unsigned char *dataptr = g->data;
for (y = 0 ; y < g->height; ++y)
{
row_to_str(dataptr, g->width, row_buffer);
g_printf(" %+3d: %s\n", y + g->baseline, row_buffer);
dataptr += (g->width + 7) / 8;
}
g_free(row_buffer);
}
}
/**************************************************************************//**
* Main
*
* @param argc Argument count
* @param argv Arguments
*/
int
main(int argc, char *argv[])
{
struct fv1_file *fv1 = NULL;
struct log_config *logging;
struct program_args pa;
int rv = 1;
logging = log_config_init_for_console(LOG_LEVEL_WARNING,
g_getenv("DUMPFV1_LOG_LEVEL"));
log_start_from_param(logging);
log_config_free(logging);
if (parse_program_args(argc, argv, &pa) &&
(fv1 = fv1_file_load(pa.font_file)) != NULL)
{
switch (pa.mode)
{
case PM_INFO:
display_font_file_info(fv1);
rv = 0;
break;
case PM_GLYPH_INFO_TABLE:
display_glyph_info_table(fv1);
rv = 0;
break;
case PM_SHOW_CHAR:
if (pa.ucode < FV1_MIN_CHAR)
{
LOG(LOG_LEVEL_ERROR, "Value for -c must be at least U+%04X",
FV1_MIN_CHAR);
}
else if (pa.ucode >= FV1_GLYPH_END(fv1))
{
LOG(LOG_LEVEL_ERROR,
"Value for -c must be less than U+%04X",
FV1_GLYPH_END(fv1));
}
else
{
const struct fv1_glyph *g =
(const struct fv1_glyph *)
list_get_item(fv1->glyphs, pa.ucode - FV1_MIN_CHAR);
display_glyph_info(pa.ucode, g);
rv = 0;
}
break;
default:
LOG(LOG_LEVEL_ERROR, "Specify one of '-i' or '-c'");
break;
}
}
fv1_file_free(fv1);
log_end();
return rv;
}
+352
View File
@@ -0,0 +1,352 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2004-2022
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file fontutils/fv1.c
* @brief Definitions relating to fv1 font files
*/
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#include <stdio.h>
#include <stddef.h>
#include "list.h"
#include "os_calls.h"
#include "parse.h"
#include "string_calls.h"
#include "fv1.h"
const static char FV1_SIGNATURE[] = {'F', 'N', 'T', '1'};
/*****************************************************************************/
struct fv1_glyph *
fv1_alloc_glyph(int ucode,
unsigned short width,
unsigned short height)
{
int datasize = FONT_DATASIZE_FROM_GEOMETRY(width, height);
struct fv1_glyph *glyph = NULL;
char ucode_str[16] = {'\0'};
if (ucode < 0)
{
g_snprintf(ucode_str, sizeof(ucode_str), "Glyph");
}
else
{
g_snprintf(ucode_str, sizeof(ucode_str), "Glyph:U+%04X", ucode);
}
if (datasize < 0 || datasize > FV1_MAX_GLYPH_DATASIZE)
{
/* shouldn't happen */
LOG(LOG_LEVEL_ERROR, "%s - datasize %d out of bounds",
ucode_str, datasize);
}
else
{
glyph = (struct fv1_glyph *)
g_malloc( offsetof(struct fv1_glyph, data) + datasize, 1);
if (glyph == NULL)
{
LOG(LOG_LEVEL_ERROR, "%s - out of memory", ucode_str);
}
else
{
glyph->width = width;
glyph->height = height;
}
}
return glyph;
}
/*****************************************************************************/
struct fv1_file *
fv1_file_create(void)
{
struct fv1_file *fv1 = (struct fv1_file *)g_new0(struct fv1_file, 1);
if (fv1 == NULL)
{
LOG(LOG_LEVEL_ERROR, "fv1_file_create - out of memory");
}
else
{
fv1->style = 1; /* Unused at present - compatibility value */
fv1->glyphs = list_create();
fv1->glyphs->auto_free = 1;
}
return fv1;
}
/*****************************************************************************/
static void
add_glyphs_from_stream(struct fv1_file *fv1, struct stream *s)
{
unsigned short width;
unsigned short height;
int datasize;
struct fv1_glyph *glyph;
while (s_check_rem(s, 4))
{
in_sint16_le(s, width);
in_sint16_le(s, height);
datasize = FONT_DATASIZE_FROM_GEOMETRY(width, height);
if (datasize < 0 || datasize > FV1_MAX_GLYPH_DATASIZE)
{
LOG(LOG_LEVEL_ERROR,
"Font:%s Glyph:%d - datasize %d out of bounds",
fv1->font_name, FV1_GLYPH_END(fv1), datasize);
break;
}
if (!s_check_rem(s, 6 + 6 + datasize))
{
LOG(LOG_LEVEL_ERROR,
"Font:%s Glyph:%d - not enough data for glyph",
fv1->font_name, FV1_GLYPH_END(fv1));
break;
}
if ((glyph = fv1_alloc_glyph(FV1_GLYPH_END(fv1), width, height)) == NULL)
{
break;
}
in_sint16_le(s, glyph->baseline);
in_sint16_le(s, glyph->offset);
in_sint16_le(s, glyph->inc_by);
in_uint8s(s, 6);
in_uint8a(s, glyph->data, datasize);
list_add_item(fv1->glyphs, (tintptr)glyph);
}
}
/*****************************************************************************/
struct fv1_file *
fv1_file_load(const char *filename)
{
struct fv1_file *fv1 = NULL;
if (!g_file_exist(filename))
{
LOG(LOG_LEVEL_ERROR, "Can't find font file %s", filename);
}
else
{
int file_size = g_file_get_size(filename);
if (file_size < FV1_MIN_FILE_SIZE || file_size > FV1_MAX_FILE_SIZE)
{
LOG(LOG_LEVEL_ERROR, "Font file %s has bad size %d",
filename, file_size);
}
else
{
struct stream *s;
int fd;
make_stream(s);
init_stream(s, file_size + 1024);
fd = g_file_open(filename);
if (fd < 0)
{
LOG(LOG_LEVEL_ERROR, "Can't open font file %s", filename);
}
else
{
int b = g_file_read(fd, s->data, file_size + 1024);
g_file_close(fd);
if (b < FV1_MIN_FILE_SIZE)
{
LOG(LOG_LEVEL_ERROR, "Font file %s is too small",
filename);
}
else
{
char sig[sizeof(FV1_SIGNATURE)];
s->end = s->data + b;
in_uint8a(s, sig, sizeof(FV1_SIGNATURE));
if (g_memcmp(sig, FV1_SIGNATURE, sizeof(sig)) != 0)
{
LOG(LOG_LEVEL_ERROR,
"Font file %s has wrong signature",
filename);
}
else if ((fv1 = fv1_file_create()) != NULL)
{
in_uint8a(s, fv1->font_name, FV1_MAX_FONT_NAME_SIZE);
fv1->font_name[FV1_MAX_FONT_NAME_SIZE] = '\0';
in_uint16_le(s, fv1->point_size);
in_uint16_le(s, fv1->style);
in_uint16_le(s, fv1->body_height);
in_uint16_le(s, fv1->min_descender);
in_uint8s(s, 4);
add_glyphs_from_stream(fv1, s);
}
}
}
free_stream(s);
}
}
return fv1;
}
/*****************************************************************************/
void
fv1_file_free(struct fv1_file *fv1)
{
if (fv1 != NULL)
{
list_delete(fv1->glyphs);
g_free(fv1);
}
}
/*****************************************************************************/
int
write_stream(int fd, struct stream *s)
{
const char *p = s->data;
int rv = 1;
while (p < s->end)
{
int len = g_file_write(fd, p, s->end - p);
if (len <= 0)
{
rv = 0;
break;
}
p += len;
}
return rv;
}
/*****************************************************************************/
int
fv1_file_save(const struct fv1_file *fv1, const char *filename)
{
int fd;
struct fv1_glyph *blank_glyph; /* Needed for bad characters */
fd = g_file_open_ex(filename, 0, 1, 1, 1);
int rv = 1;
if (fd < 0)
{
LOG(LOG_LEVEL_ERROR, "Unable to open %s for writing [%s]", filename,
g_get_strerror());
}
else
{
struct stream *s;
make_stream(s);
init_stream(s, 1024);
/* Write the header */
out_uint8a(s, FV1_SIGNATURE, sizeof(FV1_SIGNATURE));
int len = g_strlen(fv1->font_name);
if (len > FV1_MAX_FONT_NAME_SIZE)
{
len = FV1_MAX_FONT_NAME_SIZE;
}
out_uint8a(s, fv1->font_name, len);
while (len++ < FV1_MAX_FONT_NAME_SIZE)
{
out_uint8(s, '\0');
}
out_uint16_le(s, fv1->point_size);
out_uint16_le(s, fv1->style);
out_uint16_le(s, fv1->body_height);
out_uint16_le(s, fv1->min_descender);
out_uint8a(s, "\0\0\0\0", 4);
s_mark_end(s);
if (!write_stream(fd, s))
{
LOG(LOG_LEVEL_ERROR, "Unable to write file header [%s]",
g_get_strerror());
}
else if ((blank_glyph = fv1_alloc_glyph(-1, 0, 0)) == NULL)
{
LOG(LOG_LEVEL_ERROR, "Unable to allocate blank glyph");
}
else
{
int u;
for (u = FV1_MIN_CHAR; u < FV1_GLYPH_END(fv1); ++u)
{
const struct fv1_glyph *g = FV1_GET_GLYPH(fv1, u);
int datasize;
if (g == NULL)
{
LOG(LOG_LEVEL_WARNING, "Glyph %d is not set", u);
g = blank_glyph;
}
else
{
datasize = FONT_DATASIZE(g);
if (datasize > FV1_MAX_GLYPH_DATASIZE)
{
LOG(LOG_LEVEL_WARNING,
"glyph %d datasize %d exceeds max of %d"
" - glyph will be blank",
u, datasize, FV1_MAX_GLYPH_DATASIZE);
g = blank_glyph;
}
}
init_stream(s, 16 + FONT_DATASIZE(g));
out_uint16_le(s, g->width);
out_uint16_le(s, g->height);
out_uint16_le(s, g->baseline);
out_uint16_le(s, g->offset);
out_uint16_le(s, g->inc_by);
out_uint8a(s, "\0\0\0\0\0\0", 6);
out_uint8a(s, g->data, FONT_DATASIZE(g));
s_mark_end(s);
if (!write_stream(fd, s))
{
LOG(LOG_LEVEL_ERROR, "Unable to write glyph %d [%s]",
u, g_get_strerror());
break;
}
}
g_free(blank_glyph);
rv = (u == FV1_GLYPH_END(fv1)) ? 0 : 1;
}
free_stream(s);
g_file_close(fd);
}
return rv;
}
+100
View File
@@ -0,0 +1,100 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2004-2022
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file fontutils/fv1.h
* @brief Definitions relating to fv1 font files
*/
#if !defined(FV1_H)
#define FV1_H
struct list;
#define FV1_DEVICE_DPI 96
#define FV1_MIN_CHAR 0x20 /* First character value in file */
#define FV1_MIN_FILE_SIZE 48
#define FV1_MAX_FILE_SIZE (10 * 1024 * 1024)
#define FV1_MAX_FONT_NAME_SIZE 32
#define FV1_MAX_GLYPH_DATASIZE 512
struct fv1_glyph
{
unsigned short width; /* Width of glyph */
unsigned short height; /* Height of glyph */
short baseline; /* Offset from cursor pos to 1st row of glyph */
short offset; /* Space before glyph (can be -ve) */
unsigned short inc_by; /* Total width of glyph + spacing */
/* Standard C++ does not yet support C99 flexible array members */
#ifdef __cplusplus
unsigned char data[1];
#else
unsigned char data[];
#endif
};
struct fv1_file
{
char font_name[FV1_MAX_FONT_NAME_SIZE + 1];
short point_size; /* Input point size (for reference) */
short style;
short body_height; /* Body height (pixels) */
short min_descender; /* Min descender of the glyphs in the font */
struct list *glyphs; /* Glyphs are struct fv1_glyph * */
};
/**
* Get a glyph pointer for a unicode character
*/
#define FV1_GET_GLYPH(fv1,ucode) \
(((ucode) < FV1_MIN_CHAR) \
? NULL \
: (struct fv1_glyph *)list_get_item(fv1->glyphs, (ucode) - FV1_MIN_CHAR))
/**
* First glyph not in file
*/
#define FV1_GLYPH_END(fv1) (fv1->glyphs->count + FV1_MIN_CHAR)
struct fv1_file *
fv1_file_load(const char *filename);
void
fv1_file_free(struct fv1_file *);
struct fv1_file *
fv1_file_create(void);
struct fv1_glyph *
fv1_alloc_glyph(int ucode, /* Unicode character for error reporting if known */
unsigned short width,
unsigned short height);
enum fv1_realloc_mode
{
FV1_AT_TOP,
FV1_AT_BOTTOM
};
int
fv1_file_save(const struct fv1_file *fv1, const char *filename);
#endif
+587
View File
@@ -0,0 +1,587 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2004-2012
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#include <unistd.h>
#include <ctype.h>
#include <ft2build.h>
#include FT_FREETYPE_H
/* See the FT2 documentation - this builds an error table */
#undef FTERRORS_H_
#define FT_ERRORDEF( e, v, s ) { e, s },
#define FT_ERROR_START_LIST {
#define FT_ERROR_END_LIST { 0, NULL } };
static const struct
{
int err_code;
const char *err_msg;
} ft_errors[] =
#include <freetype/fterrors.h>
#if 0
/* These lines fix problems with astyle formatting following the ft_errors
* definition */
}
#endif
#include "arch.h"
#include "defines.h"
#include "log.h"
#include "os_calls.h"
#include "string_calls.h"
#include "fv1.h"
#define DEFAULT_POINT_SIZE 10
#define DEFAULT_MAX_CHAR 0x4dff
/**
* sans10 compatibility choices
*/
enum sans10_compat
{
S10_OFF = 0,
S10_ON,
S10_AUTO
};
/**
* Parsed program arguments
*/
struct program_args
{
const char *input_file;
const char *output_file;
char font_name[FV1_MAX_FONT_NAME_SIZE + 1];
unsigned short point_size;
/** Last character value in file */
unsigned int max_ucode;
/** Are we generating san10 in compatibility mode? */
enum sans10_compat sans10_compatibility;
};
struct x_dimensions
{
unsigned short width;
short offset;
unsigned short inc_by;
};
/**
* Table of some character settings in the original sans-10.fv1 font
*/
static const struct x_dimensions
original_sans10_data[] =
{
/* 0x20 - 0x3f */
{1, 0, 4}, {1, 2, 5}, {3, 1, 5}, {9, 1, 11},
{7, 1, 8}, {11, 0, 12}, {9, 1, 11}, {1, 1, 3},
{3, 1, 5}, {3, 1, 5}, {7, 0, 7}, {9, 1, 11},
{2, 1, 4}, {3, 1, 5}, {1, 2, 4}, {4, 0, 4},
{6, 1, 8}, {5, 2, 8}, {6, 1, 8}, {6, 1, 8},
{6, 1, 8}, {6, 1, 8}, {6, 1, 8}, {6, 1, 8},
{6, 1, 8}, {6, 1, 8}, {1, 2, 4}, {2, 1, 4},
{8, 1, 11}, {8, 1, 11}, {8, 1, 11}, {5, 1, 7},
/* 0x40 - 0x5f */
{11, 1, 13}, {9, 0, 9}, {7, 1, 9}, {7, 1, 9},
{8, 1, 10}, {6, 1, 8}, {5, 1, 7}, {8, 1, 10},
{8, 1, 10}, {1, 1, 3}, {3, -1, 3}, {7, 1, 8},
{6, 1, 7}, {9, 1, 11}, {8, 1, 10}, {8, 1, 10},
{6, 1, 8}, {8, 1, 10}, {7, 1, 8}, {7, 1, 9},
{7, 0, 7}, {8, 1, 10}, {9, 0, 9}, {11, 0, 11},
{8, 0, 8}, {7, 0, 7}, {8, 1, 10}, {3, 1, 5},
{4, 0, 4}, {3, 1, 5}, {8, 1, 11}, {7, 0, 7},
/* 0x60 - 0x7f */
{3, 1, 7}, {6, 1, 8}, {6, 1, 8}, {5, 1, 7},
{6, 1, 8}, {6, 1, 8}, {4, 0, 4}, {6, 1, 8},
{6, 1, 8}, {1, 1, 3}, {2, 0, 3}, {6, 1, 7},
{1, 1, 3}, {11, 1, 13}, {6, 1, 8}, {6, 1, 8},
{6, 1, 8}, {6, 1, 8}, {4, 1, 5}, {5, 1, 7},
{4, 0, 5}, {6, 1, 8}, {7, 0, 7}, {9, 0, 9},
{7, 0, 7}, {7, 0, 7}, {5, 1, 7}, {5, 2, 8},
{1, 2, 4}, {5, 2, 8}, {8, 1, 11}, {7, 1, 8},
/* 0x80 - 0x9f */
{7, 1, 8}, {7, 1, 8}, {7, 1, 8}, {7, 1, 8},
{7, 1, 8}, {7, 1, 8}, {7, 1, 8}, {7, 1, 8},
{7, 1, 8}, {7, 1, 8}, {7, 1, 8}, {7, 1, 8},
{7, 1, 8}, {7, 1, 8}, {7, 1, 8}, {7, 1, 8},
{7, 1, 8}, {7, 1, 8}, {7, 1, 8}, {7, 1, 8},
{7, 1, 8}, {7, 1, 8}, {7, 1, 8}, {7, 1, 8},
{7, 1, 8}, {7, 1, 8}, {7, 1, 8}, {7, 1, 8},
{7, 1, 8}, {7, 1, 8}, {7, 1, 8}, {7, 1, 8},
/* 0xa0 - 0xbf */
{1, 0, 4}, {1, 2, 5}, {6, 1, 8}, {7, 0, 8},
{7, 0, 8}, {7, 1, 8}, {1, 2, 4}, {5, 1, 7},
{3, 2, 7}, {9, 2, 13}, {5, 1, 6}, {6, 1, 8},
{8, 1, 11}, {3, 1, 5}, {9, 2, 13}, {4, 1, 7},
{4, 1, 7}, {9, 1, 11}, {4, 1, 5}, {4, 1, 5},
{3, 2, 7}, {7, 1, 8}, {6, 1, 8}, {1, 1, 4},
{3, 2, 7}, {3, 1, 5}, {5, 1, 6}, {6, 1, 8},
{12, 1, 13}, {11, 1, 13}, {12, 1, 13}, {5, 1, 7},
/* 0xc0 - 0xdf */
{9, 0, 9}, {9, 0, 9}, {9, 0, 9}, {9, 0, 9},
{9, 0, 9}, {9, 0, 9}, {12, 0, 13}, {7, 1, 9},
{6, 1, 8}, {6, 1, 8}, {6, 1, 8}, {6, 1, 8},
{2, 0, 3}, {2, 1, 3}, {5, -1, 3}, {3, 0, 3},
{9, 0, 10}, {8, 1, 10}, {8, 1, 10}, {8, 1, 10},
{8, 1, 10}, {8, 1, 10}, {8, 1, 10}, {7, 2, 11},
{8, 1, 10}, {8, 1, 10}, {8, 1, 10}, {8, 1, 10},
{8, 1, 10}, {7, 0, 7}, {6, 1, 8}, {6, 1, 8},
/* 0xe0 - 0xff */
{6, 1, 8}, {6, 1, 8}, {6, 1, 8}, {6, 1, 8},
{6, 1, 8}, {6, 1, 8}, {11, 1, 13}, {5, 1, 7},
{6, 1, 8}, {6, 1, 8}, {6, 1, 8}, {6, 1, 8},
{3, 0, 3}, {3, 1, 3}, {5, -1, 3}, {3, 0, 3},
{6, 1, 8}, {6, 1, 8}, {6, 1, 8}, {6, 1, 8},
{6, 1, 8}, {6, 1, 8}, {6, 1, 8}, {8, 1, 11},
{6, 1, 8}, {6, 1, 8}, {6, 1, 8}, {6, 1, 8},
{6, 1, 8}, {7, 0, 7}, {6, 1, 8}, {7, 0, 7}
};
/**************************************************************************//**
* Parses a unicode character value
*
* @param str String containing value
* @return Resulting character value
*/
static unsigned int
parse_ucode_name(const char *str)
{
unsigned int rv;
if (toupper(str[0]) == 'U' && str[1] == '+')
{
char *hex = g_strdup(str);
hex[0] = '0';
hex[1] = 'x';
rv = g_atoix(hex);
g_free(hex);
}
else if (str[0] == '@')
{
rv = str[1];
}
else
{
rv = g_atoix(str);
}
return rv;
}
/**************************************************************************//**
* Parses the program args
*
* @param argc Passed to main
* @param @argv Passed to main
* @param pa program_pargs structure for resulting values
* @return !=0 for success
*/
static int
parse_program_args(int argc, char *argv[], struct program_args *pa)
{
int params_ok = 1;
int opt;
pa->input_file = NULL;
pa->output_file = NULL;
pa->font_name[0] = '\0';
pa->point_size = DEFAULT_POINT_SIZE;
pa->max_ucode = DEFAULT_MAX_CHAR;
pa->sans10_compatibility = S10_AUTO;
while ((opt = getopt(argc, argv, "n:p:m:C:")) != -1)
{
switch (opt)
{
case 'n':
g_snprintf(pa->font_name, FV1_MAX_FONT_NAME_SIZE + 1, "%s",
optarg);
break;
case 'p':
pa->point_size = g_atoi(optarg);
break;
case 'm':
pa->max_ucode = parse_ucode_name(optarg);
break;
case 'C':
if (toupper(optarg[0]) == 'A')
{
pa->sans10_compatibility = S10_AUTO;
}
else if (g_text2bool(optarg))
{
pa->sans10_compatibility = S10_ON;
}
else
{
pa->sans10_compatibility = S10_OFF;
}
break;
default:
LOG(LOG_LEVEL_ERROR, "Unrecognised switch '%c'", (char)opt);
params_ok = 0;
}
}
if (pa->max_ucode < FV1_MIN_CHAR)
{
LOG(LOG_LEVEL_ERROR, "-m argument must be at least %d",
FV1_MIN_CHAR);
params_ok = 0;
}
switch (argc - optind)
{
case 0:
LOG(LOG_LEVEL_ERROR, "No input file specified");
params_ok = 0;
break;
case 1:
LOG(LOG_LEVEL_ERROR, "No output file specified");
params_ok = 0;
break;
case 2:
pa->input_file = argv[optind];
pa->output_file = argv[optind + 1];
break;
default:
LOG(LOG_LEVEL_ERROR, "Unexpected arguments after output file");
params_ok = 0;
}
return params_ok;
}
/**************************************************************************//**
* Checks whether the specified glyph row is blank
* @param g Glyph
* @param row Row number between 0 and g->height - 1
* @result Boolean
*/
static int
is_blank_glyph_row(const struct fv1_glyph *g, unsigned int row)
{
if (g->width == 0 || row >= g->height)
{
return 1;
}
const unsigned int glyph_row_size = ((g->width + 7) / 8);
const unsigned char *dataptr = g->data + (row * glyph_row_size);
const unsigned int masks[] =
{ 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
/* Check for set pixels in all the leading bytes */
unsigned int x;
for (x = g->width ; x > 8 ; x -= 8)
{
if (*dataptr++ != 0)
{
return 0;
}
}
/* Use a single test to check the pixels in the last byte */
return ((*dataptr & masks[x - 1]) == 0);
}
/**************************************************************************//**
* Returns a string for a freetype2 error
* @param error Freetype2 error code
* @param buff Pointer to buffer for error string
* @param bufflen Length of above
*/
static void
get_ft_error(FT_Error error, char *buff, unsigned int bufflen)
{
const char *errstr = NULL;
unsigned int i;
for (i = 0 ; i < (sizeof(ft_errors) / sizeof(ft_errors[0])); ++i)
{
if (ft_errors[i].err_code == error)
{
errstr = ft_errors[i].err_msg;
break;
}
}
if (errstr != NULL)
{
g_snprintf(buff, bufflen, "[%s]", errstr);
}
else
{
g_snprintf(buff, bufflen,
"[errorcode %d (no description)]", (int)error);
}
}
/**************************************************************************//**
* Implement sans10 compatibility for a glyph
*
* The original Windows font generator made a few different choices for the
* character x offset than freetype2 does. These are particularly noticeable
* with a small font.
*
* This routine checks the glyph, and implements the original offset size
* for popular English characters, which are all that the user will probably
* be displaying with xrdp v0.9.x
*
* @param g Glyph to check
*/
static void
implement_sans10_compatibility(struct fv1_glyph *g, unsigned int ucode)
{
const unsigned int max_index =
sizeof(original_sans10_data) / sizeof(original_sans10_data[0]);
if (ucode < FV1_MIN_CHAR || ucode >= max_index + FV1_MIN_CHAR)
{
return;
}
const struct x_dimensions *d =
&original_sans10_data[ucode - FV1_MIN_CHAR];
if (g->offset != d->offset)
{
if (g->width != d->width)
{
LOG(LOG_LEVEL_WARNING,
"Can't set compatibility offset for U+%04X: width %d != %d",
ucode, g->width, d->width);
}
else if (g->inc_by != d->inc_by)
{
LOG(LOG_LEVEL_WARNING,
"Can't set compatibility offset for U+%04X: inc_by %d != %d",
ucode, g->inc_by, d->inc_by);
}
else
{
LOG(LOG_LEVEL_INFO,
"Changing compatibility offset for U+%04X: from %d to %d",
ucode, g->offset, d->offset);
}
g->offset = d->offset;
}
}
/**************************************************************************//**
* Converts a freetype 2 bitmap to a fv1 glyph
* @param ft_glyph Freetype2 glyph. Must be a monochrome bitmap
* @param ucode Unicode character for error reporting
* @param pa Program args
* @return fv1 glyph, or NULL for error
*/
static struct fv1_glyph *
convert_mono_glyph(FT_GlyphSlot ft_glyph, unsigned int ucode,
const struct program_args *pa)
{
short width = ft_glyph->bitmap.width;
short height = ft_glyph->bitmap.rows;
struct fv1_glyph *g;
/* Number of bytes in a glyph row */
const unsigned int glyph_row_size = ((width + 7) / 8);
if ((g = fv1_alloc_glyph(ucode, width, height)) != NULL)
{
g->baseline = -(ft_glyph->metrics.horiBearingY / 64);
g->offset = ft_glyph->metrics.horiBearingX / 64;
g->inc_by = ft_glyph->metrics.horiAdvance / 64;
if (FONT_DATASIZE(g) > 0)
{
const unsigned char *srcptr = ft_glyph->bitmap.buffer;
unsigned char *dstptr = g->data;
unsigned int y;
for (y = 0; y < g->height; ++y)
{
g_memcpy(dstptr, srcptr, glyph_row_size);
dstptr += glyph_row_size;
srcptr += ft_glyph->bitmap.pitch;
}
/* Optimise the glyph by removing any blank lines at the bottom
* and top */
if (g->width > 0)
{
while (g->height > 0 &&
is_blank_glyph_row(g, g->height - 1))
{
--g->height;
}
y = 0;
while (y < g->height && is_blank_glyph_row(g, y))
{
++y;
}
if (y > 0)
{
g->baseline += y;
g->height -= y;
g_memmove(g->data, g->data + (y * glyph_row_size),
g->height * glyph_row_size);
}
}
}
}
if (pa->sans10_compatibility != S10_OFF)
{
implement_sans10_compatibility(g, ucode);
}
return g;
}
/**************************************************************************//**
* Main
*
* @param argc Argument count
* @param argv Arguments
*/
int
main(int argc, char *argv[])
{
FT_Library library = NULL; /* handle to library */
FT_Face face = NULL; /* handle to face object */
FT_Error error;
struct fv1_glyph *g;
struct program_args pa;
struct log_config *logging;
int rv = 1;
logging = log_config_init_for_console(LOG_LEVEL_WARNING,
g_getenv("MKFV1_LOG_LEVEL"));
log_start_from_param(logging);
log_config_free(logging);
struct fv1_file *fv1 = fv1_file_create();
if (fv1 == NULL)
{
LOG(LOG_LEVEL_ERROR, "Memory allocation failure");
}
else if (parse_program_args(argc, argv, &pa))
{
char errstr[128];
if ((error = FT_Init_FreeType(&library)) != 0)
{
get_ft_error(error, errstr, sizeof(errstr));
LOG(LOG_LEVEL_ERROR, "Error initializing freetype library %s",
errstr);
}
else if ((error = FT_New_Face(library, pa.input_file, 0, &face)) != 0)
{
get_ft_error(error, errstr, sizeof(errstr));
LOG(LOG_LEVEL_ERROR, "Error loading font file %s %s",
pa.input_file, errstr);
}
else if ((error = FT_Set_Char_Size(face, 0,
pa.point_size * 64,
FV1_DEVICE_DPI, 0)) != 0)
{
get_ft_error(error, errstr, sizeof(errstr));
LOG(LOG_LEVEL_ERROR, "Error setting point size to %u %s",
pa.point_size, errstr);
}
else
{
const char *fname =
(pa.font_name[0] != '\0') ? pa.font_name :
(face->family_name != NULL) ? face->family_name :
/* Default */ "";
g_snprintf(fv1->font_name, FV1_MAX_FONT_NAME_SIZE + 1, "%s", fname);
fv1->point_size = pa.point_size;
fv1->body_height = face->size->metrics.height / 64;
fv1->min_descender = face->size->metrics.descender / 64;
if (pa.sans10_compatibility == S10_AUTO)
{
if (g_strcmp(fv1->font_name, "DejaVu Sans") == 0 &&
fv1->point_size == 10)
{
pa.sans10_compatibility = S10_ON;
}
else
{
pa.sans10_compatibility = S10_OFF;
}
}
unsigned int u;
for (u = FV1_MIN_CHAR; u <= pa.max_ucode; ++u)
{
/* retrieve glyph index from character code */
FT_UInt glyph_index = FT_Get_Char_Index(face, u);
/* load glyph image into the slot (erase previous one) */
error = FT_Load_Glyph(face, glyph_index,
FT_LOAD_RENDER | FT_LOAD_TARGET_MONO);
if (error)
{
get_ft_error(error, errstr, sizeof(errstr));
LOG(LOG_LEVEL_WARNING,
"Unable to get bitmap for U+%04X %s", u, errstr);
g = NULL;
}
else if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP ||
face->glyph->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
{
LOG(LOG_LEVEL_WARNING,
"Internal error; U+%04X was not loaded as a bitmap",
u);
g = NULL;
}
else
{
g = convert_mono_glyph(face->glyph, u, &pa);
}
list_add_item(fv1->glyphs, (tintptr)g);
}
rv = fv1_file_save(fv1, pa.output_file);
}
}
FT_Done_FreeType(library);
fv1_file_free(fv1);
log_end();
return rv;
}
+1
View File
@@ -0,0 +1 @@
!Makefile
+17
View File
@@ -0,0 +1,17 @@
OBJS = fontdump.obj os_calls.obj
#CFLAGS = -O2 -I../common
CFLAGS = -O2 -I../common -DUNICODE -D_UNICODE
LDFLAGS = -W -efontdump.exe
all: fontdump1
fontdump1: $(OBJS)
$(CC) $(LDFLAGS) $(OBJS)
clean:
del $(OBJS) fontdump.exe *.tds
os_calls.obj: ../common/os_calls.c
$(CC) $(CFLAGS) -c ../common/os_calls.c
+538
View File
@@ -0,0 +1,538 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2004-2012
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <windows.h>
#include <tchar.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "os_calls.h"
#include "arch.h"
static HINSTANCE g_instance = 0;
static HWND g_wnd = 0;
static HWND g_lb = 0;
static HWND g_exit_button = 0;
static HWND g_go_button = 0;
static HWND g_font_list = 0;
static char g_font_name[512] = "";
static int g_font_size = 10;
static HFONT g_font = 0;
static int g_running = 0;
#define FONT_DATASIZE(_w, _h) (((_h * ((_w + 7) / 8)) + 3) & ~3)
/*****************************************************************************/
int
check_messages(void)
{
MSG msg;
while (PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE))
{
GetMessage(&msg, NULL, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
/*****************************************************************************/
static int
msg(char *msg1, ...)
{
va_list ap;
char text1[512];
va_start(ap, msg1);
vsnprintf(text1, 511, msg1, ap);
SendMessageA(g_lb, LB_ADDSTRING, 0, (LPARAM)text1);
va_end(ap);
return 0;
}
/*****************************************************************************/
static int
show_last_error(void)
{
LPVOID lpMsgBuf = NULL;
DWORD len;
len = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&lpMsgBuf, 0, NULL);
if (len > 0)
{
msg("GetLastError - %s", lpMsgBuf);
LocalFree(lpMsgBuf);
}
return 0;
}
/*****************************************************************************/
static int
font_dump(void)
{
HDC dc;
HDC dc1;
RECT rect;
HBRUSH brush;
HGDIOBJ saved;
HBITMAP bitmap;
BITMAPINFO bi;
char *bits;
ABC abc;
SIZE sz;
char filename[256];
TCHAR text[256];
char zero1;
char *bmtext;
int bmtextindex;
int fd;
int x1;
int strlen1;
int index1;
int index2;
int len;
int pixel;
int red;
int green;
int blue;
int width;
int height;
int roller;
int outlen;
tui8 b1;
short x2;
if (g_running)
{
return 0;
}
g_running = 1;
msg("starting");
g_font_name[0] = 0;
SendMessageA(g_font_list, WM_GETTEXT, 255, (LPARAM)g_font_name);
if (g_strlen(g_font_name) == 0)
{
msg("error font not set");
g_running = 0;
return 1;
}
dc = GetDC(g_wnd);
height = -MulDiv(g_font_size, GetDeviceCaps(dc, LOGPIXELSY), 72);
g_font = CreateFontA(height, 0, 0, 0, FW_DONTCARE, 0, 0, 0, 0, 0, 0,
0, 0, g_font_name);
ReleaseDC(g_wnd, dc);
if (g_font == 0)
{
msg("error - Font creation failed");
}
zero1 = 0;
g_snprintf(filename, 255, "%s-%d.fv1", g_font_name, g_font_size);
msg("creating file %s", filename);
g_file_delete(filename);
fd = g_file_open(filename);
g_file_write(fd, "FNT1", 4);
strlen1 = g_strlen(g_font_name);
g_file_write(fd, g_font_name, strlen1);
x1 = strlen1;
while (x1 < 32)
{
g_file_write(fd, &zero1, 1);
x1++;
}
x2 = g_font_size; /* font size */
g_file_write(fd, (char *)&x2, 2);
x2 = 1; /* style */
g_file_write(fd, (char *)&x2, 2);
/* pad */
index1 = 0;
while (index1 < 8)
{
g_file_write(fd, &zero1, 1);
index1++;
}
for (x1 = 32; x1 < 0x4e00; x1++)
{
check_messages();
dc = GetWindowDC(g_wnd);
saved = SelectObject(dc, g_font);
if (!GetCharABCWidths(dc, x1, x1, &abc))
{
show_last_error();
}
text[0] = (TCHAR)x1;
text[1] = 0;
if (!GetTextExtentPoint32(dc, text, 1, &sz))
{
show_last_error();
}
SelectObject(dc, saved);
ReleaseDC(g_wnd, dc);
if ((sz.cx > 0) && (sz.cy > 0))
{
dc = GetWindowDC(g_wnd);
saved = SelectObject(dc, g_font);
SetBkColor(dc, RGB(255, 255, 255));
if (!ExtTextOut(dc, 50, 50, ETO_OPAQUE, 0, text, 1, 0))
{
show_last_error();
}
SelectObject(dc, saved);
ReleaseDC(g_wnd, dc);
Sleep(10);
/* width */
x2 = abc.abcB;
g_file_write(fd, (char *)&x2, 2);
/* height */
x2 = sz.cy;
g_file_write(fd, (char *)&x2, 2);
/* baseline */
x2 = -sz.cy;
g_file_write(fd, (char *)&x2, 2);
/* offset */
x2 = abc.abcA;
g_file_write(fd, (char *)&x2, 2);
/* incby */
x2 = sz.cx;
g_file_write(fd, (char *)&x2, 2);
/* pad */
index1 = 0;
while (index1 < 6)
{
g_file_write(fd, &zero1, 1);
index1++;
}
dc = GetWindowDC(g_wnd);
rect.left = 50 + abc.abcA;
rect.top = 50;
rect.right = rect.left + abc.abcB;
rect.bottom = rect.top + sz.cy;
memset(&bi, 0, sizeof(bi));
width = (abc.abcB + 7) & (~7);
height = sz.cy;
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = width;
bi.bmiHeader.biHeight = height;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
bitmap = CreateDIBSection(dc, &bi, DIB_RGB_COLORS, (void *)&bits, 0, 0);
if (bitmap == 0)
{
msg("error - CreateDIBSection failed");
}
else
{
memset(bits, 0, width * height * 4);
dc1 = CreateCompatibleDC(dc);
SelectObject(dc1, bitmap);
if (!BitBlt(dc1, 0, 0, width, height, dc, rect.left, rect.top, SRCCOPY))
{
show_last_error();
}
bmtext = (char *)g_malloc(width * height + 16, 1);
bmtextindex = 0;
for (index1 = (height - 1); index1 >= 0; index1--)
{
for (index2 = 0; index2 < width; index2++)
{
pixel = ((int *)bits)[index1 * width + index2];
red = (pixel >> 16) & 0xff;
green = (pixel >> 8) & 0xff;
blue = (pixel >> 0) & 0xff;
if (red == 0 && green == 0 && blue == 0)
{
bmtext[bmtextindex] = '1';
bmtextindex++;
}
else
{
bmtext[bmtextindex] = '0';
bmtextindex++;
}
}
}
outlen = 0;
b1 = 0;
roller = 0;
len = g_strlen(bmtext);
for (index2 = 0; index2 < len; index2++)
{
if (bmtext[index2] == '1')
{
switch (roller)
{
case 0:
b1 = b1 | 0x80;
break;
case 1:
b1 = b1 | 0x40;
break;
case 2:
b1 = b1 | 0x20;
break;
case 3:
b1 = b1 | 0x10;
break;
case 4:
b1 = b1 | 0x08;
break;
case 5:
b1 = b1 | 0x04;
break;
case 6:
b1 = b1 | 0x02;
break;
case 7:
b1 = b1 | 0x01;
break;
}
}
roller++;
if (roller == 8)
{
roller = 0;
g_file_write(fd, &b1, 1);
outlen++;
b1 = 0;
}
}
while ((outlen % 4) != 0)
{
g_file_write(fd, &zero1, 1);
outlen++;
}
free(bmtext);
DeleteDC(dc1);
DeleteObject(bitmap);
}
if (sz.cx != (long)(abc.abcA + abc.abcB + abc.abcC))
{
msg("error - width not right 1");
}
brush = CreateSolidBrush(RGB(255, 255, 255));
FillRect(dc, &rect, brush);
DeleteObject(brush);
ReleaseDC(g_wnd, dc);
}
else
{
/* write out a blank glyph here */
/* width */
x2 = 1;
g_file_write(fd, (char *)&x2, 2);
/* height */
x2 = 1;
g_file_write(fd, (char *)&x2, 2);
/* baseline */
x2 = 0;
g_file_write(fd, (char *)&x2, 2);
/* offset */
x2 = 0;
g_file_write(fd, (char *)&x2, 2);
/* incby */
x2 = 1;
g_file_write(fd, (char *)&x2, 2);
/* pad */
index1 = 0;
while (index1 < 6)
{
g_file_write(fd, &zero1, 1);
index1++;
}
/* blank bitmap */
index1 = 0;
while (index1 < 4)
{
g_file_write(fd, &zero1, 1);
index1++;
}
}
}
g_file_close(fd);
msg("done");
g_running = 0;
return 0;
}
/*****************************************************************************/
static LRESULT CALLBACK
wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HBRUSH brush;
RECT rect;
switch (message)
{
case WM_PAINT:
BeginPaint(hWnd, &ps);
brush = CreateSolidBrush(RGB(255, 255, 255));
rect = ps.rcPaint;
FillRect(ps.hdc, &rect, brush);
DeleteObject(brush);
EndPaint(hWnd, &ps);
break;
case WM_CLOSE:
DestroyWindow(g_wnd);
g_wnd = 0;
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_TIMER:
KillTimer(g_wnd, 1);
font_dump();
break;
case WM_COMMAND:
if ((HWND)lParam == g_exit_button)
{
PostMessage(g_wnd, WM_CLOSE, 0, 0);
}
else if ((HWND)lParam == g_go_button)
{
while (SendMessage(g_lb, LB_GETCOUNT, 0, 0) > 0)
{
SendMessage(g_lb, LB_DELETESTRING, 0, 0);
}
SetTimer(g_wnd, 1, 1000, 0);
}
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
/*****************************************************************************/
static int
create_window(void)
{
WNDCLASS wc;
DWORD style;
HDC dc;
int height;
int left;
int top;
ZeroMemory(&wc, sizeof(wc));
wc.lpfnWndProc = wnd_proc; /* points to window procedure */
/* name of window class */
wc.lpszClassName = _T("fontdump");
wc.hCursor = LoadCursor(0, IDC_ARROW);
/* Register the window class. */
if (!RegisterClass(&wc))
{
return 0; /* Failed to register window class */
}
style = WS_OVERLAPPED | WS_CAPTION | WS_POPUP | WS_MINIMIZEBOX |
WS_SYSMENU | WS_SIZEBOX | WS_MAXIMIZEBOX;
left = GetSystemMetrics(SM_CXSCREEN) / 2 - 640 / 2;
top = GetSystemMetrics(SM_CYSCREEN) / 2 - 480 / 2;
g_wnd = CreateWindow(wc.lpszClassName, _T("fontdump"),
style, left, top, 640, 480,
(HWND) NULL, (HMENU) NULL, g_instance,
(LPVOID) NULL);
style = WS_CHILD | WS_VISIBLE | WS_BORDER;
g_lb = CreateWindow(_T("LISTBOX"), _T("LISTBOX1"), style,
200, 10, 400, 400, g_wnd, 0, g_instance, 0);
style = WS_CHILD | WS_VISIBLE;
g_exit_button = CreateWindow(_T("BUTTON"), _T("Exit"), style,
540, 410, 75, 25, g_wnd, 0, g_instance, 0);
g_go_button = CreateWindow(_T("BUTTON"), _T("Go"), style,
440, 410, 75, 25, g_wnd, 0, g_instance, 0);
style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN;
g_font_list = CreateWindow(_T("COMBOBOX"), _T("COMBOBOX1"), style,
50, 250, 125, 125, g_wnd, 0, g_instance, 0);
ShowWindow(g_wnd, SW_SHOWNORMAL);
PostMessage(g_wnd, WM_SETFONT, (WPARAM)g_font, 0);
SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"Tahoma");
SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"DejaVu Serif");
SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"DejaVu Sans");
SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"Arial");
SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"Comic Sans MS");
return 0;
}
/*****************************************************************************/
static int
main_loop(void)
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)(msg.wParam);
}
/*****************************************************************************/
int WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
g_instance = hInstance;
create_window();
return main_loop();
}