font chaining patch

SVN revision: 30940
This commit is contained in:
Carsten Haitzler 2007-07-23 14:27:44 +00:00
parent c8f22c965e
commit b9c591d390
6 changed files with 144 additions and 20 deletions

View File

@ -327,6 +327,10 @@ extern "C"
/* fonts and text */
EAPI Imlib_Font imlib_load_font(const char *font_name);
EAPI void imlib_free_font(void);
EAPI int imlib_insert_font_into_fallback_chain(Imlib_Font font, Imlib_Font fallback_font);
EAPI void imlib_remove_font_from_fallback_chain(Imlib_Font fallback_font);
EAPI Imlib_Font imlib_get_prev_font_in_fallback_chain(Imlib_Font fn);
EAPI Imlib_Font imlib_get_next_font_in_fallback_chain(Imlib_Font fn);
EAPI void imlib_text_draw(int x, int y, const char *text);
EAPI void imlib_text_draw_with_return_metrics(int x, int y, const char *text,
int *width_return,

View File

@ -3092,7 +3092,7 @@ imlib_load_font(const char *font_name)
}
/**
* Frees the current font.
* Removes the current font from any fallback chain it's in and frees it.
**/
EAPI void
imlib_free_font(void)
@ -3100,10 +3100,58 @@ imlib_free_font(void)
if (!ctx)
ctx = imlib_context_new();
CHECK_PARAM_POINTER("imlib_free_font", "font", ctx->font);
imlib_remove_font_from_fallback_chain(ctx->font);
imlib_font_free(ctx->font);
ctx->font = NULL;
}
/**
* @param font A previously loaded font.
* @param fallback_font A previously loaded font to be chained to the given font.
* @return 0 on success.
*
* This arranges for the given fallback font to be used if a glyph does not exist in the given font when text is being rendered.
* Fonts can be arranged in an aribitrarily long chain and attempts will be made in order on the chain.
* Cycles in the chain are not possible since the given fallback font is removed from any chain it's already in.
* A fallback font may be a member of only one chain. Adding it as the fallback font to another font will remove it from it's first fallback chain.
**/
EAPI int
imlib_insert_font_into_fallback_chain(Imlib_Font font, Imlib_Font fallback_font)
{
CHECK_PARAM_POINTER_RETURN("imlib_insert_font_into_fallback_chain", "font", font, 1);
CHECK_PARAM_POINTER_RETURN("imlib_insert_font_into_fallback_chain", "fallback_font", fallback_font, 1);
return imlib_insert_font_into_fallback_chain_imp(font,fallback_font);
}
/**
* @param fallback_font A font previously added to a fallback chain
* @return 0 on success.
*
* This removes the given font from any fallback chain it may be in.
* Removing this font joins its previous and next font together in the fallback chain.
**/
EAPI void
imlib_remove_font_from_fallback_chain(Imlib_Font fallback_font)
{
CHECK_PARAM_POINTER("imlib_remove_font_from_fallback_chain", "fallback_font", fallback_font);
imlib_remove_font_from_fallback_chain_imp(fallback_font);
}
EAPI Imlib_Font
imlib_get_prev_font_in_fallback_chain(Imlib_Font fn)
{
CHECK_PARAM_POINTER_RETURN("imlib_get_prev_font_in_fallback_chain", "fn", fn, 0);
return ((ImlibFont*)fn)->fallback_prev;
}
EAPI Imlib_Font
imlib_get_next_font_in_fallback_chain(Imlib_Font fn)
{
CHECK_PARAM_POINTER_RETURN("imlib_get_next_font_in_fallback_chain", "fn", fn, 0);
return ((ImlibFont*)fn)->fallback_next;
}
/**
* @param x The x coordinate of the top left corner.
* @param y The y coordinate of the top left corner.

View File

@ -50,6 +50,9 @@ struct _Imlib_Font
int references;
/* using a double-linked list for the fallback chain */
struct _Imlib_Font *fallback_prev;
struct _Imlib_Font *fallback_next;
};
struct _Imlib_Font_Glyph
@ -76,6 +79,8 @@ char **imlib_font_list_fonts(int *num_ret);
ImlibFont *imlib_font_load_joined(const char *name);
ImlibFont *imlib_font_load(const char *name, int size);
void imlib_font_free(ImlibFont * fn);
int imlib_insert_font_into_fallback_chain_imp(ImlibFont * fn, ImlibFont *fallback);
void imlib_remove_font_from_fallback_chain_imp(ImlibFont * fn);
int imlib_font_cache_get(void);
void imlib_font_cache_set(int size);
void imlib_font_flush(void);

View File

