#include "evas_common.h"

/* string extents */
void
evas_common_font_query_size(RGBA_Font *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;
   evas_common_font_size_use(fn);
   use_kerning = FT_HAS_KERNING(fn->src->ft.face);
   prev_index = 0;
   for (chr = 0; text[chr];)
     {
	FT_UInt index;
	RGBA_Font_Glyph *fg;
	int chr_x, chr_y, chr_w;
        int gl;
	
	gl = evas_common_font_utf8_get_next((unsigned char *)text, &chr);
	if (gl == 0) break;
	index = FT_Get_Char_Index(fn->src->ft.face, gl);
	if ((use_kerning) && (prev_index) && (index))
	  {
	     FT_Vector delta;
	     
	     FT_Get_Kerning(fn->src->ft.face, prev_index, index,
			    ft_kerning_default, &delta);
	     pen_x += delta.x << 2;
	  }
	fg = evas_common_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 = end_x - start_x;
   if (h) *h = evas_common_font_max_ascent_get(fn) + evas_common_font_max_descent_get(fn);
}

/* text x inset */
int
evas_common_font_query_inset(RGBA_Font *fn, const char *text)
{
   FT_UInt index;
   RGBA_Font_Glyph *fg;
   int chr;
   int gl;
   
   chr = 0;
   if (!text[0]) return 0;
   gl = evas_common_font_utf8_get_next((unsigned char *)text, &chr);   
   if (gl == 0) return 0;
   evas_common_font_size_use(fn);
   index = FT_Get_Char_Index(fn->src->ft.face, gl);
   fg = evas_common_font_cache_glyph_get(fn, index);
   if (!fg) return 0;
   return fg->glyph_out->left;
}

/* h & v advance */
void
evas_common_font_query_advance(RGBA_Font *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;
   evas_common_font_size_use(fn);
   use_kerning = FT_HAS_KERNING(fn->src->ft.face);
   prev_index = 0;
   for (chr = 0; text[chr];)     
     {
	FT_UInt index;
	RGBA_Font_Glyph *fg;
	int chr_x, chr_y, chr_w;
        int gl;
	
	gl = evas_common_font_utf8_get_next((unsigned char *)text, &chr);
	if (gl == 0) break;
	index = FT_Get_Char_Index(fn->src->ft.face, gl);
	if ((use_kerning) && (prev_index) && (index))
	  {
	     FT_Vector delta;
	     
	     FT_Get_Kerning(fn->src->ft.face, prev_index, index,
			    ft_kerning_default, &delta);
	     pen_x += delta.x << 2;
	  }
	fg = evas_common_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 = evas_common_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
evas_common_font_query_char_coords(RGBA_Font *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;
   evas_common_font_size_use(fn);
   use_kerning = FT_HAS_KERNING(fn->src->ft.face);
   prev_index = 0;
   prev_chr_end = 0;
   asc = evas_common_font_max_ascent_get(fn);
   desc = evas_common_font_max_descent_get(fn);
   for (chr = 0; text[chr];)
     {
	int pchr;
	FT_UInt index;
	RGBA_Font_Glyph *fg;
	int chr_x, chr_y, chr_w;
        int gl, kern;
	FT_Vector delta;

	pchr = chr;
	gl = evas_common_font_utf8_get_next((unsigned char *)text, &chr);
	if (gl == 0) break;
	index = FT_Get_Char_Index(fn->src->ft.face, gl);
	kern = 0;
	if ((use_kerning) && (prev_index) && (index))
	  {
	     FT_Get_Kerning(fn->src->ft.face, prev_index, index,
			    ft_kerning_default, &delta);
	     kern = delta.x << 2;
	     pen_x += kern;
	  }
	fg = evas_common_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
evas_common_font_query_text_at_pos(RGBA_Font *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;
   evas_common_font_size_use(fn);
   use_kerning = FT_HAS_KERNING(fn->src->ft.face);
   prev_index = 0;
   prev_chr_end = 0;
   asc = evas_common_font_max_ascent_get(fn);
   desc = evas_common_font_max_descent_get(fn);
   for (chr = 0; text[chr];)
     {
	int pchr;
	FT_UInt index;
	RGBA_Font_Glyph *fg;
	int chr_x, chr_y, chr_w;
        int gl, kern;
	FT_Vector delta;

	pchr = chr;
	gl = evas_common_font_utf8_get_next((unsigned char *)text, &chr);
	if (gl == 0) break;
	index = FT_Get_Char_Index(fn->src->ft.face, gl);
	kern = 0;
	if ((use_kerning) && (prev_index) && (index))
	  {
	     FT_Get_Kerning(fn->src->ft.face, prev_index, index,
			    ft_kerning_default, &delta);
	     kern = delta.x << 2;
	     pen_x += kern;
	  }
	fg = evas_common_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;
}
