From: Dana Jansens Date: Wed, 28 May 2003 23:52:25 +0000 (+0000) Subject: most of the glft is contained herein. but buggy :) X-Git-Tag: gl2~52 X-Git-Url: http://git.openbox.org/?a=commitdiff_plain;h=d0e027d78cb7295f9e48a3221d9785981fd3478b;p=dana%2Fopenbox.git most of the glft is contained herein. but buggy :) --- diff --git a/glft/.cvsignore b/glft/.cvsignore index fc1eb28d..b9e33618 100644 --- a/glft/.cvsignore +++ b/glft/.cvsignore @@ -7,3 +7,4 @@ init.lo glfttest debug.lo font.lo +render.lo diff --git a/glft/Makefile.am b/glft/Makefile.am index e106496d..3dccc940 100644 --- a/glft/Makefile.am +++ b/glft/Makefile.am @@ -3,12 +3,14 @@ themedir=$(datadir)/openbox/themes theme=operation CPPFLAGS=$(FC_CFLAGS) $(GLIB_CFLAGS) $(GL_CFLAGS) @CPPFLAGS@ \ + $(shell freetype-config --cflags) \ -DG_LOG_DOMAIN=\"GlFt\" \ -DDEFAULT_THEME=\"$(theme)\" \ -DTHEMEDIR=\"$(themedir)\" INCLUDES=-I.. -LIBS=$(FC_LIBS) $(GLIB_LIBS) $(X_LIBS) $(GL_LIBS) @LIBS@ +LIBS=$(FC_LIBS) $(GLIB_LIBS) $(X_LIBS) $(GL_LIBS) \ + $(shell freetype-config --libs) @LIBS@ noinst_PROGRAMS=glfttest glfttest_LDFLAGS=-lglft -L. @@ -18,13 +20,15 @@ lib_LTLIBRARIES=libglft.la libglft_la_SOURCES=\ init.c \ font.c \ - debug.c + debug.c \ + render.c noinst_HEADERS=\ glft.h \ font.h \ init.h \ - debug.h + debug.h \ + render.h MAINTAINERCLEANFILES=Makefile.in diff --git a/glft/font.c b/glft/font.c index 53c8d7cf..fcb0512c 100644 --- a/glft/font.c +++ b/glft/font.c @@ -2,45 +2,293 @@ #include "glft.h" #include "init.h" #include "debug.h" +#include "render.h" #include #include +#include + +struct GHashTable *glyph_map = NULL; + +#define FLOOR(x) ((x) & -64) +#define CEIL(x) (((x)+63) & -64) +#define TRUNC(x) ((x) >> 6) +#define ROUND(x) (((x)+32) & -64) + +void dest_glyph_map_value(gpointer data) +{ + struct GlftGlyph *g = data; + glDeleteLists(g->dlist, 1); + free(data); +} struct GlftFont *GlftFontOpen(const char *name) { struct GlftFont *font; - FcPattern *pat; - FcFontSet *set; - double alpha; + FcPattern *pat, *match; + FcResult res; + double alpha, psize; + FcBool hinting, autohint, advance; assert(init_done); pat = FcNameParse((const unsigned char*)name); assert(pat); - set = FcFontSetCreate(); - if (!FcFontSetAdd(set, pat)) { - FcPatternDestroy(pat); - FcFontSetDestroy(set); - GlftDebug("failed to load font\n"); + + /* XXX read our extended attributes here? (if failing below..) */ + + FcConfigSubstitute(NULL, pat, FcMatchPattern); + FcDefaultSubstitute(pat); + + match = FcFontMatch(NULL, pat, &res); + printf("Pattern "); + FcPatternPrint(pat); + printf("Match "); + FcPatternPrint(match); + FcPatternDestroy(pat); + if (!match) { + GlftDebug("failed to find matching font\n"); return NULL; } font = malloc(sizeof(struct GlftFont)); - font->set = set; - if (FcResultMatch != FcPatternGetBool(pat, "shadow", 0, &font->shadow)) + font->pat = match; + font->ftflags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP; + + if (FcPatternGetString(match, FC_FILE, 0, (FcChar8**) &font->filename) != + FcResultMatch) { + GlftDebug("error getting FC_FILE from pattern\n"); + goto openfail0; + } + + switch (FcPatternGetInteger(match, FC_INDEX, 0, &font->index)) { + case FcResultNoMatch: + font->index = 0; + break; + case FcResultMatch: + break; + default: + GlftDebug("error getting FC_INDEX from pattern\n"); + goto openfail0; + } + + switch (FcPatternGetBool(match, FC_ANTIALIAS, 0, &font->antialias)) { + case FcResultNoMatch: + font->antialias = FcTrue; + break; + case FcResultMatch: + break; + default: + GlftDebug("error getting FC_ANTIALIAS from pattern\n"); + goto openfail0; + } + + switch (FcPatternGetBool(match, FC_HINTING, 0, &hinting)) { + case FcResultNoMatch: + hinting = FcTrue; + break; + case FcResultMatch: + break; + default: + GlftDebug("error getting FC_HINTING from pattern\n"); + goto openfail0; + } + if (!hinting) font->ftflags |= FT_LOAD_NO_HINTING; + + switch (FcPatternGetBool(match, FC_AUTOHINT, 0, &autohint)) { + case FcResultNoMatch: + autohint = FcFalse; + break; + case FcResultMatch: + break; + default: + GlftDebug("error getting FC_AUTOHINT from pattern\n"); + goto openfail0; + } + if (autohint) font->ftflags |= FT_LOAD_FORCE_AUTOHINT; + + switch (FcPatternGetBool(match, FC_GLOBAL_ADVANCE, 0, &advance)) { + case FcResultNoMatch: + advance = FcTrue; + break; + case FcResultMatch: + break; + default: + GlftDebug("error getting FC_GLOBAL_ADVANCE from pattern\n"); + goto openfail0; + } + if (!advance) font->ftflags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; + + switch (FcPatternGetInteger(match, FC_SPACING, 0, &font->spacing)) { + case FcResultNoMatch: + font->spacing = FC_PROPORTIONAL; + break; + case FcResultMatch: + break; + default: + GlftDebug("error getting FC_SPACING from pattern\n"); + goto openfail0; + } + + switch (FcPatternGetBool(match, FC_MINSPACE, 0, &font->minspace)) { + case FcResultNoMatch: + font->minspace = FcFalse; + break; + case FcResultMatch: + break; + default: + GlftDebug("error getting FC_MINSPACE from pattern\n"); + goto openfail0; + } + + switch (FcPatternGetInteger(match, FC_CHAR_WIDTH, 0, &font->char_width)) { + case FcResultNoMatch: + font->char_width = 0; + break; + case FcResultMatch: + if (font->char_width) + font->spacing = FC_MONO; + break; + default: + GlftDebug("error getting FC_CHAR_WIDTH from pattern\n"); + goto openfail0; + } + + if (FcPatternGetDouble(match, FC_PIXEL_SIZE, 0, &psize) != FcResultMatch) + goto openfail0; + font->ftcharsize = (FT_F26Dot6) psize * 64; + + if (FcPatternGetBool(match, "shadow", 0, &font->shadow) != FcResultMatch) font->shadow = FcFalse; - if (FcResultMatch != - FcPatternGetInteger(pat, "shadowoffset", 0, &font->shadow_offset)) + + if (FcPatternGetInteger(match, "shadowoffset", 0, &font->shadow_offset) != + FcResultMatch) font->shadow_offset = 2; - if (FcResultMatch != FcPatternGetDouble(pat, "shadowalpha", 0, &alpha)) + + if (FcPatternGetDouble(match, "shadowalpha", 0, &alpha) != FcResultMatch) alpha = 0.5; font->shadow_alpha = (float)alpha; + + /* time to load the font! */ + + if (FT_New_Face(ft_lib, font->filename, font->index, &font->face)) { + GlftDebug("failed to open FT face\n"); + goto openfail0; + } + if (FT_Set_Char_Size(font->face, 0, font->ftcharsize, 0, 0)) { + GlftDebug("failed to set char size on FT face\n"); + goto openfail0; + } + + if (!FcPatternGetCharSet(match, FC_CHARSET, 0, &font->chars) != + FcResultMatch) + font->chars = FcFreeTypeCharSet(font->face, FcConfigGetBlanks(NULL)); + if (!font->chars) { + GlftDebug("failed to get a valid CharSet\n"); + goto openfail0; + } + + font->glyph_map = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, + dest_glyph_map_value); + + if (font->char_width) + font->max_advance_width = font->char_width; + else + font->max_advance_width = font->face->size->metrics.max_advance >> 6; + font->descent = -(font->face->size->metrics.descender >> 6); + font->ascent = font->face->size->metrics.ascender >> 6; + if (font->minspace) font->height = font->ascent + font->descent; + else font->height = font->face->size->metrics.height >> 6; + return font; + +openfail0: + FcPatternDestroy(match); + free(font); + return NULL; } void GlftFontClose(struct GlftFont *font) { if (font) { - FcFontSetDestroy(font->set); + FT_Done_Face(font->face); + FcPatternDestroy(font->pat); + FcCharSetDestroy(font->chars); + g_hash_table_destroy(font->glyph_map); free(font); } } + +struct GlftGlyph *GlftFontGlyph(struct GlftFont *font, const char *c) +{ + const char *n = g_utf8_next_char(c); + int b = n - c; + struct GlftGlyph *g; + FcChar32 w; + + FcUtf8ToUcs4((const FcChar8*) c, &w, b); + + g = g_hash_table_lookup(font->glyph_map, &w); + if (!g) { + if (FT_Load_Glyph(font->face, FcFreeTypeCharIndex(font->face, w), + font->ftflags)) { + if (FT_Load_Glyph(font->face, 0, font->ftflags)) + return NULL; + else { + g = g_hash_table_lookup(font->glyph_map, &w); + } + } + } + if (!g) { + assert(font->face->face_flags & FT_FACE_FLAG_SCALABLE); + + g = malloc(sizeof(struct GlftGlyph)); + g->w = w; + g->dlist = glGenLists(1); + + GlftRenderGlyph(font->face, g->dlist); + + if (!(font->spacing == FC_PROPORTIONAL)) { + g->width = font->max_advance_width; + } else { + /*g->width = TRUNC(ROUND(font->face->glyph->advance.x));*/ + g->width = font->face->glyph->metrics.width >> 6; + } + g->height = -(font->face->glyph->metrics.height >> 6); + + g_hash_table_insert(font->glyph_map, &g->w, &g); + } + + return g; +} + +void GlftMeasureString(struct GlftFont *font, + const char *str, + int bytes, + int *w, + int *h) +{ + const char *c; + struct GlftGlyph *g; + + if (!g_utf8_validate(str, bytes, NULL)) { + GlftDebug("Invalid UTF-8 in string\n"); + return; + } + + *w = 0; + *h = 0; + + c = str; + while (c) { + g = GlftFontGlyph(font, c); + if (g) { + *w += g->width; + *h = MAX(g->height, *h); + } else { + *w += font->max_advance_width; + } + c = g_utf8_next_char(c); + if (c - str > bytes) break; + } +} + diff --git a/glft/font.h b/glft/font.h index 2eab714f..f428a9e8 100644 --- a/glft/font.h +++ b/glft/font.h @@ -3,13 +3,53 @@ #include +#include +#include FT_FREETYPE_H +#include + +#include + struct GlftFont { - FcFontSet *set; + FcPattern *pat; + FcCharSet *chars; + + char *filename; + int index; + FT_Face face; + FT_Int ftflags; + FT_F26Dot6 ftcharsize; + + FcBool antialias; + int spacing; + FcBool minspace; + int char_width; /* extended font attributes */ FcBool shadow; int shadow_offset; float shadow_alpha; + + GHashTable *glyph_map; + + /* public shit */ + int ascent; + int descent; + int height; + int max_advance_width; }; +struct GlftGlyph { + /* The character in UCS-4 encoding */ + FcChar32 w; + /* OpenGL display list for the character */ + unsigned int dlist; + + int width; + int height; +}; + +/*! Takes a character in UTF-8 encoding and returns an OpenGL display list + for it */ +struct GlftGlyph *GlftFontGlyph(struct GlftFont *font, const char *c); + #endif diff --git a/glft/glft.h b/glft/glft.h index b8e4bccf..9adfe8e6 100644 --- a/glft/glft.h +++ b/glft/glft.h @@ -17,4 +17,20 @@ void GlftFontClose(struct GlftFont *font); /* rendering */ +/*! Renders a string in UTF-8 encoding */ +void GlftRenderString(struct GlftFont *font, + const char *str, + int bytes, + int x, + int y); + +/* metrics */ + +/*! Measures a string in UTF-8 encoding */ +void GlftMeasureString(struct GlftFont *font, + const char *str, + int bytes, + int *w, + int *h); + #endif diff --git a/glft/init.c b/glft/init.c index bedd16c5..2c4410ef 100644 --- a/glft/init.c +++ b/glft/init.c @@ -1,8 +1,14 @@ #include "glft.h" +#include "font.h" + +#include +#include FT_FREETYPE_H +#include FcBool init_done = 0; +FT_Library ft_lib; FcBool GlftInit() { - return init_done = FcInit(); + return init_done = (FcInit() && !FT_Init_FreeType(&ft_lib)); } diff --git a/glft/init.h b/glft/init.h index 43fcb226..e5f3166d 100644 --- a/glft/init.h +++ b/glft/init.h @@ -2,5 +2,6 @@ #define __glft_init_h extern FcBool init_done; +extern FT_Library ft_lib; #endif diff --git a/glft/render.c b/glft/render.c new file mode 100644 index 00000000..5eb545ea --- /dev/null +++ b/glft/render.c @@ -0,0 +1,38 @@ +#include "render.h" +#include "font.h" +#include "debug.h" +#include +#include + +void GlftRenderGlyph(FT_Face face, unsigned int dlist) +{ + FT_GlyphSlot slot = face->glyph; +} + +void GlftRenderString(struct GlftFont *font, const char *str, int bytes, + int x, int y) +{ + const char *c; + struct GlftGlyph *g; + + if (!g_utf8_validate(str, bytes, NULL)) { + GlftDebug("Invalid UTF-8 in string\n"); + return; + } + + glPushMatrix(); + + c = str; + while (c) { + g = GlftFontGlyph(font, c); + if (g) { + glCallList(g->dlist); + glTranslatef(g->width, 0.0, 0.0); + } else + glTranslatef(font->max_advance_width, 0.0, 0.0); + c = g_utf8_next_char(c); + if (c - str >= bytes) break; + } + + glPopMatrix(); +} diff --git a/glft/render.h b/glft/render.h new file mode 100644 index 00000000..9a3c1518 --- /dev/null +++ b/glft/render.h @@ -0,0 +1,9 @@ +#ifndef __glft_render_h +#define __glft_render_h + +#include +#include FT_FREETYPE_H + +void GlftRenderGlyph(FT_Face face, unsigned int dlist); + +#endif