@ -245,6 +245,31 @@ imlib_render_str(ImlibImage * im, ImlibFont * fn, int drx, int dry,
/* TODO this function is purely my art -- check once more */
}
/*
* This function returns the first font in the fallback chain to contain the requested glyph.
* The glyph index is returned in ret_index
* If the glyph is not found, then the given font pointer is returned and ret_index will be set to 0
*/
ImlibFont *
imlib_find_glyph_in_font_chain(ImlibFont * first_fn, int gl, int *ret_index)
{
ImlibFont *fn = first_fn;
do
{
int index = FT_Get_Char_Index(fn->ft.face, gl);
if(index<=0)
fn = fn->fallback_next;
else
{
(*ret_index) = index;
return fn;
}
} while(fn);
(*ret_index) = 0;
return first_fn;
}
void
imlib_font_draw(ImlibImage * dst, DATA32 col, ImlibFont * fn, int x, int y,
const char *text, int *nextx, int *nexty, int clx, int cly,
@ -310,22 +335,23 @@ imlib_font_draw(ImlibImage * dst, DATA32 col, ImlibFont * fn, int x, int y,
{
FT_UInt index;
Imlib_Font_Glyph *fg;
ImlibFont *fn_in_chain;
int chr_x, chr_y;
int gl;
gl = imlib_font_utf8_get_next((unsigned char *)text, &chr);
if (gl == 0)
break;
index = FT_Get_Char_Index(fn->ft.face, gl);
fn_in_chain = imlib_find_glyph_in_font_chain(fn, gl, &index);
if ((use_kerning) && (prev_index) && (index))
{
FT_Vector delta;
FT_Get_Kerning(fn->ft.face, prev_index, index, ft_kerning_default,
FT_Get_Kerning(fn_in_chain->ft.face, prev_index, index, ft_kerning_default,
&delta);
pen_x += delta.x << 2;
}
fg = imlib_font_cache_glyph_get(fn, index);
fg = imlib_font_cache_glyph_get(fn_in_chain, index);
if (!fg)
continue;

View File

@ -185,6 +185,9 @@ imlib_font_load(const char *name, int size)
fn->references = 1;
fn->fallback_prev = NULL;
fn->fallback_next = NULL;
fonts = imlib_object_list_prepend(fonts, fn);
return fn;
}
@ -200,6 +203,36 @@ imlib_font_free(ImlibFont * fn)
}
}
int
imlib_insert_font_into_fallback_chain_imp(ImlibFont * fn, ImlibFont *fallback)
{
/* avoid infinite recursion */
if(fn == fallback)
return 1;
/* now remove the given fallback font from any chain it's already in */
imlib_remove_font_from_fallback_chain_imp(fallback);
/* insert fallback into fn's font chain */
ImlibFont *tmp=fn->fallback_next;
fn->fallback_next = fallback;
fallback->fallback_prev = fn;
fallback->fallback_next = tmp;
if (tmp)
tmp->fallback_prev = fallback;
return 0;
}
void
imlib_remove_font_from_fallback_chain_imp(ImlibFont *fn)
{
/* if fn has a previous font in its font chain, then make its fallback_next fn's fallback_next since fn is going away */
if(fn->fallback_prev)
fn->fallback_prev->fallback_next=fn->fallback_next;
fn->fallback_prev = NULL;
fn->fallback_next = NULL;
}
static int
font_modify_cache_cb(Imlib_Hash * hash, const char *key, void *data,
void *fdata)

View File

@ -15,6 +15,9 @@
#include "rgbadraw.h"
#include "rotate.h"
extern ImlibFont *
imlib_find_glyph_in_font_chain(ImlibFont * first_fn, int gl, int *ret_index); /* defined in font_draw.c */
extern FT_Library ft_lib;
/* string extents */
@ -37,22 +40,23 @@ imlib_font_query_size(ImlibFont * fn, const char *text, int *w, int *h)
{
FT_UInt index;
Imlib_Font_Glyph *fg;
ImlibFont *fn_in_chain;
int chr_x, chr_y, chr_w;
int gl;
gl = imlib_font_utf8_get_next((unsigned char *)text, &chr);
if (gl == 0)
break;
index = FT_Get_Char_Index(fn->ft.face, gl);
fn_in_chain = imlib_find_glyph_in_font_chain(fn, gl, &index);
if ((use_kerning) && (prev_index) && (index))
{
FT_Vector delta;
FT_Get_Kerning(fn->ft.face, prev_index, index, ft_kerning_default,
FT_Get_Kerning(fn_in_chain->ft.face, prev_index, index, ft_kerning_default,
&delta);
pen_x += delta.x << 2;
}
fg = imlib_font_cache_glyph_get(fn, index);
fg = imlib_font_cache_glyph_get(fn_in_chain, index);
if (!fg)
continue;
@ -71,7 +75,7 @@ imlib_font_query_size(ImlibFont * fn, const char *text, int *w, int *h)
if (w)
*w = (pen_x >> 8) - start_x;
if (h)
*h = imlib_font_max_ascent_get(fn) - imlib_font_max_descent_get(fn);
*h = imlib_font_max_ascent_get(fn) - imlib_font_max_descent_get(fn); /* TODO: compute this inside the loop since we now may be dealing with multiple fonts */
}
/* text x inset */
@ -80,6 +84,7 @@ imlib_font_query_inset(ImlibFont * fn, const char *text)
{
FT_UInt index;
Imlib_Font_Glyph *fg;
ImlibFont *fn_in_chain;
int chr;
int gl;
@ -89,8 +94,8 @@ imlib_font_query_inset(ImlibFont * fn, const char *text)
gl = imlib_font_utf8_get_next((unsigned char *)text, &chr);
if (gl == 0)
return 0;
index = FT_Get_Char_Index(fn->ft.face, gl);
fg = imlib_font_cache_glyph_get(fn, index);
fn_in_chain = imlib_find_glyph_in_font_chain(fn, gl, &index);
fg = imlib_font_cache_glyph_get(fn_in_chain, index);
if (!fg)
return 0;
return -fg->glyph_out->left;
@ -116,22 +121,23 @@ imlib_font_query_advance(ImlibFont * fn, const char *text, int *h_adv,
{
FT_UInt index;
Imlib_Font_Glyph *fg;
ImlibFont *fn_in_chain;
int chr_x, chr_y, chr_w;
int gl;
gl = imlib_font_utf8_get_next((unsigned char *)text, &chr);
if (gl == 0)
break;
index = FT_Get_Char_Index(fn->ft.face, gl);
fn_in_chain = imlib_find_glyph_in_font_chain(fn, gl, &index);
if ((use_kerning) && (prev_index) && (index))
{
FT_Vector delta;
FT_Get_Kerning(fn->ft.face, prev_index, index, ft_kerning_default,
FT_Get_Kerning(fn_in_chain->ft.face, prev_index, index, ft_kerning_default,
&delta);
pen_x += delta.x << 2;
}
fg = imlib_font_cache_glyph_get(fn, index);
fg = imlib_font_cache_glyph_get(fn_in_chain, index);
if (!fg)
continue;
@ -143,7 +149,7 @@ imlib_font_query_advance(ImlibFont * fn, const char *text, int *h_adv,
prev_index = index;
}
if (v_adv)
*v_adv = imlib_font_get_line_advance(fn);
*v_adv = imlib_font_get_line_advance(fn); /* TODO: compute this in the loop since we may be dealing with multiple fonts */
if (h_adv)
*h_adv = (pen_x >> 8) - start_x;
}
@ -172,6 +178,7 @@ imlib_font_query_char_coords(ImlibFont * fn, const char *text, int pos,
int pchr;
FT_UInt index;
Imlib_Font_Glyph *fg;
ImlibFont *fn_in_chain;
int chr_x, chr_y, chr_w;
int gl, kern;
FT_Vector delta;
@ -180,16 +187,16 @@ imlib_font_query_char_coords(ImlibFont * fn, const char *text, int pos,
gl = imlib_font_utf8_get_next((unsigned char *)text, &chr);
if (gl == 0)
break;
index = FT_Get_Char_Index(fn->ft.face, gl);
fn_in_chain = imlib_find_glyph_in_font_chain(fn, gl, &index);
kern = 0;
if ((use_kerning) && (prev_index) && (index))
{
FT_Get_Kerning(fn->ft.face, prev_index, index, ft_kerning_default,
FT_Get_Kerning(fn_in_chain->ft.face, prev_index, index, ft_kerning_default,
&delta);
kern = delta.x << 2;
pen_x += kern;
}
fg = imlib_font_cache_glyph_get(fn, index);
fg = imlib_font_cache_glyph_get(fn_in_chain, index);
if (!fg)
continue;
@ -254,6 +261,7 @@ imlib_font_query_text_at_pos(ImlibFont * fn, const char *text, int x, int y,
int pchr;
FT_UInt index;
Imlib_Font_Glyph *fg;
ImlibFont *fn_in_chain;
int chr_x, chr_y, chr_w;
int gl, kern;
FT_Vector delta;
@ -262,16 +270,16 @@ imlib_font_query_text_at_pos(ImlibFont * fn, const char *text, int x, int y,
gl = imlib_font_utf8_get_next((unsigned char *)text, &chr);
if (gl == 0)
break;
index = FT_Get_Char_Index(fn->ft.face, gl);
fn_in_chain = imlib_find_glyph_in_font_chain(fn, gl, &index);
kern = 0;
if ((use_kerning) && (prev_index) && (index))
{
FT_Get_Kerning(fn->ft.face, prev_index, index, ft_kerning_default,
FT_Get_Kerning(fn_in_chain->ft.face, prev_index, index, ft_kerning_default,
&delta);
kern = delta.x << 2;
pen_x += kern;
}
fg = imlib_font_cache_glyph_get(fn, index);
fg = imlib_font_cache_glyph_get(fn_in_chain, index);
if (!fg)
continue;