forked from old/legacy-imlib2
parent
7c65468d34
commit
be6f2d57cb
|
@ -0,0 +1,421 @@
|
|||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "colormod.h"
|
||||
#include "image.h"
|
||||
#include "blend.h"
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_GLYPH_H
|
||||
#include "font.h"
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "file.h"
|
||||
#include "updates.h"
|
||||
#include "rgbadraw.h"
|
||||
#include "rotate.h"
|
||||
|
||||
extern FT_Library ft_lib;
|
||||
|
||||
Imlib_Font_Glyph *
|
||||
imlib_font_cache_glyph_get(ImlibFont * fn, FT_UInt index)
|
||||
{
|
||||
Imlib_Font_Glyph *fg;
|
||||
char key[6];
|
||||
FT_Error error;
|
||||
|
||||
key[0] = ((index) & 0x7f) + 1;
|
||||
key[1] = ((index >> 7) & 0x7f) + 1;
|
||||
key[2] = ((index >> 14) & 0x7f) + 1;
|
||||
key[3] = ((index >> 21) & 0x7f) + 1;
|
||||
key[4] = ((index >> 28) & 0x0f) + 1;
|
||||
key[5] = 0;
|
||||
|
||||
fg = imlib_hash_find(fn->glyphs, key);
|
||||
if (fg)
|
||||
return fg;
|
||||
|
||||
error = FT_Load_Glyph(fn->ft.face, index, FT_LOAD_NO_BITMAP);
|
||||
if (error)
|
||||
return NULL;
|
||||
|
||||
fg = malloc(sizeof(struct _Imlib_Font_Glyph));
|
||||
if (!fg)
|
||||
return NULL;
|
||||
memset(fg, 0, (sizeof(struct _Imlib_Font_Glyph)));
|
||||
|
||||
error = FT_Get_Glyph(fn->ft.face->glyph, &(fg->glyph));
|
||||
if (error)
|
||||
{
|
||||
free(fg);
|
||||
return NULL;
|
||||
}
|
||||
if (fg->glyph->format != ft_glyph_format_bitmap)
|
||||
{
|
||||
error = FT_Glyph_To_Bitmap(&(fg->glyph), ft_render_mode_normal, 0, 1);
|
||||
if (error)
|
||||
{
|
||||
FT_Done_Glyph(fg->glyph);
|
||||
free(fg);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
fg->glyph_out = (FT_BitmapGlyph) fg->glyph;
|
||||
|
||||
fn->glyphs = imlib_hash_add(fn->glyphs, key, fg);
|
||||
return fg;
|
||||
}
|
||||
|
||||
void
|
||||
imlib_render_str(ImlibImage * im, ImlibFont * fn, int drx, int dry,
|
||||
const char *text, DATA8 r, DATA8 g, DATA8 b, DATA8 a,
|
||||
char dir, double angle, int *retw, int *reth, int blur,
|
||||
int *nextx, int *nexty, ImlibOp op, int clx, int cly,
|
||||
int clw, int clh)
|
||||
{
|
||||
int w, h, ascent;
|
||||
ImlibImage *im2;
|
||||
DATA32 *data, col;
|
||||
int nx, ny, tmp;
|
||||
|
||||
imlib_font_query_size(fn, text, &w, &h);
|
||||
|
||||
data = malloc(w * h * sizeof(DATA32));
|
||||
if (!data)
|
||||
return;
|
||||
memset(data, 0, w * h * sizeof(DATA32));
|
||||
/* TODO check if this is the right way of rendering. Esp for huge sizes */
|
||||
im2 = __imlib_CreateImage(w, h, data);
|
||||
if (!im2)
|
||||
{
|
||||
free(data);
|
||||
return;
|
||||
}
|
||||
SET_FLAG(im2->flags, F_HAS_ALPHA);
|
||||
|
||||
/* TODO check for endianess */
|
||||
col = (a << 24) | (r << 16) | (g << 8) | b;
|
||||
|
||||
ascent = imlib_font_max_ascent_get(fn);
|
||||
|
||||
imlib_font_draw(im2, col, fn, 0, ascent, text, &nx, &ny, clx, cly, clw, clh);
|
||||
|
||||
/* OK, now we have small ImlibImage with text rendered,
|
||||
* have to blend it on im */
|
||||
|
||||
if (blur > 0)
|
||||
__imlib_BlurImage(im2, blur);
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case 0: /* to right */
|
||||
angle = 0.0;
|
||||
break;
|
||||
case 1: /* to left */
|
||||
angle = 0.0;
|
||||
__imlib_FlipImageBoth(im2);
|
||||
break;
|
||||
case 2: /* to down */
|
||||
angle = 0.0;
|
||||
__imlib_FlipImageDiagonal(im2, 1);
|
||||
break;
|
||||
case 3: /* to up */
|
||||
angle = 0.0;
|
||||
__imlib_FlipImageDiagonal(im2, 2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (angle == 0.0)
|
||||
{
|
||||
__imlib_BlendImageToImage(im2, im, 0, 1, IMAGE_HAS_ALPHA(im), 0, 0,
|
||||
im2->w, im2->h, drx, dry, im2->w, im2->h,
|
||||
NULL, op, clx, cly, clw, clh);
|
||||
}
|
||||
else
|
||||
{
|
||||
int xx, yy;
|
||||
double sa, ca;
|
||||
|
||||
sa = sin(angle);
|
||||
ca = cos(angle);
|
||||
xx = drx;
|
||||
yy = dry;
|
||||
if (sa > 0.0)
|
||||
xx += sa * im2->h;
|
||||
else
|
||||
yy -= sa * im2->w;
|
||||
if (ca < 0.0)
|
||||
{
|
||||
xx -= ca * im2->w;
|
||||
yy -= ca * im2->h;
|
||||
}
|
||||
__imlib_BlendImageToImageSkewed(im2, im, 1, 1, IMAGE_HAS_ALPHA(im), 0,
|
||||
0, im2->w, im2->h, xx, yy, (w * ca),
|
||||
(w * sa), 0, 0, NULL, op, clx, cly, clw,
|
||||
clh);
|
||||
}
|
||||
|
||||
__imlib_FreeImage(im2);
|
||||
|
||||
/* finally deal with return values */
|
||||
switch (dir)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
if (retw)
|
||||
*retw = w;
|
||||
if (reth)
|
||||
*reth = h;
|
||||
if (nextx)
|
||||
*nextx = nx;
|
||||
if (nexty)
|
||||
*nexty = ny;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
if (retw)
|
||||
*retw = h;
|
||||
if (reth)
|
||||
*reth = w;
|
||||
if (nextx)
|
||||
*nextx = ny;
|
||||
if (nexty)
|
||||
*nexty = nx;
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
double sa, ca;
|
||||
double x1, x2, xt;
|
||||
double y1, y2, yt;
|
||||
|
||||
sa = sin(angle);
|
||||
ca = cos(angle);
|
||||
|
||||
x1 = x2 = 0.0;
|
||||
xt = ca * w;
|
||||
if (xt < x1)
|
||||
x1 = xt;
|
||||
if (xt > x2)
|
||||
x2 = xt;
|
||||
xt = -(sa * h);
|
||||
if (xt < x1)
|
||||
x1 = xt;
|
||||
if (xt > x2)
|
||||
x2 = xt;
|
||||
xt = ca * w - sa * h;
|
||||
if (xt < x1)
|
||||
x1 = xt;
|
||||
if (xt > x2)
|
||||
x2 = xt;
|
||||
w = (int)(x2 - x1);
|
||||
|
||||
y1 = y2 = 0.0;
|
||||
yt = sa * w;
|
||||
if (yt < y1)
|
||||
y1 = yt;
|
||||
if (yt > y2)
|
||||
y2 = yt;
|
||||
yt = ca * h;
|
||||
if (yt < y1)
|
||||
y1 = yt;
|
||||
if (yt > y2)
|
||||
y2 = yt;
|
||||
yt = sa * w + ca * h;
|
||||
if (yt < y1)
|
||||
y1 = yt;
|
||||
if (yt > y2)
|
||||
y2 = yt;
|
||||
h = (int)(y2 - y1);
|
||||
}
|
||||
if (retw)
|
||||
*retw = w;
|
||||
if (reth)
|
||||
*reth = h;
|
||||
if (nextx)
|
||||
*nextx = nx;
|
||||
if (nexty)
|
||||
*nexty = ny;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* TODO this function is purely my art -- check once more */
|
||||
}
|
||||
|
||||
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,
|
||||
int clw, int clh)
|
||||
{
|
||||
int use_kerning;
|
||||
int pen_x, pen_y;
|
||||
int chr;
|
||||
FT_UInt prev_index;
|
||||
int ext_x, ext_y, ext_w, ext_h;
|
||||
DATA32 *im;
|
||||
int im_w, im_h;
|
||||
int lut[256];
|
||||
int ii;
|
||||
|
||||
im = dst->data;
|
||||
im_w = dst->w;
|
||||
im_h = dst->h;
|
||||
|
||||
ext_x = 0;
|
||||
ext_y = 0;
|
||||
ext_w = im_w;
|
||||
ext_h = im_h;
|
||||
|
||||
if (clw)
|
||||
{
|
||||
ext_x = clx;
|
||||
ext_y = cly;
|
||||
ext_w = clw;
|
||||
ext_h = clh;
|
||||
}
|
||||
if (ext_x < 0)
|
||||
{
|
||||
ext_w += ext_x;
|
||||
ext_x = 0;
|
||||
}
|
||||
if (ext_y < 0)
|
||||
{
|
||||
ext_h += ext_y;
|
||||
ext_y = 0;
|
||||
}
|
||||
if ((ext_x + ext_w) > im_w)
|
||||
ext_w = im_w - ext_x;
|
||||
if ((ext_y + ext_h) > im_h)
|
||||
ext_h = im_h - ext_y;
|
||||
|
||||
if (ext_w <= 0)
|
||||
return;
|
||||
if (ext_h <= 0)
|
||||
return;
|
||||
|
||||
for (ii = 0; ii < 256; ii++)
|
||||
{
|
||||
lut[ii] = (col & 0x00ffffff); /* TODO check endianess */
|
||||
lut[ii] |= ((((ii + 1) * (col >> 24)) >> 8) << 24);
|
||||
}
|
||||
|
||||
pen_x = x << 8;
|
||||
pen_y = y << 8;
|
||||
use_kerning = FT_HAS_KERNING(fn->ft.face);
|
||||
prev_index = 0;
|
||||
for (chr = 0; text[chr];)
|
||||
{
|
||||
FT_UInt index;
|
||||
Imlib_Font_Glyph *fg;
|
||||
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);
|
||||
if ((use_kerning) && (prev_index) && (index))
|
||||
{
|
||||
FT_Vector delta;
|
||||
|
||||
FT_Get_Kerning(fn->ft.face, prev_index, index, ft_kerning_default,
|
||||
&delta);
|
||||
pen_x += delta.x << 2;
|
||||
}
|
||||
fg = imlib_font_cache_glyph_get(fn, index);
|
||||
if (!fg)
|
||||
continue;
|
||||
|
||||
chr_x = (pen_x + (fg->glyph_out->left << 8)) >> 8;
|
||||
chr_y = (pen_y + (fg->glyph_out->top << 8)) >> 8;
|
||||
|
||||
if (chr_x < (ext_x + ext_w))
|
||||
{
|
||||
DATA8 *data;
|
||||
int i, j, w, h;
|
||||
|
||||
data = fg->glyph_out->bitmap.buffer;
|
||||
j = fg->glyph_out->bitmap.pitch;
|
||||
w = fg->glyph_out->bitmap.width;
|
||||
if (j < w)
|
||||
j = w;
|
||||
h = fg->glyph_out->bitmap.rows;
|
||||
if ((fg->glyph_out->bitmap.pixel_mode == ft_pixel_mode_grays)
|
||||
&& (fg->glyph_out->bitmap.num_grays == 256))
|
||||
{
|
||||
if ((j > 0) && (chr_x + w > ext_x))
|
||||
{
|
||||
for (i = 0; i < h; i++)
|
||||
{
|
||||
int dx, dy;
|
||||
int in_x, in_w;
|
||||
|
||||
in_x = 0;
|
||||
in_w = 0;
|
||||
dx = chr_x;
|
||||
dy = y - (chr_y - i - y);
|
||||
if ((dx < (ext_x + ext_w)) && (dy >= (ext_y))
|
||||
&& (dy < (ext_y + ext_h)))
|
||||
{
|
||||
if (dx + w > (ext_x + ext_w))
|
||||
in_w += (dx + w) - (ext_x + ext_w);
|
||||
if (dx < ext_x)
|
||||
{
|
||||
in_w += ext_x - dx;
|
||||
in_x = ext_x - dx;
|
||||
dx = ext_x;
|
||||
}
|
||||
if (in_w < w)
|
||||
{
|
||||
DATA8 *src_ptr;
|
||||
DATA32 *dst_ptr;
|
||||
DATA32 *dst_end_ptr;
|
||||
|
||||
src_ptr = data + (i * j) + in_x;
|
||||
dst_ptr = im + (dy * im_w) + dx;
|
||||
dst_end_ptr = dst_ptr + w - in_w;
|
||||
|
||||
while (dst_ptr < dst_end_ptr)
|
||||
{
|
||||
/* FIXME Oops! change this op */
|
||||
if (!*dst_ptr)
|
||||
*dst_ptr =
|
||||
lut[(unsigned char)*src_ptr];
|
||||
else if (*src_ptr)
|
||||
{
|
||||
/* very rare case - I've never seen symbols
|
||||
* overlapped by kerning */
|
||||
int tmp;
|
||||
|
||||
tmp =
|
||||
(*dst_ptr >> 24) +
|
||||
(lut
|
||||
[(unsigned char)*src_ptr]
|
||||
>> 24);
|
||||
tmp = (tmp > 256) ? 256 : tmp;
|
||||
*dst_ptr &= 0x00ffffff;
|
||||
*dst_ptr |= (tmp << 24);
|
||||
}
|
||||
|
||||
dst_ptr++;
|
||||
src_ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
pen_x += fg->glyph->advance.x >> 8;
|
||||
prev_index = index;
|
||||
}
|
||||
|
||||
if (nextx)
|
||||
*nextx = (pen_x >> 8) - x;
|
||||
if (nexty)
|
||||
*nexty = imlib_font_get_line_advance(fn);
|
||||
}
|
|
@ -0,0 +1,431 @@
|
|||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "colormod.h"
|
||||
#include "image.h"
|
||||
#include "blend.h"
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_GLYPH_H
|
||||
#include "font.h"
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "file.h"
|
||||
#include "updates.h"
|
||||
#include "rgbadraw.h"
|
||||
#include "rotate.h"
|
||||
|
||||
extern FT_Library ft_lib;
|
||||
|
||||
static int font_cache_usage = 0;
|
||||
static int font_cache = 0;
|
||||
static char **fpath = NULL;
|
||||
static int fpath_num = 0;
|
||||
static Imlib_Object_List *fonts = NULL;
|
||||
|
||||
static int font_modify_cache_cb(Imlib_Hash * hash, const char *key,
|
||||
void *data, void *fdata);
|
||||
static int font_flush_free_glyph_cb(Imlib_Hash * hash, const char *key,
|
||||
void *data, void *fdata);
|
||||
|
||||
/* FIXME now! listdir() from evas_object_text.c */
|
||||
|
||||
/* separate fontname and size, find font file, start imlib_font_load() then */
|
||||
ImlibFont *
|
||||
imlib_font_load_joined(const char *fontname)
|
||||
{
|
||||
int j, size;
|
||||
char *name = NULL, *file = NULL, *tmp = NULL;
|
||||
ImlibFont *fn;
|
||||
|
||||
/* split font name (in format name/size) */
|
||||
for (j = strlen(fontname) - 1; (j >= 0) && (fontname[j] != '/'); j--);
|
||||
/* no "/" in font after the first char */
|
||||
if (j <= 0)
|
||||
return NULL;
|
||||
/* get size */
|
||||
size = atoi(&(fontname[j + 1]));
|
||||
/* split name in front off */
|
||||
name = malloc((j + 1) * sizeof(char));
|
||||
memcpy(name, fontname, j);
|
||||
name[j] = 0;
|
||||
/* find file if it exists */
|
||||
tmp = malloc(strlen(name) + 4 + 1);
|
||||
if (!tmp)
|
||||
{
|
||||
free(name);
|
||||
return NULL;
|
||||
}
|
||||
sprintf(tmp, "%s.ttf", name);
|
||||
if (__imlib_FileIsFile(tmp))
|
||||
file = strdup(tmp);
|
||||
else
|
||||
{
|
||||
sprintf(tmp, "%s.TTF", name);
|
||||
if (__imlib_FileIsFile(tmp))
|
||||
file = strdup(tmp);
|
||||
else
|
||||
{
|
||||
sprintf(tmp, "%s", name);
|
||||
if (__imlib_FileIsFile(tmp))
|
||||
file = strdup(tmp);
|
||||
}
|
||||
}
|
||||
free(tmp);
|
||||
if (!file)
|
||||
{
|
||||
for (j = 0; (j < fpath_num) && (!file); j++)
|
||||
{
|
||||
tmp = malloc(strlen(fpath[j]) + 1 + strlen(name) + 4 + 1);
|
||||
if (!tmp)
|
||||
{
|
||||
free(name);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(tmp, "%s/%s.ttf", fpath[j], name);
|
||||
if (__imlib_FileIsFile(tmp))
|
||||
file = strdup(tmp);
|
||||
else
|
||||
{
|
||||
sprintf(tmp, "%s/%s.TTF", fpath[j], name);
|
||||
if (__imlib_FileIsFile(tmp))
|
||||
file = strdup(tmp);
|
||||
else
|
||||
{
|
||||
sprintf(tmp, "%s/%s", fpath[j], name);
|
||||
if (__imlib_FileIsFile(tmp))
|
||||
file = strdup(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
free(name);
|
||||
/* didnt find a file? abort */
|
||||
if (!file)
|
||||
return NULL;
|
||||
fn = imlib_font_load(file, size);
|
||||
free(file);
|
||||
return fn;
|
||||
}
|
||||
|
||||
ImlibFont *
|
||||
imlib_font_load(const char *name, int size)
|
||||
{
|
||||
int error;
|
||||
ImlibFont *fn;
|
||||
char *file;
|
||||
|
||||
fn = imlib_font_find(name, size);
|
||||
if (fn)
|
||||
return fn;
|
||||
|
||||
imlib_font_init();
|
||||
|
||||
fn = malloc(sizeof(ImlibFont));
|
||||
file = (char *)name;
|
||||
|
||||
error = FT_New_Face(ft_lib, file, 0, &(fn->ft.face));
|
||||
if (error)
|
||||
{
|
||||
free(fn);
|
||||
return NULL;
|
||||
}
|
||||
error = FT_Set_Char_Size(fn->ft.face, 0, (size * 64), 96, 96);
|
||||
if (error)
|
||||
error = FT_Set_Pixel_Sizes(fn->ft.face, 0, size);
|
||||
if (error)
|
||||
{
|
||||
int i;
|
||||
int chosen_size = 0;
|
||||
int chosen_width = 0;
|
||||
|
||||
for (i = 0; i < fn->ft.face->num_fixed_sizes; i++)
|
||||
{
|
||||
int s;
|
||||
int d, cd;
|
||||
|
||||
s = fn->ft.face->available_sizes[i].height;
|
||||
cd = chosen_size - size;
|
||||
if (cd < 0)
|
||||
cd = -cd;
|
||||
d = s - size;
|
||||
if (d < 0)
|
||||
d = -d;
|
||||
if (d < cd)
|
||||
{
|
||||
chosen_width = fn->ft.face->available_sizes[i].width;
|
||||
chosen_size = s;
|
||||
}
|
||||
if (d == 0)
|
||||
break;
|
||||
}
|
||||
error = FT_Set_Pixel_Sizes(fn->ft.face, chosen_width, chosen_size);
|
||||
if (error)
|
||||
{
|
||||
/* couldn't choose the size anyway... what now? */
|
||||
}
|
||||
}
|
||||
|
||||
error = FT_Select_Charmap(fn->ft.face, ft_encoding_unicode);
|
||||
if (error)
|
||||
{
|
||||
}
|
||||
|
||||
fn->file = strdup(file);
|
||||
fn->name = strdup(file);
|
||||
fn->size = size;
|
||||
|
||||
fn->glyphs = NULL;
|
||||
|
||||
fn->usage = 0;
|
||||
|
||||
fn->references = 1;
|
||||
|
||||
fonts = imlib_object_list_prepend(fonts, fn);
|
||||
return fn;
|
||||
}
|
||||
|
||||
void
|
||||
imlib_font_free(ImlibFont * fn)
|
||||
{
|
||||
fn->references--;
|
||||
if (fn->references == 0)
|
||||
{
|
||||
imlib_font_modify_cache_by(fn, 1);
|
||||
imlib_font_flush();
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
font_modify_cache_cb(Imlib_Hash * hash, const char *key, void *data,
|
||||
void *fdata)
|
||||
{
|
||||
int *dir;
|
||||
Imlib_Font_Glyph *fg;
|
||||
|
||||
fg = data;
|
||||
dir = fdata;
|
||||
font_cache_usage += (*dir) * ((fg->glyph_out->bitmap.width * fg->glyph_out->bitmap.rows) + sizeof(Imlib_Font_Glyph) + sizeof(Imlib_Object_List) + 400); /* fudge values */
|
||||
return 1;
|
||||
hash = 0;
|
||||
key = 0;
|
||||
}
|
||||
|
||||
void
|
||||
imlib_font_modify_cache_by(ImlibFont * fn, int dir)
|
||||
{
|
||||
int sz_name = 0, sz_file = 0, sz_hash = 0;
|
||||
|
||||
if (fn->name)
|
||||
sz_name = strlen(fn->name);
|
||||
if (fn->file)
|
||||
sz_file = strlen(fn->file);
|
||||
if (fn->glyphs)
|
||||
sz_hash = sizeof(Imlib_Hash);
|
||||
imlib_hash_foreach(fn->glyphs, font_modify_cache_cb, &dir);
|
||||
font_cache_usage += dir * (sizeof(ImlibFont) + sz_name + sz_file + sz_hash + sizeof(FT_FaceRec) + 16384); /* fudge values */
|
||||
}
|
||||
|
||||
int
|
||||
imlib_font_cache_get(void)
|
||||
{
|
||||
return font_cache;
|
||||
}
|
||||
|
||||
void
|
||||
imlib_font_cache_set(int size)
|
||||
{
|
||||
font_cache = size;
|
||||
imlib_font_flush();
|
||||
}
|
||||
|
||||
void
|
||||
imlib_font_flush(void)
|
||||
{
|
||||
if (font_cache_usage < font_cache)
|
||||
return;
|
||||
while (font_cache_usage > font_cache)
|
||||
imlib_font_flush_last();
|
||||
}
|
||||
|
||||
static int
|
||||
font_flush_free_glyph_cb(Imlib_Hash * hash, const char *key, void *data,
|
||||
void *fdata)
|
||||
{
|
||||
Imlib_Font_Glyph *fg;
|
||||
|
||||
fg = data;
|
||||
FT_Done_Glyph(fg->glyph);
|
||||
free(fg);
|
||||
return 1;
|
||||
hash = 0;
|
||||
key = 0;
|
||||
fdata = 0;
|
||||
}
|
||||
|
||||
void
|
||||
imlib_font_flush_last(void)
|
||||
{
|
||||
Imlib_Object_List *l;
|
||||
ImlibFont *fn = NULL;
|
||||
|
||||
for (l = fonts; l; l = l->next)
|
||||
{
|
||||
ImlibFont *fn_tmp;
|
||||
|
||||
fn_tmp = (ImlibFont *) l;
|
||||
if (fn_tmp->references == 0)
|
||||
fn = fn_tmp;
|
||||
}
|
||||
if (!fn)
|
||||
return;
|
||||
|
||||
fonts = imlib_object_list_remove(fonts, fn);
|
||||
imlib_font_modify_cache_by(fn, -1);
|
||||
|
||||
imlib_hash_foreach(fn->glyphs, font_flush_free_glyph_cb, NULL);
|
||||
imlib_hash_free(fn->glyphs);
|
||||
|
||||
if (fn->file)
|
||||
free(fn->file);
|
||||
if (fn->name)
|
||||
free(fn->name);
|
||||
FT_Done_Face(fn->ft.face);
|
||||
free(fn);
|
||||
}
|
||||
|
||||
ImlibFont *
|
||||
imlib_font_find(const char *name, int size)
|
||||
{
|
||||
Imlib_Object_List *l;
|
||||
|
||||
for (l = fonts; l; l = l->next)
|
||||
{
|
||||
ImlibFont *fn;
|
||||
|
||||
fn = (ImlibFont *) l;
|
||||
if ((fn->size == size) && (!strcmp(name, fn->name)))
|
||||
{
|
||||
if (fn->references == 0)
|
||||
imlib_font_modify_cache_by(fn, -1);
|
||||
fn->references++;
|
||||
fonts = imlib_object_list_remove(fonts, fn);
|
||||
fonts = imlib_object_list_prepend(fonts, fn);
|
||||
return fn;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* font pathes */
|
||||
void
|
||||
imlib_font_add_font_path(const char *path)
|
||||
{
|
||||
fpath_num++;
|
||||
if (!fpath)
|
||||
fpath = malloc(sizeof(char *));
|
||||
else
|
||||
fpath = realloc(fpath, (fpath_num * sizeof(char *)));
|
||||
fpath[fpath_num - 1] = strdup(path);
|
||||
}
|
||||
|
||||
void
|
||||
imlib_font_del_font_path(const char *path)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < fpath_num; i++)
|
||||
{
|
||||
if (!strcmp(path, fpath[i]))
|
||||
{
|
||||
if (fpath[i])
|
||||
free(fpath[i]);
|
||||
fpath_num--;
|
||||
for (j = i; j < fpath_num; j++)
|
||||
fpath[j] = fpath[j + 1];
|
||||
if (fpath_num > 0)
|
||||
fpath = realloc(fpath, fpath_num * sizeof(char *));
|
||||
else
|
||||
{
|
||||
free(fpath);
|
||||
fpath = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
imlib_font_path_exists(const char *path)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < fpath_num; i++)
|
||||
{
|
||||
if (!strcmp(path, fpath[i]))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char **
|
||||
imlib_font_list_font_path(int *num_ret)
|
||||
{
|
||||
*num_ret = fpath_num;
|
||||
return fpath;
|
||||
}
|
||||
|
||||
/* fonts list */
|
||||
char **
|
||||
imlib_font_list_fonts(int *num_ret)
|
||||
{
|
||||
int i, j, d, l = 0;
|
||||
char **list = NULL, **dir, *path;
|
||||
FT_Error error;
|
||||
char *p;
|
||||
|
||||
imlib_font_init();
|
||||
|
||||
for (i = 0; i < fpath_num; i++)
|
||||
{
|
||||
dir = __imlib_FileDir(fpath[i], &d);
|
||||
if (dir)
|
||||
{
|
||||
for (j = 0; j < d; j++)
|
||||
{
|
||||
path = malloc(strlen(fpath[i]) + strlen(dir[j]) + 2);
|
||||
sprintf(path, "%s/%s", fpath[i], dir[j]);
|
||||
/* trim .ttf if it is there */
|
||||
if ((p = strrchr(dir[j], '.')))
|
||||
*p = '\0';
|
||||
if (!__imlib_ItemInList(list, l, dir[j]))
|
||||
{
|
||||
if (__imlib_FileIsFile(path))
|
||||
{
|
||||
FT_Face f;
|
||||
|
||||
error = FT_New_Face(ft_lib, path, 0, &f);
|
||||
if (!error)
|
||||
{
|
||||
FT_Done_Face(f);
|
||||
l++;
|
||||
if (list)
|
||||
list = realloc(list, sizeof(char *) * l);
|
||||
else
|
||||
list = malloc(sizeof(char *));
|
||||
list[l - 1] = strdup(dir[j]);
|
||||
}
|
||||
free(dir[j]);
|
||||
}
|
||||
}
|
||||
free(path);
|
||||
}
|
||||
free(dir);
|
||||
}
|
||||
}
|
||||
*num_ret = l;
|
||||
return list;
|
||||
}
|
|
@ -0,0 +1,418 @@
|
|||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "colormod.h"
|
||||
#include "image.h"
|
||||
#include "blend.h"
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_GLYPH_H
|
||||
#include "font.h"
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "file.h"
|
||||
#include "updates.h"
|
||||
#include "rgbadraw.h"
|
||||
#include "rotate.h"
|
||||
|
||||
FT_Library ft_lib;
|
||||
|
||||
static int imlib_hash_gen(const char *key);
|
||||
static int imlib_list_alloc_error(void);
|
||||
|
||||
static int _imlib_hash_alloc_error = 0;
|
||||
static int _imlib_list_alloc_error = 0;
|
||||
|
||||
void
|
||||
imlib_font_init(void)
|
||||
{
|
||||
static int initialised = 0;
|
||||
int error;
|
||||
|
||||
if (initialised)
|
||||
return;
|
||||
error = FT_Init_FreeType(&ft_lib);
|
||||
if (error)
|
||||
return;
|
||||
initialised = 1;
|
||||
}
|
||||
|
||||
int
|
||||
imlib_font_ascent_get(ImlibFont * fn)
|
||||
{
|
||||
int val;
|
||||
int ret;
|
||||
|
||||
val = (int)fn->ft.face->ascender;
|
||||
fn->ft.face->units_per_EM = 2048; /* nasy hack - need to have correct
|
||||
* val */
|
||||
ret =
|
||||
(val * fn->ft.face->size->metrics.y_scale) /
|
||||
(fn->ft.face->units_per_EM * fn->ft.face->units_per_EM);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
imlib_font_descent_get(ImlibFont * fn)
|
||||
{
|
||||
int val;
|
||||
int ret;
|
||||
|
||||
val = -(int)fn->ft.face->descender;
|
||||
fn->ft.face->units_per_EM = 2048; /* nasy hack - need to have correct
|
||||
* val */
|
||||
ret =
|
||||
(val * fn->ft.face->size->metrics.y_scale) /
|
||||
(fn->ft.face->units_per_EM * fn->ft.face->units_per_EM);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
imlib_font_max_ascent_get(ImlibFont * fn)
|
||||
{
|
||||
int val;
|
||||
int ret;
|
||||
|
||||
val = (int)fn->ft.face->bbox.yMax;
|
||||
fn->ft.face->units_per_EM = 2048; /* nasy hack - need to have correct
|
||||
* val */
|
||||
ret =
|
||||
(val * fn->ft.face->size->metrics.y_scale) /
|
||||
(fn->ft.face->units_per_EM * fn->ft.face->units_per_EM);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
imlib_font_max_descent_get(ImlibFont * fn)
|
||||
{
|
||||
int val;
|
||||
int ret;
|
||||
|
||||
val = (int)fn->ft.face->bbox.yMin;
|
||||
fn->ft.face->units_per_EM = 2048; /* nasy hack - need to have correct
|
||||
* val */
|
||||
ret =
|
||||
(val * fn->ft.face->size->metrics.y_scale) /
|
||||
(fn->ft.face->units_per_EM * fn->ft.face->units_per_EM);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
imlib_font_get_line_advance(ImlibFont * fn)
|
||||
{
|
||||
int val;
|
||||
int ret;
|
||||
|
||||
val = (int)fn->ft.face->height;
|
||||
fn->ft.face->units_per_EM = 2048; /* nasy hack - need to have correct
|
||||
* val */
|
||||
ret =
|
||||
(val * fn->ft.face->size->metrics.y_scale) /
|
||||
(fn->ft.face->units_per_EM * fn->ft.face->units_per_EM);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
imlib_font_utf8_get_next(unsigned char *buf, int *iindex)
|
||||
{
|
||||
/* Reads UTF8 bytes from @buf, starting at *@index and returns the code
|
||||
* point of the next valid code point. @index is updated ready for the
|
||||
* next call.
|
||||
*
|
||||
* * Returns 0 to indicate an error (e.g. invalid UTF8) */
|
||||
|
||||
int index = *iindex, r;
|
||||
unsigned char d = buf[index++], d2, d3, d4;
|
||||
|
||||
if (!d)
|
||||
return 0;
|
||||
if (d < 0x80)
|
||||
{
|
||||
*iindex = index;
|
||||
return d;
|
||||
}
|
||||
if ((d & 0xe0) == 0xc0)
|
||||
{
|
||||
/* 2 byte */
|
||||
d2 = buf[index++];
|
||||
if ((d2 & 0xc0) != 0x80)
|
||||
return 0;
|
||||
r = d & 0x1f; /* copy lower 5 */
|
||||
r <<= 6;
|
||||
r |= (d2 & 0x3f); /* copy lower 6 */
|
||||
}
|
||||
else if ((d & 0xf0) == 0xe0)
|
||||
{
|
||||
/* 3 byte */
|
||||
d2 = buf[index++];
|
||||
d3 = buf[index++];
|
||||
if ((d2 & 0xc0) != 0x80 || (d3 & 0xc0) != 0x80)
|
||||
return 0;
|
||||
r = d & 0x0f; /* copy lower 4 */
|
||||
r <<= 6;
|
||||
r |= (d2 & 0x3f);
|
||||
r <<= 6;
|
||||
r |= (d3 & 0x3f);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 4 byte */
|
||||
d2 = buf[index++];
|
||||
d3 = buf[index++];
|
||||
d4 = buf[index++];
|
||||
if ((d2 & 0xc0) != 0x80 || (d3 & 0xc0) != 0x80 || (d4 & 0xc0) != 0x80)
|
||||
return 0;
|
||||
r = d & 0x0f; /* copy lower 4 */
|
||||
r <<= 6;
|
||||
r |= (d2 & 0x3f);
|
||||
r <<= 6;
|
||||
r |= (d3 & 0x3f);
|
||||
r <<= 6;
|
||||
r |= (d4 & 0x3f);
|
||||
|
||||
}
|
||||
if (r < 0xdfff && d > 0xd800)
|
||||
{
|
||||
/* ill-formed says Table 3.1B in the */
|
||||
/* Unicode 3.2 std */
|
||||
return 0;
|
||||
}
|
||||
*iindex = index;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* TODO put this somewhere else */
|
||||
|
||||
void *
|
||||
imlib_object_list_prepend(void *in_list, void *in_item)
|
||||
{
|
||||
Imlib_Object_List *new_l;
|
||||
Imlib_Object_List *list, *item;
|
||||
|
||||
list = in_list;
|
||||
item = in_item;
|
||||
new_l = item;
|
||||
new_l->prev = NULL;
|
||||
if (!list)
|
||||
{
|
||||
new_l->next = NULL;
|
||||
new_l->last = new_l;
|
||||
return new_l;
|
||||
}
|
||||
new_l->next = list;
|
||||
list->prev = new_l;
|
||||
new_l->last = list->last;
|
||||
list->last = NULL;
|
||||
return new_l;
|
||||
}
|
||||
|
||||
void *
|
||||
imlib_object_list_remove(void *in_list, void *in_item)
|
||||
{
|
||||
Imlib_Object_List *return_l;
|
||||
Imlib_Object_List *list, *item;
|
||||
|
||||
/* checkme */
|
||||
if (!in_list)
|
||||
return in_list;
|
||||
|
||||
list = in_list;
|
||||
item = in_item;
|
||||
if (!item)
|
||||
return list;
|
||||
if (item->next)
|
||||
item->next->prev = item->prev;
|
||||
if (item->prev)
|
||||
{
|
||||
item->prev->next = item->next;
|
||||
return_l = list;
|
||||
}
|
||||
else
|
||||
{
|
||||
return_l = item->next;
|
||||
if (return_l)
|
||||
return_l->last = list->last;
|
||||
}
|
||||
if (item == list->last)
|
||||
list->last = item->prev;
|
||||
item->next = NULL;
|
||||
item->prev = NULL;
|
||||
return return_l;
|
||||
}
|
||||
|
||||
static int
|
||||
imlib_hash_gen(const char *key)
|
||||
{
|
||||
unsigned int hash_num = 0;
|
||||
const unsigned char *ptr;
|
||||
|
||||
if (!key)
|
||||
return 0;
|
||||
|
||||
for (ptr = (unsigned char *)key; *ptr; ptr++)
|
||||
hash_num ^= (int)(*ptr);
|
||||
|
||||
hash_num &= 0xff;
|
||||
return (int)hash_num;
|
||||
}
|
||||
|
||||
Imlib_Hash *
|
||||
imlib_hash_add(Imlib_Hash * hash, const char *key, const void *data)
|
||||
{
|
||||
int hash_num;
|
||||
Imlib_Hash_El *el;
|
||||
|
||||
_imlib_hash_alloc_error = 0;
|
||||
if (!hash)
|
||||
{
|
||||
hash = calloc(1, sizeof(struct _Imlib_Hash));
|
||||
if (!hash)
|
||||
{
|
||||
_imlib_hash_alloc_error = 1;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (!(el = malloc(sizeof(struct _Imlib_Hash_El))))
|
||||
{
|
||||
if (hash->population <= 0)
|
||||
{
|
||||
free(hash);
|
||||
hash = NULL;
|
||||
}
|
||||
_imlib_hash_alloc_error = 1;
|
||||
return hash;
|
||||
};
|
||||
if (key)
|
||||
{
|
||||
el->key = strdup(key);
|
||||
if (!el->key)
|
||||
{
|
||||
free(el);
|
||||
_imlib_hash_alloc_error = 1;
|
||||
return hash;
|
||||
}
|
||||
hash_num = imlib_hash_gen(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
el->key = NULL;
|
||||
hash_num = 0;
|
||||
}
|
||||
el->data = (void *)data;
|
||||
|
||||
hash->buckets[hash_num] =
|
||||
imlib_object_list_prepend(hash->buckets[hash_num], el);
|
||||
|
||||
if (imlib_list_alloc_error())
|
||||
{
|
||||
_imlib_hash_alloc_error = 1;
|
||||
if (el->key)
|
||||
free(el->key);
|
||||
free(el);
|
||||
return hash;
|
||||
}
|
||||
hash->population++;
|
||||
return hash;
|
||||
}
|
||||
|
||||
void *
|
||||
imlib_hash_find(Imlib_Hash * hash, const char *key)
|
||||
{
|
||||
int hash_num;
|
||||
Imlib_Hash_El *el;
|
||||
Imlib_Object_List *l;
|
||||
|
||||
_imlib_hash_alloc_error = 0;
|
||||
if (!hash)
|
||||
return NULL;
|
||||
hash_num = imlib_hash_gen(key);
|
||||
for (l = hash->buckets[hash_num]; l; l = l->next)
|
||||
{
|
||||
el = (Imlib_Hash_El *) l;
|
||||
if (((el->key) && (key) && (!strcmp(el->key, key)))
|
||||
|| ((!el->key) && (!key)))
|
||||
{
|
||||
if (l != hash->buckets[hash_num])
|
||||
{
|
||||
/* FIXME: move to front of list without alloc */
|
||||
hash->buckets[hash_num] =
|
||||
imlib_object_list_remove(hash->buckets[hash_num], el);
|
||||
hash->buckets[hash_num] =
|
||||
imlib_object_list_prepend(hash->buckets[hash_num], el);
|
||||
if (imlib_list_alloc_error())
|
||||
{
|
||||
_imlib_hash_alloc_error = 1;
|
||||
return el->data;
|
||||
}
|
||||
}
|
||||
return el->data;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
imlib_hash_free(Imlib_Hash * hash)
|
||||
{
|
||||
int i, size;
|
||||
|
||||
if (!hash)
|
||||
return;
|
||||
size = imlib_hash_size(hash);
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
while (hash->buckets[i])
|
||||
{
|
||||
Imlib_Hash_El *el;
|
||||
|
||||
el = (Imlib_Hash_El *) hash->buckets[i];
|
||||
if (el->key)
|
||||
free(el->key);
|
||||
hash->buckets[i] = imlib_object_list_remove(hash->buckets[i], el);
|
||||
free(el);
|
||||
}
|
||||
}
|
||||
free(hash);
|
||||
}
|
||||
|
||||
void
|
||||
imlib_hash_foreach(Imlib_Hash * hash, int (*func) (Imlib_Hash * hash,
|
||||
const char *key, void *data,
|
||||
void *fdata),
|
||||
const void *fdata)
|
||||
{
|
||||
int i, size;
|
||||
|
||||
if (!hash)
|
||||
return;
|
||||
size = imlib_hash_size(hash);
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
Imlib_Object_List *l, *next_l;
|
||||
|
||||
for (l = hash->buckets[i]; l;)
|
||||
{
|
||||
Imlib_Hash_El *el;
|
||||
|
||||
next_l = l->next;
|
||||
el = (Imlib_Hash_El *) l;
|
||||
if (!func(hash, el->key, el->data, (void *)fdata))
|
||||
return;
|
||||
l = next_l;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
imlib_hash_size(Imlib_Hash * hash)
|
||||
{
|
||||
if (!hash)
|
||||
return 0;
|
||||
return 256;
|
||||
}
|
||||
|
||||
int
|
||||
imlib_list_alloc_error(void)
|
||||
{
|
||||
return _imlib_list_alloc_error;
|
||||
}
|
|
@ -0,0 +1,313 @@
|
|||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "colormod.h"
|
||||
#include "image.h"
|
||||
#include "blend.h"
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_GLYPH_H
|
||||
#include "font.h"
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "file.h"
|
||||
#include "updates.h"
|
||||
#include "rgbadraw.h"
|
||||
#include "rotate.h"
|
||||
|
||||
extern FT_Library ft_lib;
|
||||
|
||||
/* string extents */
|
||||
void
|
||||
imlib_font_query_size(ImlibFont * fn, const char *text, int *w, int *h)
|
||||
{
|
||||
int use_kerning;
|
||||
int pen_x, pen_y;
|
||||
int start_x, end_x;
|
||||
int chr;
|
||||
FT_UInt prev_index;
|
||||
|
||||
start_x = 0;
|
||||
end_x = 0;
|
||||
pen_x = 0;
|
||||
pen_y = 0;
|
||||
use_kerning = FT_HAS_KERNING(fn->ft.face);
|
||||
prev_index = 0;
|
||||
for (chr = 0; text[chr];)
|
||||
{
|
||||
FT_UInt index;
|
||||
Imlib_Font_Glyph *fg;
|
||||
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);
|
||||
if ((use_kerning) && (prev_index) && (index))
|
||||
{
|
||||
FT_Vector delta;
|
||||
|
||||
FT_Get_Kerning(fn->ft.face, prev_index, index, ft_kerning_default,
|
||||
&delta);
|
||||
pen_x += delta.x << 2;
|
||||
}
|
||||
fg = imlib_font_cache_glyph_get(fn, index);
|
||||
if (!fg)
|
||||
continue;
|
||||
|
||||
chr_x = (pen_x >> 8) + fg->glyph_out->left;
|
||||
chr_y = (pen_y >> 8) + fg->glyph_out->top;
|
||||
chr_w = fg->glyph_out->bitmap.width;
|
||||
|
||||
if (!prev_index)
|
||||
start_x = chr_x;
|
||||
if ((chr_x + chr_w) > end_x)
|
||||
end_x = chr_x + chr_w;
|
||||
|
||||
pen_x += fg->glyph->advance.x >> 8;
|
||||
prev_index = index;
|
||||
}
|
||||
if (w)
|
||||
*w = (pen_x >> 8) - start_x;
|
||||
if (h)
|
||||
*h = imlib_font_max_ascent_get(fn) - imlib_font_max_descent_get(fn);
|
||||
}
|
||||
|
||||
/* text x inset */
|
||||
int
|
||||
imlib_font_query_inset(ImlibFont * fn, const char *text)
|
||||
{
|
||||
FT_UInt index;
|
||||
Imlib_Font_Glyph *fg;
|
||||
int chr;
|
||||
int gl;
|
||||
|
||||
chr = 0;
|
||||
if (!text[0])
|
||||
return 0;
|
||||
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);
|
||||
if (!fg)
|
||||
return 0;
|
||||
return -fg->glyph_out->left;
|
||||
}
|
||||
|
||||
/* h & v advance */
|
||||
void
|
||||
imlib_font_query_advance(ImlibFont * fn, const char *text, int *h_adv,
|
||||
int *v_adv)
|
||||
{
|
||||
int use_kerning;
|
||||
int pen_x, pen_y;
|
||||
int start_x;
|
||||
int chr;
|
||||
FT_UInt prev_index;
|
||||
|
||||
start_x = 0;
|
||||
pen_x = 0;
|
||||
pen_y = 0;
|
||||
use_kerning = FT_HAS_KERNING(fn->ft.face);
|
||||
prev_index = 0;
|
||||
for (chr = 0; text[chr];)
|
||||
{
|
||||
FT_UInt index;
|
||||
Imlib_Font_Glyph *fg;
|
||||
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);
|
||||
if ((use_kerning) && (prev_index) && (index))
|
||||
{
|
||||
FT_Vector delta;
|
||||
|
||||
FT_Get_Kerning(fn->ft.face, prev_index, index, ft_kerning_default,
|
||||
&delta);
|
||||
pen_x += delta.x << 2;
|
||||
}
|
||||
fg = imlib_font_cache_glyph_get(fn, index);
|
||||
if (!fg)
|
||||
continue;
|
||||
|
||||
chr_x = (pen_x >> 8) + fg->glyph_out->left;
|
||||
chr_y = (pen_y >> 8) + fg->glyph_out->top;
|
||||
chr_w = fg->glyph_out->bitmap.width;
|
||||
|
||||
pen_x += fg->glyph->advance.x >> 8;
|
||||
prev_index = index;
|
||||
}
|
||||
if (v_adv)
|
||||
*v_adv = imlib_font_get_line_advance(fn);
|
||||
if (h_adv)
|
||||
*h_adv = (pen_x >> 8) - start_x;
|
||||
}
|
||||
|
||||
/* x y w h for char at char pos */
|
||||
int
|
||||
imlib_font_query_char_coords(ImlibFont * fn, const char *text, int pos,
|
||||
int *cx, int *cy, int *cw, int *ch)
|
||||
{
|
||||
int use_kerning;
|
||||
int pen_x, pen_y;
|
||||
int prev_chr_end;
|
||||
int chr;
|
||||
int asc, desc;
|
||||
FT_UInt prev_index;
|
||||
|
||||
pen_x = 0;
|
||||
pen_y = 0;
|
||||
use_kerning = FT_HAS_KERNING(fn->ft.face);
|
||||
prev_index = 0;
|
||||
prev_chr_end = 0;
|
||||
asc = imlib_font_max_ascent_get(fn);
|
||||
desc = imlib_font_max_descent_get(fn);
|
||||
for (chr = 0; text[chr];)
|
||||
{
|
||||
int pchr;
|
||||
FT_UInt index;
|
||||
Imlib_Font_Glyph *fg;
|
||||
int chr_x, chr_y, chr_w;
|
||||
int gl, kern;
|
||||
FT_Vector delta;
|
||||
|
||||
pchr = chr;
|
||||
gl = imlib_font_utf8_get_next((unsigned char *)text, &chr);
|
||||
if (gl == 0)
|
||||
break;
|
||||
index = FT_Get_Char_Index(fn->ft.face, gl);
|
||||
kern = 0;
|
||||
if ((use_kerning) && (prev_index) && (index))
|
||||
{
|
||||
FT_Get_Kerning(fn->ft.face, prev_index, index, ft_kerning_default,
|
||||
&delta);
|
||||
kern = delta.x << 2;
|
||||
pen_x += kern;
|
||||
}
|
||||
fg = imlib_font_cache_glyph_get(fn, index);
|
||||
if (!fg)
|
||||
continue;
|
||||
|
||||
if (kern < 0)
|
||||
kern = 0;
|
||||
chr_x = ((pen_x - kern) >> 8) + fg->glyph_out->left;
|
||||
chr_y = (pen_y >> 8) + fg->glyph_out->top;
|
||||
chr_w = fg->glyph_out->bitmap.width + (kern >> 8);
|
||||
if (text[chr])
|
||||
{
|
||||
int advw;
|
||||
|
||||
advw = ((fg->glyph->advance.x + (kern << 8)) >> 16);
|
||||
if (chr_w < advw)
|
||||
chr_w = advw;
|
||||
}
|
||||
if (chr_x > prev_chr_end)
|
||||
{
|
||||
chr_w += (chr_x - prev_chr_end);
|
||||
chr_x = prev_chr_end;
|
||||
}
|
||||
if (pchr == pos)
|
||||
{
|
||||
if (cx)
|
||||
*cx = chr_x;
|
||||
if (cy)
|
||||
*cy = -asc;
|
||||
if (cw)
|
||||
*cw = chr_w;
|
||||
if (ch)
|
||||
*ch = asc + desc;
|
||||
return 1;
|
||||
}
|
||||
prev_chr_end = chr_x + chr_w;
|
||||
pen_x += fg->glyph->advance.x >> 8;
|
||||
prev_index = index;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* char pos of text at xy pos */
|
||||
int
|
||||
imlib_font_query_text_at_pos(ImlibFont * fn, const char *text, int x, int y,
|
||||
int *cx, int *cy, int *cw, int *ch)
|
||||
{
|
||||
int use_kerning;
|
||||
int pen_x, pen_y;
|
||||
int prev_chr_end;
|
||||
int chr;
|
||||
int asc, desc;
|
||||
FT_UInt prev_index;
|
||||
|
||||
pen_x = 0;
|
||||
pen_y = 0;
|
||||
use_kerning = FT_HAS_KERNING(fn->ft.face);
|
||||
prev_index = 0;
|
||||
prev_chr_end = 0;
|
||||
asc = imlib_font_max_ascent_get(fn);
|
||||
desc = imlib_font_max_descent_get(fn);
|
||||
for (chr = 0; text[chr];)
|
||||
{
|
||||
int pchr;
|
||||
FT_UInt index;
|
||||
Imlib_Font_Glyph *fg;
|
||||
int chr_x, chr_y, chr_w;
|
||||
int gl, kern;
|
||||
FT_Vector delta;
|
||||
|
||||
pchr = chr;
|
||||
gl = imlib_font_utf8_get_next((unsigned char *)text, &chr);
|
||||
if (gl == 0)
|
||||
break;
|
||||
index = FT_Get_Char_Index(fn->ft.face, gl);
|
||||
kern = 0;
|
||||
if ((use_kerning) && (prev_index) && (index))
|
||||
{
|
||||
FT_Get_Kerning(fn->ft.face, prev_index, index, ft_kerning_default,
|
||||
&delta);
|
||||
kern = delta.x << 2;
|
||||
pen_x += kern;
|
||||
}
|
||||
fg = imlib_font_cache_glyph_get(fn, index);
|
||||
if (!fg)
|
||||
continue;
|
||||
|
||||
if (kern < 0)
|
||||
kern = 0;
|
||||
chr_x = ((pen_x - kern) >> 8) + fg->glyph_out->left;
|
||||
chr_y = (pen_y >> 8) + fg->glyph_out->top;
|
||||
chr_w = fg->glyph_out->bitmap.width + (kern >> 8);
|
||||
if (text[chr])
|
||||
{
|
||||
int advw;
|
||||
|
||||
advw = ((fg->glyph->advance.x + (kern << 8)) >> 16);
|
||||
if (chr_w < advw)
|
||||
chr_w = advw;
|
||||
}
|
||||
if (chr_x > prev_chr_end)
|
||||
{
|
||||
chr_w += (chr_x - prev_chr_end);
|
||||
chr_x = prev_chr_end;
|
||||
}
|
||||
if ((x >= chr_x) && (x <= (chr_x + chr_w)) && (y > -asc) && (y < desc))
|
||||
{
|
||||
if (cx)
|
||||
*cx = chr_x;
|
||||
if (cy)
|
||||
*cy = -asc;
|
||||
if (cw)
|
||||
*cw = chr_w;
|
||||
if (ch)
|
||||
*ch = asc + desc;
|
||||
return pchr;
|
||||
}
|
||||
prev_chr_end = chr_x + chr_w;
|
||||
pen_x += fg->glyph->advance.x >> 8;
|
||||
prev_index = index;
|
||||
}
|
||||
return -1;
|
||||
}
|
Loading…
Reference in New Issue