aseprite/src/gui/jfont.cpp

1003 lines
23 KiB
C++

// ASE gui library
// Copyright (C) 2001-2010 David Capello
//
// This source file is ditributed under a BSD-like license, please
// read LICENSE.txt for more information.
/* Based on code of AllegroFont, Copyright (c) 2001, 2002 Javier Gonzalez */
#include "config.h"
#include <allegro.h>
#include <allegro/internal/aintern.h>
#include <stdlib.h>
#include <string.h>
#include "gui/jfont.h"
#include "gui/jintern.h"
#include "gui/jtheme.h"
FONT* ji_font_load(const char* filepathname)
{
FONT* f = ji_font_load_bmp(filepathname);
if (!f)
f = ji_font_load_ttf(filepathname);
return f;
}
FONT* ji_font_load_bmp(const char* filepathname)
{
int old_color_conv = _color_conv;
FONT* f = NULL;
PALETTE junk;
BITMAP *bmp;
set_color_conversion(COLORCONV_NONE);
bmp = load_bitmap(filepathname, junk);
set_color_conversion(old_color_conv);
if (bmp) {
bmp = ji_apply_guiscale(bmp);
f = _ji_bitmap2font(bmp);
destroy_bitmap(bmp);
}
return f;
}
/**********************************************************************/
#if 1 /* with FreeType */
/**********************************************************************/
#include "ft2build.h"
#include FT_FREETYPE_H
#include FT_GLYPH_H
typedef struct CACHED_GLYPH {
bool is_cached : 1;
bool mono_available : 1;
bool aa_available : 1;
int width, height, aawidth, aaheight;
int left, top, aaleft, aatop;
int advancex, advancey;
unsigned char* bmp;
unsigned char* aabmp;
} CACHED_GLYPH;
typedef struct FONT_AA_DATA {
int aa_mode;
FT_Face face; /* face */
int face_h; /* face height */
int real_face_h; /* real face height */
int face_ascender; /* face ascender */
char* data; /* if loaded from memory, the data chunk */
int data_size; /* and its size */
int ch_spacing; /* extra spacing */
int num_fixed_sizes; /* -1 if scalable, >=0 if fixed */
CACHED_GLYPH* cached_glyphs; /* array to know which glyphs have been cached */
int* fixed_sizes; /* array with the fixed sizes */
} FONT_AA_DATA;
static FT_Library ft_library;
static bool ji_font_inited = false;
extern FONT_VTABLE _ji_font_vtable_aa;
extern FONT_VTABLE* ji_font_vtable_aa;
/* helpers */
static void _font_reget_fixed_sizes(FONT* f)
{
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
if (af->num_fixed_sizes < 0) {
/* scalable font */
af->fixed_sizes[0] = -1;
}
else {
/* fixed */
int i;
for (i=0; i<af->num_fixed_sizes; i++)
af->fixed_sizes[i] = af->face->available_sizes[i].height;
/* set last one to -1 */
af->fixed_sizes[af->num_fixed_sizes] = -1;
}
}
static void _font_uncache_glyphs(FONT* f)
{
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
if (af->cached_glyphs) {
int i;
for (i=0; i<af->face->num_glyphs; i++) {
if (af->cached_glyphs[i].is_cached) {
af->cached_glyphs[i].is_cached = false;
if (af->cached_glyphs[i].bmp) {
jfree(af->cached_glyphs[i].bmp);
af->cached_glyphs[i].bmp = NULL;
}
if (af->cached_glyphs[i].aabmp) {
jfree(af->cached_glyphs[i].aabmp);
af->cached_glyphs[i].aabmp = NULL;
}
}
}
}
}
static void _font_delete_glyphs(FONT* f)
{
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
_font_uncache_glyphs(f);
if (af->cached_glyphs) {
jfree(af->cached_glyphs);
af->cached_glyphs = NULL;
}
}
static void _font_cache_glyph(AL_CONST FONT* f, int glyph_number)
{
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
/* if glyph not cached yet */
if (!af->cached_glyphs[glyph_number].is_cached) {
FT_Glyph new_glyph;
/* load the font glyph */
FT_Load_Glyph(af->face, glyph_number, FT_LOAD_DEFAULT);
FT_Get_Glyph(af->face->glyph, &new_glyph);
/* ok, this glyph is now cached */
af->cached_glyphs[glyph_number].is_cached = true;
af->cached_glyphs[glyph_number].mono_available = false;
af->cached_glyphs[glyph_number].aa_available = false;
/* render the mono bmp */
{
FT_Bitmap *ft_bmp;
FT_Glyph glyph;
FT_BitmapGlyph bmp_glyph;
FT_Glyph_Copy(new_glyph, &glyph);
/* only render glyph if it is not already a bitmap */
if (glyph->format != ft_glyph_format_bitmap)
FT_Glyph_To_Bitmap(&glyph, ft_render_mode_mono, NULL, 1);
/* the FT rendered bitmap */
bmp_glyph = (FT_BitmapGlyph)glyph;
ft_bmp = &bmp_glyph->bitmap;
/* save only if the bitmap is really 1 bit */
if (ft_bmp->pixel_mode == ft_pixel_mode_mono) {
af->cached_glyphs[glyph_number].mono_available = true;
/* set width, height, left, top */
af->cached_glyphs[glyph_number].width = ft_bmp->width;
af->cached_glyphs[glyph_number].height = ft_bmp->rows;
af->cached_glyphs[glyph_number].left = bmp_glyph->left;
af->cached_glyphs[glyph_number].top = bmp_glyph->top;
/* allocate bitmap */
af->cached_glyphs[glyph_number].bmp =
jnew(unsigned char, ft_bmp->width * ft_bmp->rows);
/* monochrome drawing */
{
unsigned char *outbmp_p = af->cached_glyphs[glyph_number].bmp;
unsigned char *bmp_p;
int bmp_x, bmp_y, bit;
/* copy the FT character bitmap to ours */
bmp_p = ft_bmp->buffer;
for (bmp_y = 0; bmp_y < ft_bmp->rows; bmp_y++) {
unsigned char *next_bmp_p;
next_bmp_p = bmp_p + ft_bmp->pitch;
bit = 7;
for (bmp_x = 0; bmp_x < ft_bmp->width; bmp_x++) {
*outbmp_p = *bmp_p & (1 << bit);
outbmp_p++;
if (bit == 0) {
bit = 7;
bmp_p++;
}
else
bit--;
}
bmp_p = next_bmp_p;
}
}
}
FT_Done_Glyph(glyph);
}
/* render the aa bmp */
{
FT_Bitmap *ft_bmp;
FT_Glyph glyph;
FT_BitmapGlyph bmp_glyph;
FT_Glyph_Copy(new_glyph, &glyph);
/* only render glyph if it is not already a bitmap */
if (glyph->format != ft_glyph_format_bitmap)
FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, NULL, 1);
/* the FT rendered bitmap */
bmp_glyph = (FT_BitmapGlyph)glyph;
ft_bmp = &bmp_glyph->bitmap;
/* save only if the bitmap is really 8 bit */
if (ft_bmp->pixel_mode == ft_pixel_mode_grays) {
af->cached_glyphs[glyph_number].aa_available = true;
/* set width, height, left, top */
af->cached_glyphs[glyph_number].aawidth = ft_bmp->width;
af->cached_glyphs[glyph_number].aaheight = ft_bmp->rows;
af->cached_glyphs[glyph_number].aaleft = bmp_glyph->left;
af->cached_glyphs[glyph_number].aatop = bmp_glyph->top;
/* allocate bitmap */
af->cached_glyphs[glyph_number].aabmp =
jnew(unsigned char, ft_bmp->width * ft_bmp->rows);
/* aa drawing */
{
unsigned char *outbmp_p = af->cached_glyphs[glyph_number].aabmp;
unsigned char *bmp_p;
int bmp_y;
unsigned char mul = 256 / ft_bmp->num_grays;
/* we set it to 0 because it is faster to test for false */
if (mul == 1)
mul = 0;
/* copy the FT character bitmap to ours */
bmp_p = ft_bmp->buffer;
for (bmp_y = 0; bmp_y < ft_bmp->rows; bmp_y++) {
unsigned char *next_bmp_p;
next_bmp_p = bmp_p + ft_bmp->pitch;
memcpy(outbmp_p, bmp_p, ft_bmp->width * sizeof(unsigned char));
/* we have to change our pixels if the numgrays is not 256 */
if (mul) {
unsigned char *p = outbmp_p;
unsigned char *p_end = p + ft_bmp->width;
for (; p < p_end; p++)
*p *= mul;
}
outbmp_p += ft_bmp->width;
bmp_p = next_bmp_p;
}
}
}
FT_Done_Glyph(glyph);
}
af->cached_glyphs[glyph_number].advancex = af->face->glyph->advance.x >> 6;
af->cached_glyphs[glyph_number].advancey = af->face->glyph->advance.y >> 6;
/* delete the glyph */
FT_Done_Glyph(new_glyph);
}
}
static void _font_new_cache_glyph(FONT* f)
{
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
int i;
if (!af->cached_glyphs)
af->cached_glyphs = jnew(struct CACHED_GLYPH, af->face->num_glyphs);
for (i=0; i<af->face->num_glyphs; i++) {
af->cached_glyphs[i].is_cached = false;
af->cached_glyphs[i].bmp = NULL;
af->cached_glyphs[i].aabmp = 0;
}
}
/* API */
int _ji_font_init()
{
if (!ji_font_inited) {
if (FT_Init_FreeType (&ft_library))
return -1;
ji_font_inited = true;
}
return 0;
}
void _ji_font_exit()
{
if (ji_font_inited) {
FT_Done_FreeType(ft_library);
ji_font_inited = false;
}
}
FONT* ji_font_load_ttf(const char *filepathname)
{
FONT_AA_DATA* af;
int error;
FONT* f;
/* try to allocate the memory */
f = (FONT*)jmalloc(sizeof(FONT));
if (!f)
return NULL;
f->data = af = (FONT_AA_DATA*)jmalloc0(sizeof(FONT_AA_DATA));
if (!f->data) {
jfree(f);
return NULL;
}
f->height = 0;
f->vtable = ji_font_vtable_aa;
/* clear the struct */
af->cached_glyphs = NULL;
/* we are loading from file, no mem buffer needed */
af->data = NULL;
af->data_size = 0;
/* load the font */
error = FT_New_Face(ft_library, filepathname, 0, &af->face);
if (error) {
jfree(af);
jfree(f);
return NULL;
}
/* get if the font contains only fixed sizes */
if (!(af->face->face_flags & FT_FACE_FLAG_SCALABLE))
af->num_fixed_sizes = af->face->num_fixed_sizes;
else
af->num_fixed_sizes = -1;
_font_new_cache_glyph(f);
if (af->num_fixed_sizes < 0) {
af->fixed_sizes = (int*)jmalloc(sizeof(int));
_font_reget_fixed_sizes(f);
ji_font_set_size(f, 8);
}
else {
af->fixed_sizes = jnew(int, af->num_fixed_sizes + 1);
_font_reget_fixed_sizes(f);
/* set as current size the first found fixed size */
ji_font_set_size(f, af->fixed_sizes[0]);
}
ji_font_set_char_extra_spacing(f, 0);
return f;
}
int ji_font_get_size(FONT* f)
{
if (f->vtable == ji_font_vtable_aa) {
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
return af->face_h;
}
else
return text_height(f);
}
int ji_font_set_size(FONT* f, int h)
{
int error, test_h, direction;
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
if (f->vtable != ji_font_vtable_aa)
return -1;
/* check the font doesn't already use that w and h */
if (h == af->face_h)
return 0;
else if (h <= 0)
return -1;
/* keep changing the size until the real size is not the one */
/* we want */
test_h = h;
direction = 0;
while (1) {
int real_height;
error = FT_Set_Pixel_Sizes(af->face, 0, test_h);
if (error)
break;
/* compare real height with asked height */
real_height = abs(af->face->size->metrics.ascender >> 6)
+ abs(af->face->size->metrics.descender >> 6);
if (real_height == h) {
/* we found the wanted height */
break;
}
/* check the direction */
if (direction == 0) {
/* direction still not set */
if (real_height > h)
direction = -1;
else
direction = 1;
}
/* check we didn't overpass it */
else if ((direction > 0) && (real_height > h)) {
/* decrease one and found */
test_h--;
FT_Set_Pixel_Sizes(af->face, 0, test_h);
break;
}
/* check we didn't surpass it */
else if ((direction < 0) && (real_height < h)) {
break;
}
test_h += direction;
/* check we arent at 0 */
if (test_h <= 0) {
error = true;
break;
}
}
if (!error) {
_font_uncache_glyphs(f);
af->face_h = h;
af->real_face_h = test_h;
af->face_ascender = af->face->size->metrics.ascender >> 6;
return 0;
}
else {
FT_Set_Pixel_Sizes(af->face, 0, af->real_face_h);
return -1;
}
}
int ji_font_get_aa_mode(struct FONT* f)
{
if (f->vtable == ji_font_vtable_aa) {
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
return af->aa_mode;
}
else
return -1;
}
int ji_font_set_aa_mode(struct FONT* f, int mode)
{
if (f->vtable == ji_font_vtable_aa) {
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
int old_mode = af->aa_mode;
af->aa_mode = mode;
return old_mode;
}
else
return -1;
}
bool ji_font_is_fixed(FONT* f)
{
if (f->vtable == ji_font_vtable_aa) {
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
if (af->num_fixed_sizes < 0)
return false;
else
return true;
}
else
return true;
}
bool ji_font_is_scalable(FONT* f)
{
if (f->vtable == ji_font_vtable_aa) {
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
if (af->num_fixed_sizes < 0)
return true;
else
return false;
}
else
return false;
}
const int *ji_font_get_available_fixed_sizes(FONT* f, int *n)
{
if (f->vtable == ji_font_vtable_aa) {
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
/* we reget them just to make sure the contents where not changed */
_font_reget_fixed_sizes(f);
if (n)
*n = af->num_fixed_sizes;
return af->fixed_sizes;
}
else
return NULL; /* TODO return text_height(...) size */
}
int ji_font_get_char_extra_spacing(FONT* f)
{
if (f->vtable == ji_font_vtable_aa) {
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
return af->ch_spacing;
}
else
return 0;
}
void ji_font_set_char_extra_spacing(FONT* f, int spacing)
{
if (f->vtable == ji_font_vtable_aa) {
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
af->ch_spacing = MID(0, spacing, 4096);
}
}
int ji_font_char_len(FONT* f, int chr)
{
return f->vtable->char_length(f, chr);
}
// see jdraw_text
int ji_font_text_len(struct FONT* f, const char *s)
{
int in_pos = 0;
int pix_len = 0;
int c;
while ((c = ugetc(s+in_pos)) != 0) {
if (c == '&') {
in_pos += uwidth(s+in_pos);
c = ugetc(s+in_pos);
if (c == '&') {
pix_len += f->vtable->char_length(f, '&');
in_pos += uwidth(s+in_pos);
}
}
else {
pix_len += f->vtable->char_length(f, c);
in_pos += uwidth(s+in_pos);
}
}
return pix_len;
}
/* _aa_find_glyph:
* Helper for aa vtable entries, below.
*/
static CACHED_GLYPH *_aa_find_glyph(AL_CONST FONT* f, int ch)
{
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
int glyph_index;
/* get the character out of the font */
if (af->face->charmap)
glyph_index = FT_Get_Char_Index(af->face, ch);
else
glyph_index = ch;
/* apply kerning */
/*if (last_glyph_index) {
FT_Vector v;
FT_Get_Kerning(af->face, last_glyph_index, glyph_index, ft_kerning_default, &v);
total_length += v.x >> 6;
}*/
/* cache */
_font_cache_glyph(f, glyph_index);
return af->cached_glyphs + glyph_index;
}
/* font_height:
* Returns the height, in pixels of the font.
*/
static int aa_font_height(AL_CONST FONT* f)
{
/* TODO */
/* return f->height; */
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
return af->face_h;
}
/* aa_char_length:
* Returns the length of a character, in pixels, as it would be rendered
* in this font.
*/
static int aa_char_length(AL_CONST FONT* f, int ch)
{
CACHED_GLYPH *g = _aa_find_glyph(f, ch);
/* return g->advancex ? g->advancex + af->ch_spacing: 0; */
return g->advancex;
}
/* aa_length:
* Returns the length, in pixels, of a string as rendered in a font.
*/
static int aa_length(AL_CONST FONT* f, AL_CONST char *text)
{
AL_CONST FONT_AA_DATA* af = reinterpret_cast<AL_CONST FONT_AA_DATA*>(f->data);
AL_CONST char *p = text;
int ch = 0, w = 0;
while ((ch = ugetxc(&p))) {
w += f->vtable->char_length(f, ch)
+ af->ch_spacing;
}
return w;
}
static void _aa_prepare_alpha_table(AL_CONST FONT* f, int color,
int *alpha_table, int depth)
{
AL_CONST FONT_AA_DATA* af = reinterpret_cast<AL_CONST FONT_AA_DATA*>(f->data);
int i, r, g, b, br, bg, bb, ir, ig, ib;
int blendr, blendg, blendb;
/* if we are gonna use transparent mode, set blender */
if (af->aa_mode < 0)
drawing_mode(DRAW_MODE_TRANS, NULL, 0, 0);
/* else if we are doing opaque mode, draw a rect and init our table*/
else {
/* get the color rgb */
r = getr_depth(depth, color);
g = getg_depth(depth, color);
b = getb_depth(depth, color);
/* get the background rgb */
br = getr_depth(depth, af->aa_mode);
bg = getg_depth(depth, af->aa_mode);
bb = getb_depth(depth, af->aa_mode);
/* get increments */
if (r == br)
ir = 0;
else
ir = (r + 1) - br;
if (g == bg)
ig = 0;
else
ig = (g + 1) - bg;
if (b == bb)
ib = 0;
else
ib = (b + 1) - bb;
blendr = br << 8;
blendg = bg << 8;
blendb = bb << 8;
/* blend both values and make our alpha table */
for (i=0; i<256; i++) {
if (i == 0)
alpha_table[i] = -1;
else
alpha_table[i] = makecol_depth(depth,
blendr >> 8, blendg >> 8, blendb >> 8);
blendr += ir;
blendg += ig;
blendb += ib;
}
}
}
static void _aa_render_glyph(BITMAP *bmp, FONT_AA_DATA* af, CACHED_GLYPH *g,
int u, int v, int color, int *alpha_table)
{
int max_bmp_x, max_bmp_y;
unsigned char *bmp_p;
int bmp_x, bmp_y;
int c;
/* anti-aliased drawing */
if (g->aa_available) {
bmp_p = g->aabmp;
u = (u + g->aaleft);
v = (v - g->aatop) + af->face_ascender;
max_bmp_x = g->aawidth + u;
max_bmp_y = g->aaheight + v;
/* if in opaque mode */
if (af->aa_mode >= 0) {
/* copy the character bitmap to the dest one */
for (bmp_y=v; bmp_y<max_bmp_y; bmp_y++) {
for (bmp_x=u; bmp_x<max_bmp_x; bmp_x++) {
c = alpha_table[*bmp_p];
if (c >= 0)
putpixel(bmp, bmp_x, bmp_y, c);
bmp_p++;
}
}
}
/* if in transparent mode */
else {
/* copy the FT character bitmap to our dest one */
for (bmp_y=v; bmp_y<max_bmp_y; bmp_y++) {
for (bmp_x=u; bmp_x<max_bmp_x; bmp_x++) {
set_trans_blender(0, 0, 0, *bmp_p);
putpixel(bmp, bmp_x, bmp_y, color);
bmp_p++;
}
}
}
}
/* monochrome drawing */
else if (g->mono_available) {
bmp_p = g->bmp;
u = (u + g->left);
v = (v - g->top) + af->face_ascender;
max_bmp_x = g->width + u;
max_bmp_y = g->height + v;
/* copy the character bitmap to our allegro one */
for (bmp_y=u; bmp_y<max_bmp_y; bmp_y++) {
for (bmp_x=v; bmp_x<max_bmp_x; bmp_x++) {
if (*bmp_p)
putpixel(bmp, bmp_x, bmp_y, color);
/* else if (af->aa_mode >= 0) */
/* putpixel(bmp, bmp_x, bmp_y, af->aa_mode); */
bmp_p++;
}
}
}
}
/* aa_render_char:
* Renders a color character onto a bitmap, at the specified location, using
* the specified colors. If fg == -1, render as color, else render as
* mono; if bg == -1, render as transparent, else render as opaque.
* Returns the character width, in pixels.
*/
static int aa_render_char(AL_CONST FONT* f, int ch, int fg, int bg, BITMAP *bmp, int x, int y)
{
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
CACHED_GLYPH *g = NULL;
int w = 0;
acquire_bitmap(bmp);
if (bg >= 0) {
rectfill(bmp, x, y,
x + f->vtable->char_length(f, ch) - 1,
y + f->vtable->font_height(f) - 1, bg);
}
g = _aa_find_glyph(f, ch);
if (g) {
int alpha_table[256];
_aa_prepare_alpha_table(f, fg, alpha_table, bitmap_color_depth(bmp));
_aa_render_glyph(bmp, af, g, x, y, fg, alpha_table);
w += g->advancex;
/* reset blender */
if (af->aa_mode < 0)
solid_mode();
}
release_bitmap(bmp);
return w;
}
/* aa_render:
* Renders a color font onto a bitmap, at the specified location, using
* the specified colors. If fg == -1, render as color, else render as
* mono; if bg == -1, render as transparent, else render as opaque.
*/
static void aa_render(AL_CONST FONT* f, AL_CONST char *text, int fg, int bg, BITMAP *bmp, int x, int y)
{
AL_CONST char *p = text;
FONT_AA_DATA* af = reinterpret_cast<FONT_AA_DATA*>(f->data);
CACHED_GLYPH *g;
int alpha_table[256];
int ch = 0;
acquire_bitmap(bmp);
if (bg >= 0) {
rectfill(bmp, x, y,
x + text_length(f, text) - 1,
y + text_height(f) - 1, bg);
bg = -1; /* to avoid filling rectangles for each character */
}
_aa_prepare_alpha_table(f, fg, alpha_table, bitmap_color_depth(bmp));
while ((ch = ugetxc (&p))) {
g = _aa_find_glyph(f, ch);
if (g) {
_aa_render_glyph(bmp, af, g, x, y, fg, alpha_table);
if (g->advancex) x += g->advancex + af->ch_spacing;
if (g->advancey) y += g->advancey + af->ch_spacing;
}
}
/* reset blender */
if (af->aa_mode < 0)
solid_mode();
release_bitmap(bmp);
}
static void aa_destroy(FONT* f)
{
FONT_AA_DATA* af;
if (!f) return;
af = reinterpret_cast<FONT_AA_DATA*>(f->data);
/* delete old glyphs */
_font_delete_glyphs(f);
/* delete the face */
FT_Done_Face(af->face);
if (af->fixed_sizes)
jfree(af->fixed_sizes);
/* deallocate the data */
if (af->data)
jfree(af->data);
jfree(af);
jfree(f);
}
/********
* vtable declarations
********/
FONT_VTABLE _ji_font_vtable_aa =
{
aa_font_height,
aa_char_length,
aa_length,
aa_render_char,
aa_render,
aa_destroy
};
FONT_VTABLE *ji_font_vtable_aa = &_ji_font_vtable_aa;
/**********************************************************************/
#else /* without FreeType */
/**********************************************************************/
int _ji_font_init()
{
return 0;
}
void _ji_font_exit()
{
}
FONT* ji_font_load_ttf(const char* filepathname)
{
return NULL;
}
int ji_font_get_size(FONT* f)
{
return text_height(f);
}
int ji_font_set_size(FONT* f, int h)
{
/* do nothing */
return -1;
}
int ji_font_get_aa_mode(struct FONT* f)
{
return -1;
}
int ji_font_set_aa_mode(struct FONT* f, int mode)
{
return -1;
}
bool ji_font_is_fixed(FONT* f)
{
return true;
}
bool ji_font_is_scalable(FONT* f)
{
return false;
}
const int *ji_font_get_available_fixed_sizes(FONT* f, int* n)
{
return NULL; /* TODO return text_height(...) size */
}
int ji_font_get_char_extra_spacing(FONT* f)
{
return 0;
}
void ji_font_set_char_extra_spacing(FONT* f, int spacing)
{
/* do nothing */
}
int ji_font_char_len(FONT* f, int chr)
{
return f->vtable->char_length(f, chr);
}
// see jdraw_text
int ji_font_text_len(struct FONT* f, const char* s)
{
int in_pos = 0;
int pix_len = 0;
int c;
while ((c = ugetc(s+in_pos)) != 0) {
if (c == '&') {
in_pos += uwidth(s+in_pos);
c = ugetc(s+in_pos);
if (c == '&') {
pix_len += f->vtable->char_length(f, '&');
in_pos += uwidth(s+in_pos);
}
}
else {
pix_len += f->vtable->char_length(f, c);
in_pos += uwidth(s+in_pos);
}
}
return pix_len;
}
#endif