Restore Flash font embedding

This commit is contained in:
Joshua Granick
2014-10-14 12:46:31 -07:00
parent 1dbcc45890
commit 79082949a6
5 changed files with 587 additions and 195 deletions

View File

@@ -240,6 +240,21 @@ class Font {
}
public function decompose ():NativeFontData {
#if (cpp || neko)
return lime_font_outline_decompose (handle, 1024 * 20);
#else
return null;
#end
}
public function loadRange (size:Int, start:Int, end:Int) {
#if (flash || js)
@@ -281,7 +296,46 @@ class Font {
private static var lime_font_load_glyphs = System.load ("lime", "lime_font_load_glyphs", 3);
private static var lime_font_load_range = System.load ("lime", "lime_font_load_range", 4);
private static var lime_font_create_image = System.load ("lime", "lime_font_create_image", 1);
private static var lime_font_outline_decompose = System.load ("lime", "lime_font_outline_decompose", 2);
#end
}
typedef NativeFontData =
{
var has_kerning: Bool;
var is_fixed_width: Bool;
var has_glyph_names: Bool;
var is_italic: Bool;
var is_bold: Bool;
var num_glyphs: Int;
var family_name: String;
var style_name: String;
var em_size: Int;
var ascend: Int;
var descend: Int;
var height: Int;
var glyphs: Array<NativeGlyphData>;
var kerning: Array<NativeKerningData>;
}
typedef NativeGlyphData =
{
var char_code: Int;
var advance: Int;
var min_x: Int;
var max_x: Int;
var min_y: Int;
var max_y: Int;
var points: Array<Int>;
}
typedef NativeKerningData =
{
var left_glyph:Int;
var right_glyph:Int;
var x:Int;
var y:Int;
}

View File

@@ -9,6 +9,11 @@
#ifdef LIME_FREETYPE
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_BITMAP_H
#include FT_SFNT_NAMES_H
#include FT_TRUETYPE_IDS_H
#include FT_GLYPH_H
#include FT_OUTLINE_H
#endif
@@ -45,10 +50,12 @@ namespace lime {
public:
Font (const char *fontFace);
value Decompose (int em);
void LoadGlyphs (const char *glyphs);
void LoadRange (unsigned long start, unsigned long end);
void SetSize (size_t size);
value RenderToImage (ImageBuffer *image);
void SetSize (size_t size);
#ifdef LIME_FREETYPE
FT_Face face;

View File

@@ -158,6 +158,18 @@ namespace lime {
}
value lime_font_outline_decompose (value fontHandle, value size) {
#ifdef LIME_FREETYPE
Font *font = (Font*)(intptr_t)val_float (fontHandle);
return font->Decompose (val_int (size));
#else
return alloc_null ();
#endif
}
value lime_image_load (value data) {
ImageBuffer imageBuffer;
@@ -380,6 +392,7 @@ namespace lime {
DEFINE_PRIM (lime_font_load, 1);
DEFINE_PRIM (lime_font_load_glyphs, 3);
DEFINE_PRIM (lime_font_load_range, 4);
DEFINE_PRIM (lime_font_outline_decompose, 2);
DEFINE_PRIM (lime_image_load, 1);
DEFINE_PRIM (lime_key_event_manager_register, 2);
DEFINE_PRIM (lime_lzma_encode, 1);

View File

@@ -1,6 +1,7 @@
#include <graphics/Font.h>
#include <graphics/ImageBuffer.h>
#include <algorithm>
#include <vector>
// 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)))
@@ -112,16 +113,117 @@ unsigned long readNextChar (char*& p)
}
namespace {
enum {
PT_MOVE = 1,
PT_LINE = 2,
PT_CURVE = 3
};
struct point {
int x, y;
unsigned char type;
point() { }
point(int x, int y, unsigned char type) : x(x), y(y), type(type) { }
};
struct glyph {
FT_ULong char_code;
FT_Vector advance;
FT_Glyph_Metrics metrics;
int index, x, y;
std::vector<int> pts;
glyph(): x(0), y(0) { }
};
struct kerning {
int l_glyph, r_glyph;
int x, y;
kerning() { }
kerning(int l, int r, int x, int y): l_glyph(l), r_glyph(r), x(x), y(y) { }
};
struct glyph_sort_predicate {
bool operator()(const glyph* g1, const glyph* g2) const {
return g1->char_code < g2->char_code;
}
};
typedef const FT_Vector *FVecPtr;
int outline_move_to(FVecPtr to, void *user) {
glyph *g = static_cast<glyph*>(user);
g->pts.push_back(PT_MOVE);
g->pts.push_back(to->x);
g->pts.push_back(to->y);
g->x = to->x;
g->y = to->y;
return 0;
}
int outline_line_to(FVecPtr to, void *user) {
glyph *g = static_cast<glyph*>(user);
g->pts.push_back(PT_LINE);
g->pts.push_back(to->x - g->x);
g->pts.push_back(to->y - g->y);
g->x = to->x;
g->y = to->y;
return 0;
}
int outline_conic_to(FVecPtr ctl, FVecPtr to, void *user) {
glyph *g = static_cast<glyph*>(user);
g->pts.push_back(PT_CURVE);
g->pts.push_back(ctl->x - g->x);
g->pts.push_back(ctl->y - g->y);
g->pts.push_back(to->x - ctl->x);
g->pts.push_back(to->y - ctl->y);
g->x = to->x;
g->y = to->y;
return 0;
}
int outline_cubic_to(FVecPtr, FVecPtr , FVecPtr , void *user) {
// Cubic curves are not supported
return 1;
}
}
namespace lime {
static int id_codepoint;
static int id_height;
static int id_offset;
static int id_size;
static int id_width;
static int id_x;
static int id_y;
static int id_offset;
static int id_width;
static int id_height;
static int id_size;
static int id_codepoint;
static bool init = false;
@@ -131,6 +233,7 @@ namespace lime {
}
bool CompareGlyphCodepoint (const GlyphInfo &a, const GlyphInfo &b) {
return a.codepoint < b.codepoint && a.size < b.size;
@@ -187,6 +290,220 @@ namespace lime {
}
wchar_t *get_familyname_from_sfnt_name(FT_Face face)
{
wchar_t *family_name = NULL;
FT_SfntName sfnt_name;
FT_UInt num_sfnt_names, sfnt_name_index;
int len, i;
if (FT_IS_SFNT(face))
{
num_sfnt_names = FT_Get_Sfnt_Name_Count(face);
sfnt_name_index = 0;
while (sfnt_name_index < num_sfnt_names)
{
if (!FT_Get_Sfnt_Name(face, sfnt_name_index++, (FT_SfntName *)&sfnt_name))
{
//if((sfnt_name.name_id == TT_NAME_ID_FONT_FAMILY) &&
if((sfnt_name.name_id == 4) &&
//(sfnt_name.language_id == GetUserDefaultLCID()) &&
(sfnt_name.platform_id == TT_PLATFORM_MICROSOFT) &&
(sfnt_name.encoding_id == TT_MS_ID_UNICODE_CS))
{
/* Note that most fonts contains a Unicode charmap using
TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS.
*/
/* .string :
Note that its format differs depending on the
(platform,encoding) pair. It can be a Pascal String,
a UTF-16 one, etc..
Generally speaking, the string is "not" zero-terminated.
Please refer to the TrueType specification for details..
.string_len :
The length of `string' in bytes.
*/
len = sfnt_name.string_len / 2;
family_name = (wchar_t*)malloc((len + 1) * sizeof(wchar_t));
for(i = 0; i < len; i++)
{
family_name[i] = ((wchar_t)sfnt_name.string[i*2 + 1]) | (((wchar_t)sfnt_name.string[i*2]) << 8);
}
family_name[len] = 0;
return family_name;
}
}
}
}
return NULL;
}
value Font::Decompose (int em) {
int result, i, j;
FT_Set_Char_Size (face, em, em, 72, 72);
std::vector<glyph*> glyphs;
FT_Outline_Funcs ofn =
{
outline_move_to,
outline_line_to,
outline_conic_to,
outline_cubic_to,
0, // shift
0 // delta
};
// Import every character in face
FT_ULong char_code;
FT_UInt glyph_index;
char_code = FT_Get_First_Char (face, &glyph_index);
while (glyph_index != 0) {
if (FT_Load_Glyph (face, glyph_index, FT_LOAD_FORCE_AUTOHINT | FT_LOAD_DEFAULT) == 0) {
glyph *g = new glyph;
result = FT_Outline_Decompose (&face->glyph->outline, &ofn, g);
if (result == 0) {
g->index = glyph_index;
g->char_code = char_code;
g->metrics = face->glyph->metrics;
glyphs.push_back (g);
} else {
delete g;
}
}
char_code = FT_Get_Next_Char (face, char_code, &glyph_index);
}
// Ascending sort by character codes
std::sort (glyphs.begin (), glyphs.end (), glyph_sort_predicate ());
std::vector<kerning> kern;
if (FT_HAS_KERNING (face)) {
int n = glyphs.size ();
FT_Vector v;
for (i = 0; i < n; i++) {
int l_glyph = glyphs[i]->index;
for (j = 0; j < n; j++) {
int r_glyph = glyphs[j]->index;
FT_Get_Kerning (face, l_glyph, r_glyph, FT_KERNING_DEFAULT, &v);
if (v.x != 0 || v.y != 0) {
kern.push_back (kerning (i, j, v.x, v.y));
}
}
}
}
int num_glyphs = glyphs.size ();
wchar_t* family_name = get_familyname_from_sfnt_name (face);
value ret = alloc_empty_object ();
alloc_field (ret, val_id ("has_kerning"), alloc_bool (FT_HAS_KERNING (face)));
alloc_field (ret, val_id ("is_fixed_width"), alloc_bool (FT_IS_FIXED_WIDTH (face)));
alloc_field (ret, val_id ("has_glyph_names"), alloc_bool (FT_HAS_GLYPH_NAMES (face)));
alloc_field (ret, val_id ("is_italic"), alloc_bool (face->style_flags & FT_STYLE_FLAG_ITALIC));
alloc_field (ret, val_id ("is_bold"), alloc_bool (face->style_flags & FT_STYLE_FLAG_BOLD));
alloc_field (ret, val_id ("num_glyphs"), alloc_int (num_glyphs));
alloc_field (ret, val_id ("family_name"), family_name == NULL ? alloc_string (face->family_name) : alloc_wstring (family_name));
alloc_field (ret, val_id ("style_name"), alloc_string (face->style_name));
alloc_field (ret, val_id ("em_size"), alloc_int (face->units_per_EM));
alloc_field (ret, val_id ("ascend"), alloc_int (face->ascender));
alloc_field (ret, val_id ("descend"), alloc_int (face->descender));
alloc_field (ret, val_id ("height"), alloc_int (face->height));
// 'glyphs' field
value neko_glyphs = alloc_array (num_glyphs);
for (i = 0; i < glyphs.size (); i++) {
glyph *g = glyphs[i];
int num_points = g->pts.size ();
value points = alloc_array (num_points);
for (j = 0; j < num_points; j++) {
val_array_set_i (points, j, alloc_int (g->pts[j]));
}
value item = alloc_empty_object ();
val_array_set_i (neko_glyphs, i, item);
alloc_field (item, val_id ("char_code"), alloc_int (g->char_code));
alloc_field (item, val_id ("advance"), alloc_int (g->metrics.horiAdvance));
alloc_field (item, val_id ("min_x"), alloc_int (g->metrics.horiBearingX));
alloc_field (item, val_id ("max_x"), alloc_int (g->metrics.horiBearingX + g->metrics.width));
alloc_field (item, val_id ("min_y"), alloc_int (g->metrics.horiBearingY - g->metrics.height));
alloc_field (item, val_id ("max_y"), alloc_int (g->metrics.horiBearingY));
alloc_field (item, val_id ("points"), points);
delete g;
}
alloc_field (ret, val_id ("glyphs"), neko_glyphs);
// 'kerning' field
if (FT_HAS_KERNING (face)) {
value neko_kerning = alloc_array (kern.size ());
for (i = 0; i < kern.size(); i++) {
kerning *k = &kern[i];
value item = alloc_empty_object();
val_array_set_i (neko_kerning,i,item);
alloc_field (item, val_id ("left_glyph"), alloc_int (k->l_glyph));
alloc_field (item, val_id ("right_glyph"), alloc_int (k->r_glyph));
alloc_field (item, val_id ("x"), alloc_int (k->x));
alloc_field (item, val_id ("y"), alloc_int (k->y));
}
alloc_field (ret, val_id ("kerning"), neko_kerning);
} else {
alloc_field (ret, val_id ("kerning"), alloc_null ());
}
return ret;
}
bool Font::InsertCodepoint (unsigned long codepoint) {
GlyphInfo info;
@@ -216,6 +533,31 @@ namespace lime {
}
void Font::LoadGlyphs (const char *glyphs) {
char *g = (char*)glyphs;
while (*g != 0) {
InsertCodepoint (readNextChar (g));
}
}
void Font::LoadRange (unsigned long start, unsigned long end) {
for (unsigned long codepoint = start; codepoint < end; codepoint++) {
InsertCodepoint (codepoint);
}
}
void Font::SetSize (size_t size) {
size_t hdpi = 72;
@@ -235,28 +577,6 @@ namespace lime {
}
void Font::LoadRange (unsigned long start, unsigned long end) {
for (unsigned long codepoint = start; codepoint < end; codepoint++) {
InsertCodepoint (codepoint);
}
}
void Font::LoadGlyphs (const char *glyphs) {
char *g = (char*)glyphs;
while (*g != 0) {
InsertCodepoint (readNextChar (g));
}
}
value Font::RenderToImage (ImageBuffer *image) {

View File

@@ -12,6 +12,7 @@ import haxe.io.Bytes;
import haxe.io.Path;
import helpers.LogHelper;
import helpers.ProcessHelper;
import lime.graphics.Font;
import project.Asset;
import project.AssetEncoding;
import project.AssetType;
@@ -295,10 +296,9 @@ class FlashHelper {
var src = name;
var font_name = Path.withoutExtension (name);
return false;
//var font = Font.load (src);
#if false
var face = new Font (src);
var font = face.decompose ();
var glyphs = new Array <Font2GlyphData> ();
var glyph_layout = new Array <FontLayoutGlyphData> ();
@@ -418,8 +418,6 @@ class FlashHelper {
}
})) );
#end
} else {
var bytes:Bytes = null;