423 lines
12 KiB
C
423 lines
12 KiB
C
#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;
|
|
|
|
imlib_font_query_advance(fn, text, &w, NULL);
|
|
h = imlib_font_max_ascent_get(fn) - imlib_font_max_descent_get(fn);
|
|
|
|
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, 0, 0, w, h);
|
|
|
|
/* 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);
|
|
}
|