Font changes, Text (harfbuzz) and sample project added

This commit is contained in:
MattTuttle
2014-07-30 14:48:27 -05:00
parent d0604d8484
commit 83bb9d9b66
15 changed files with 830 additions and 45 deletions

View File

@@ -12,7 +12,10 @@
#include <app/UpdateEvent.h>
#ifdef LIME_FREETYPE
#include <graphics/Font.h>
#endif
#ifdef LIME_HARFBUZZ
#include <graphics/Text.h>
#endif // LIME_HARFBUZZ
#endif // LIME_FREETYPE
#include <graphics/Renderer.h>
#include <graphics/RenderEvent.h>
#include <media/format/JPEG.h>
@@ -27,6 +30,7 @@
#include <ui/TouchEvent.h>
#include <ui/Window.h>
#include <ui/WindowEvent.h>
#include <utils/CFFIValue.h>
#include <vm/NekoVM.h>
@@ -129,11 +133,22 @@ namespace lime {
}
void lime_font_destroy (value fontHandle) {
Font *font = (Font*)(intptr_t)val_float (fontHandle);
delete font;
font = 0;
}
value lime_font_load (value fontFace) {
#ifdef LIME_FREETYPE
Font *font = new Font (val_string (fontFace));
return alloc_float ((intptr_t)font);
value v = alloc_float ((intptr_t)font);
val_gc (v, lime_font_destroy);
return v;
#else
return alloc_null ();
#endif
@@ -143,11 +158,23 @@ namespace lime {
value lime_font_load_glyphs (value fontHandle, value size, value glyphs) {
#ifdef LIME_FREETYPE
Font *font = (Font*)(intptr_t)val_float (fontHandle);
font->LoadGlyphs (val_int (size), val_string (glyphs));
#endif
return alloc_null ();
}
value lime_font_create_image (value fontHandle) {
#ifdef LIME_FREETYPE
Image image;
Font *font = (Font*)(intptr_t)val_float (fontHandle);
value data = alloc_empty_object ();
alloc_field (data, val_id ("glyphs"), font->LoadGlyphs (val_int (size), val_string (glyphs), &image));
alloc_field (data, val_id ("glyphs"), font->createImage (&image));
alloc_field (data, val_id ("image"), image.Value ());
return data;
#else
@@ -157,6 +184,44 @@ namespace lime {
}
void lime_text_destroy (value textHandle) {
Text *text = (Text*)(intptr_t)val_float (textHandle);
delete text;
text = 0;
}
value lime_text_create (value direction, value script, value language) {
#if defined(LIME_FREETYPE) && defined(LIME_HARFBUZZ)
Text *text = new Text (val_int (direction), val_string (script), val_string (language));
value v = alloc_float ((intptr_t)text);
val_gc (v, lime_text_destroy);
return v;
#else
return alloc_null ();
#endif
}
value lime_text_from_string (value textHandle, value fontHandle, value textString) {
#if defined(LIME_FREETYPE) && defined(LIME_HARFBUZZ)
Image image;
Text *text = (Text*)(intptr_t)val_float (textHandle);
Font *font = (Font*)(intptr_t)val_float (fontHandle);
text->fromString(font, val_string (textString));
return alloc_null ();
#else
return alloc_null ();
#endif
}
value lime_key_event_manager_register (value callback, value eventObject) {
KeyEvent::callback = new AutoGCRoot (callback);
@@ -303,6 +368,9 @@ namespace lime {
DEFINE_PRIM (lime_image_load, 1);
DEFINE_PRIM (lime_font_load, 1);
DEFINE_PRIM (lime_font_load_glyphs, 3);
DEFINE_PRIM (lime_font_create_image, 1);
DEFINE_PRIM (lime_text_create, 3);
DEFINE_PRIM (lime_text_from_string, 3);
DEFINE_PRIM (lime_key_event_manager_register, 2);
DEFINE_PRIM (lime_lzma_encode, 1);
DEFINE_PRIM (lime_lzma_decode, 1);

View File

@@ -1,15 +1,115 @@
#include <graphics/Font.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <media/Image.h>
#include <algorithm>
// from http://stackoverflow.com/questions/2948308/how-do-i-read-utf-8-characters-via-a-pointer
#define IS_IN_RANGE(c, f, l) (((c) >= (f)) && ((c) <= (l)))
typedef struct {
unsigned long readNextChar (char*& p)
{
// TODO: since UTF-8 is a variable-length
// encoding, you should pass in the input
// buffer's actual byte length so that you
// can determine if a malformed UTF-8
// sequence would exceed the end of the buffer...
char c;
FT_UInt index;
FT_Pos height;
unsigned char c1, c2, *ptr = (unsigned char*) p;
unsigned long uc = 0;
int seqlen;
} GlyphInfo;
c1 = ptr[0];
if ((c1 & 0x80) == 0) {
uc = (unsigned long) (c1 & 0x7F);
seqlen = 1;
} else if ((c1 & 0xE0) == 0xC0) {
uc = (unsigned long) (c1 & 0x1F);
seqlen = 2;
} else if ((c1 & 0xF0) == 0xE0) {
uc = (unsigned long) (c1 & 0x0F);
seqlen = 3;
} else if ((c1 & 0xF8) == 0xF0) {
uc = (unsigned long) (c1 & 0x07);
seqlen = 4;
} else {
// malformed data, do something !!!
return (unsigned long) -1;
}
for (int i = 1; i < seqlen; ++i) {
c1 = ptr[i];
if ((c1 & 0xC0) != 0x80) {
// malformed data, do something !!!
return (unsigned long) -1;
}
}
switch (seqlen) {
case 2:
c1 = ptr[0];
if (!IS_IN_RANGE(c1, 0xC2, 0xDF)) {
// malformed data, do something !!!
return (unsigned long) -1;
}
break;
case 3:
c1 = ptr[0];
c2 = ptr[1];
if (((c1 == 0xE0) && !IS_IN_RANGE(c2, 0xA0, 0xBF)) ||
((c1 == 0xED) && !IS_IN_RANGE(c2, 0x80, 0x9F)) ||
(!IS_IN_RANGE(c1, 0xE1, 0xEC) && !IS_IN_RANGE(c1, 0xEE, 0xEF))) {
// malformed data, do something !!!
return (unsigned long) -1;
}
break;
case 4:
c1 = ptr[0];
c2 = ptr[1];
if (((c1 == 0xF0) && !IS_IN_RANGE(c2, 0x90, 0xBF)) ||
((c1 == 0xF4) && !IS_IN_RANGE(c2, 0x80, 0x8F)) ||
!IS_IN_RANGE(c1, 0xF1, 0xF3)) {
// malformed data, do something !!!
return (unsigned long) -1;
}
break;
}
for (int i = 1; i < seqlen; ++i) {
uc = ((uc << 6) | (unsigned long)(ptr[i] & 0x3F));
}
p += seqlen;
return uc;
}
namespace lime {
@@ -22,16 +122,22 @@ namespace lime {
static int id_advance;
static int id_width;
static int id_height;
static int id_char;
static int id_codepoint;
static bool init = false;
bool CompareGlyph (const GlyphInfo &a, const GlyphInfo &b) {
bool CompareGlyphHeight (const GlyphInfo &a, const GlyphInfo &b) {
return a.height > b.height;
}
bool CompareGlyphCodepoint (const GlyphInfo &a, const GlyphInfo &b) {
return a.codepoint < b.codepoint;
}
Font::Font (const char *fontFace) {
@@ -58,10 +164,72 @@ namespace lime {
}
/* Set charmap
*
* See http://www.microsoft.com/typography/otspec/name.htm for a list of
* some possible platform-encoding pairs. We're interested in 0-3 aka 3-1
* - UCS-2. Otherwise, fail. If a font has some unicode map, but lacks
* UCS-2 - it is a broken or irrelevant font. What exactly Freetype will
* select on face load (it promises most wide unicode, and if that will be
* slower that UCS-2 - left as an excercise to check.
*/
for (int i = 0; i < face->num_charmaps; i++) {
FT_UShort pid = face->charmaps[i]->platform_id;
FT_UShort eid = face->charmaps[i]->encoding_id;
if (((pid == 0) && (eid == 3)) || ((pid == 3) && (eid == 1))) {
FT_Set_Charmap (face, face->charmaps[i]);
}
}
}
value Font::LoadGlyphs (int size, const char *glyphs, Image *image) {
void Font::LoadGlyphs (int size, const char *glyphs) {
size_t hdpi = 72;
size_t vdpi = 72;
size_t hres = 100;
FT_Matrix matrix = {
(int)((1.0/hres) * 0x10000L),
(int)((0.0) * 0x10000L),
(int)((0.0) * 0x10000L),
(int)((1.0) * 0x10000L)
};
FT_Set_Char_Size (face, 0, (int)(size*64), (int)(hdpi * hres), vdpi);
FT_Set_Transform (face, &matrix, NULL);
char *g = (char*)glyphs;
while (*g != 0) {
GlyphInfo info;
bool found = false;
info.codepoint = readNextChar(g);
std::list<GlyphInfo>::iterator first = glyphList.begin ();
first = std::lower_bound (first, glyphList.end (), info, CompareGlyphCodepoint);
if (info.codepoint < (*first).codepoint) {
info.index = FT_Get_Char_Index (face, info.codepoint);
if (FT_Load_Glyph (face, info.index, FT_LOAD_DEFAULT) != 0) continue;
info.height = face->glyph->metrics.height;
glyphList.insert (first, info);
}
}
}
value Font::createImage (Image *image) {
if (!init) {
@@ -72,33 +240,14 @@ namespace lime {
id_x_offset = val_id ("xOffset");
id_y_offset = val_id ("yOffset");
id_advance = val_id ("advance");
id_char = val_id ("char");
id_codepoint = val_id ("codepoint");
init = true;
}
std::list<GlyphInfo> glyphList;
int numGlyphs = strlen (glyphs);
char c[2] = " ";
glyphList.sort (CompareGlyphHeight);
FT_Set_Pixel_Sizes (face, 0, size);
for (int i = 0; i < numGlyphs; i++) {
GlyphInfo info;
info.c = glyphs[i];
info.index = FT_Get_Char_Index (face, info.c);
if (FT_Load_Glyph (face, info.index, FT_LOAD_DEFAULT) != 0) continue;
info.height = face->glyph->metrics.height;
glyphList.push_back(info);
}
glyphList.sort(CompareGlyph);
image->Resize(128, 128, 1);
image->Resize (128, 128, 1);
int x = 0, y = 0, maxRows = 0;
unsigned char *bytes = image->data->Bytes ();
@@ -108,7 +257,6 @@ namespace lime {
for (std::list<GlyphInfo>::iterator it = glyphList.begin(); it != glyphList.end(); it++) {
FT_Load_Glyph (face, (*it).index, FT_LOAD_DEFAULT);
c[0] = (*it).c;
if (FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL) != 0) continue;
@@ -177,7 +325,7 @@ namespace lime {
alloc_field (v, id_advance, alloc_int (face->glyph->metrics.horiAdvance / 64));
alloc_field (v, id_width, alloc_int (bitmap.width));
alloc_field (v, id_height, alloc_int (bitmap.rows));
alloc_field (v, id_char, alloc_string (c));
alloc_field (v, id_codepoint, alloc_int ((*it).codepoint));
val_array_set_i (rects, rectsIndex++, v);
x += bitmap.width + 1;

View File

@@ -0,0 +1,55 @@
#include <graphics/Font.h>
#include <graphics/Text.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <hb-ft.h>
namespace lime {
Text::Text (hb_tag_t direction, const char *script, const char *language) {
if (strlen(script) != 4) return;
buffer = hb_buffer_create ();
hb_buffer_set_direction (buffer, (hb_direction_t)direction);
hb_buffer_set_script (buffer, (hb_script_t)HB_TAG (script[0], script[1], script[2], script[3]));
hb_buffer_set_language (buffer, hb_language_from_string (language, strlen (language)));
}
Text::~Text () {
hb_buffer_destroy (buffer);
}
void Text::fromString (Font *font, const char *text) {
// layout the text
size_t len = strlen (text);
hb_buffer_add_utf8 (buffer, text, len, 0, len);
hb_font_t *hb_font = hb_ft_font_create (font->face, NULL);
hb_shape (hb_font, buffer, NULL, 0);
unsigned int glyph_count;
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos (buffer, &glyph_count);
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions (buffer, &glyph_count);
float hres = 16.0;
for (int i = 0; i < glyph_count; i++) {
int codepoint = glyph_info[i].codepoint;
float x_advance = glyph_pos[i].x_advance / (float)(hres * 64);
float x_offset = glyph_pos[i].x_offset / (float)(hres * 64);
float y_advance = glyph_pos[i].y_advance / (float)(64);
float y_offset = glyph_pos[i].y_offset / (float)(64);
}
hb_font_destroy (hb_font);
}
}