spiv: Fix image list counter
[gfxprim.git] / libs / text / GP_FreeType.c
blob3b8866774864b3c524ffc799ad8f967dadc21994
1 /*****************************************************************************
2 * This file is part of gfxprim library. *
3 * *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
8 * *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
18 * *
19 * Copyright (C) 2009-2012 Cyril Hrubis <metan@ucw.cz> *
20 * *
21 *****************************************************************************/
23 #include "../../config.h"
24 #include "core/GP_Debug.h"
25 #include "text/GP_Font.h"
27 #ifdef HAVE_FREETYPE
29 #include <ft2build.h>
30 #include FT_FREETYPE_H
32 GP_FontFace *GP_FontFaceLoad(const char *path, uint32_t width, uint32_t height)
34 FT_Library library;
35 FT_Face face;
36 int err;
38 err = FT_Init_FreeType(&library);
40 if (err) {
41 GP_DEBUG(1, "Failed to initalize Free Type");
42 return NULL;
45 err = FT_New_Face(library, path, 0, &face);
47 if (err) {
48 //TODO: FT_Exit_FreeType() ?
49 GP_DEBUG(1, "Failed to open font '%s'", path);
50 return NULL;
53 GP_DEBUG(1, "Opened font '%s'", path);
54 GP_DEBUG(2, "Font family_name='%s' style_name='%s' num_glyphs=%li",
55 face->family_name, face->style_name,
56 (long)face->num_glyphs);
57 GP_DEBUG(2, "Font ascender=%i descender=%i height=%i",
58 (int)face->ascender, (int)face->descender, (int)face->height);
60 //TODO: not scalable fonts?
61 err = FT_Set_Pixel_Sizes(face, width, height);
63 if (err) {
64 GP_DEBUG(1, "Failed to set pixel size");
65 return NULL;
68 /* Allocate font face structure */
69 unsigned int font_face_size;
71 font_face_size = sizeof(GP_FontFace) +
72 sizeof(uint32_t) * GP_GetGlyphCount(GP_CHARSET_7BIT);
74 GP_FontFace *font = malloc(font_face_size);
76 if (font == NULL) {
77 GP_DEBUG(1, "Malloc failed :(");
78 goto err1;
81 /* Copy font metadata */
82 strncpy(font->family_name, face->family_name,
83 sizeof(font->family_name));
84 font->family_name[GP_FONT_NAME_MAX - 1] = '\0';
85 strncpy(font->style_name, face->style_name,
86 sizeof(font->style_name));
87 font->style_name[GP_FONT_NAME_MAX - 1] = '\0';
89 font->glyph_bitmap_format = GP_FONT_BITMAP_8BPP;
90 font->charset = GP_CHARSET_7BIT;
92 /* Count glyph data size */
93 unsigned int i;
94 unsigned int glyph_table_size = 0;
96 for (i = 0x20; i < 0x7f; i++) {
97 FT_UInt glyph_idx = FT_Get_Char_Index(face, i);
99 err = FT_Load_Glyph(face, glyph_idx, FT_LOAD_DEFAULT);
101 if (err) {
102 GP_DEBUG(1, "Failed to load glyph '%c'", i);
103 goto err2;
106 err = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
108 if (err) {
109 GP_DEBUG(1, "Failed to render glyph '%c'", i);
110 goto err2;
113 FT_Bitmap *bitmap = &face->glyph->bitmap;
115 GP_DEBUG(2, "Glyph '%c' bitmap rows=%i width=%i pitch=%i",
116 i, bitmap->rows, bitmap->width, bitmap->pitch);
118 GP_DEBUG(2, " bitmap top=%i left=%i",
119 face->glyph->bitmap_top, face->glyph->bitmap_left);
121 /* count glyph table size and fill offset table */
122 font->glyph_offsets[i - 0x20] = glyph_table_size;
123 glyph_table_size += sizeof(GP_GlyphBitmap) +
124 bitmap->rows * bitmap->pitch;
127 GP_DEBUG(2, "Glyph table size %u bytes", glyph_table_size);
129 font->glyphs = malloc(glyph_table_size);
131 if (font->glyphs == NULL) {
132 GP_DEBUG(1, "Malloc failed :(");
133 goto err2;
136 font->max_glyph_width = 0;
137 font->max_glyph_advance = 0;
138 font->ascend = 0;
139 font->descend = 0;
141 for (i = 0x20; i < 0x7f; i++) {
142 FT_UInt glyph_idx = FT_Get_Char_Index(face, i);
144 err = FT_Load_Glyph(face, glyph_idx, FT_LOAD_DEFAULT);
146 GP_DEBUG(2, "Loading and rendering glyph '%c'", i);
148 if (err) {
149 GP_DEBUG(1, "Failed to load glyph '%c'", i);
150 goto err3;
153 err = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
155 if (err) {
156 GP_DEBUG(1, "Failed to render glyph '%c'", i);
157 goto err3;
160 GP_GlyphBitmap *glyph_bitmap = GP_GetGlyphBitmap(font, i);
161 FT_GlyphSlot glyph = face->glyph;
163 glyph_bitmap->width = glyph->bitmap.width;
164 glyph_bitmap->height = glyph->bitmap.rows;
165 glyph_bitmap->bearing_x = glyph->bitmap_left;
166 glyph_bitmap->bearing_y = glyph->bitmap_top;
167 glyph_bitmap->advance_x = (glyph->advance.x + 32)>>6;
169 int16_t width = glyph_bitmap->bearing_x + glyph_bitmap->width;
170 int16_t ascend = glyph_bitmap->bearing_y;
171 int16_t descend = glyph_bitmap->height - ascend;
173 if (font->ascend < ascend)
174 font->ascend = ascend;
176 if (font->descend < descend)
177 font->descend = descend;
179 if (font->max_glyph_advance < glyph_bitmap->advance_x)
180 font->max_glyph_advance = glyph_bitmap->advance_x;
182 if (font->max_glyph_width < width)
183 font->max_glyph_width = width;
185 int x, y;
187 for (y = 0; y < glyph_bitmap->height; y++) {
188 for (x = 0; x < glyph_bitmap->width; x++) {
189 unsigned int addr = glyph_bitmap->width * y + x;
191 glyph_bitmap->bitmap[addr] = glyph->bitmap.buffer[y * glyph->bitmap.pitch + x];
196 return font;
197 err3:
198 free(font->glyphs);
199 err2:
200 free(font);
201 err1:
202 //TODO FREETYPE CLEANUP
203 return NULL;
206 #else
208 GP_FontFace *GP_FontFaceLoad(const char *path, uint32_t width, uint32_t height)
210 (void)path;
211 (void)width;
212 (void)height;
214 GP_WARN("FreeType support not compiled in.");
216 return NULL;
219 #endif /* HAVE_FREETYPE */