Rename (and refactor) TextLayout, update GlyphMetrics

This commit is contained in:
Joshua Granick
2015-03-14 23:50:15 -07:00
parent 19ace78c33
commit 74592ed5bd
14 changed files with 415 additions and 293 deletions

View File

@@ -3,6 +3,7 @@ package lime.text;
import lime.graphics.Image;
import lime.graphics.ImageBuffer;
import lime.math.Vector2;
import lime.utils.ByteArray;
import lime.utils.UInt8Array;
import lime.system.System;
@@ -101,13 +102,10 @@ class Font {
var value = lime_font_get_glyph_metrics (__handle, glyph);
var metrics = new GlyphMetrics ();
metrics.advance = new Vector2 (value.horizontalAdvance, value.verticalAdvance);
metrics.height = value.height;
metrics.horizontalAdvance = value.horizontalAdvance;
metrics.horizontalBearingX = value.horizontalBearingX;
metrics.horizontalBearingY = value.horizontalBearingY;
metrics.verticalAdvance = value.verticalAdvance;
metrics.verticalBearingX = value.verticalBearingX;
metrics.verticalBearingY = value.verticalBearingY;
metrics.horizontalBearing = new Vector2 (value.horizontalBearingX, value.horizontalBearingY);
metrics.verticalBearing = new Vector2 (value.verticalBearingX, value.verticalBearingY);
return metrics;
#else

View File

@@ -1,7 +1,7 @@
package lime.text;
abstract Glyph(Int) from Int to Int {
abstract Glyph(Int) from Int to Int from UInt to UInt {
public function new (i:Int) {

View File

@@ -1,16 +1,16 @@
package lime.text;
import lime.math.Vector2;
class GlyphMetrics {
public var advance:Vector2;
public var height:Int;
public var horizontalAdvance:Int;
public var horizontalBearingX:Int;
public var horizontalBearingY:Int;
public var verticalAdvance:Int;
public var verticalBearingX:Int;
public var verticalBearingY:Int;
public var horizontalBearing:Vector2;
public var verticalBearing:Vector2;
public function new () {

View File

@@ -0,0 +1,32 @@
package lime.text;
import lime.math.Vector2;
class GlyphPosition {
public var advance:Vector2;
public var glyph:Glyph;
public var offset:Vector2;
public function new (glyph:Glyph, advance:Vector2, offset:Vector2 = null) {
this.glyph = glyph;
this.advance = advance;
if (offset != null) {
this.offset = offset;
} else {
this.offset = new Vector2 ();
}
}
}

View File

@@ -1,75 +0,0 @@
package lime.text;
import lime.system.System;
@:access(lime.text.Font)
class TextEngine {
public var direction (default, null):TextDirection;
public var language (default, null):String;
public var script (default, null):TextScript;
#if (cpp || neko || nodejs)
private var __handle:Dynamic;
#end
public function new (direction:TextDirection = LEFT_TO_RIGHT, script:TextScript = COMMON, language:String = "") {
this.direction = direction;
this.script = script;
this.language = language;
#if (cpp || neko || nodejs)
__handle = lime_text_engine_create (direction, script, language);
#end
this.direction = direction;
}
public function layout (font:Font, size:Int, text:String):Array<PosInfo> {
#if (cpp || neko || nodejs)
if (font.__handle == null) throw "Uninitialized font handle.";
return lime_text_engine_layout (__handle, font.__handle, size, text);
#else
return null;
#end
}
#if (cpp || neko || nodejs)
private static var lime_text_engine_create = System.load ("lime", "lime_text_engine_create", 3);
private static var lime_text_engine_layout = System.load ("lime", "lime_text_engine_layout", 4);
#end
}
typedef Point = {
var x:Float;
var y:Float;
};
typedef PosInfo = {
var codepoint:UInt;
var advance:Point;
var offset:Point;
};

224
lime/text/TextLayout.hx Normal file
View File

@@ -0,0 +1,224 @@
package lime.text;
import lime.math.Vector2;
import lime.system.System;
import lime.utils.ByteArray;
@:access(lime.text.Font)
class TextLayout {
public var direction (get, set):TextDirection;
public var font (default, set):Font;
public var glyphs (get, null):Array<Glyph>;
public var language (get, set):String;
public var positions (default, null):Array<GlyphPosition>;
public var script (get, set):TextScript;
public var size (default, set):Int;
public var text (default, set):String;
@:noCompletion private var __buffer:ByteArray;
@:noCompletion private var __direction:TextDirection;
@:noCompletion private var __handle:Dynamic;
@:noCompletion private var __language:String;
@:noCompletion private var __script:TextScript;
public function new (text:String = "", font:Font = null, size:Int = 12, direction:TextDirection = LEFT_TO_RIGHT, script:TextScript = COMMON, language:String = "en") {
this.text = text;
this.font = font;
this.size = size;
__direction = direction;
__script = script;
__language = language;
#if (cpp || neko || nodejs)
__handle = lime_text_layout_create (__direction, __script, __language);
#end
__position ();
}
@:noCompletion private function __position ():Void {
positions = [];
#if (cpp || neko || nodejs)
if (__handle != null && text != null && text != "" && font != null && font.__handle != null) {
if (__buffer == null) {
__buffer = new ByteArray ();
__buffer.bigEndian = false;
}
lime_text_layout_position (__handle, font.__handle, size, text, __buffer);
if (__buffer.length > 4) {
__buffer.position = 0;
var count = __buffer.readUnsignedInt ();
var index, advanceX, advanceY, offsetX, offsetY;
for (i in 0...count) {
index = __buffer.readUnsignedInt ();
advanceX = __buffer.readFloat ();
advanceY = __buffer.readFloat ();
offsetX = __buffer.readFloat ();
offsetY = __buffer.readFloat ();
positions.push (new GlyphPosition (index, new Vector2 (advanceX, advanceY), new Vector2 (offsetX, offsetY)));
}
}
}
#end
}
// Get & Set Methods
@:noCompletion private function get_direction ():TextDirection {
return __direction;
}
@:noCompletion private function set_direction (value:TextDirection):TextDirection {
__direction = value;
#if (cpp || neko || nodejs)
lime_text_layout_set_direction (__handle, value);
#end
__position ();
return value;
}
@:noCompletion private function set_font (value:Font):Font {
this.font = value;
__position ();
return value;
}
@:noCompletion private function get_glyphs ():Array<Glyph> {
var glyphs = [];
for (position in positions) {
glyphs.push (position.glyph);
}
return glyphs;
}
@:noCompletion private function get_language ():String {
return __language;
}
@:noCompletion private function set_language (value:String):String {
__language = value;
#if (cpp || neko || nodejs)
lime_text_layout_set_language (__handle, value);
#end
__position ();
return value;
}
@:noCompletion private function get_script ():TextScript {
return __script;
}
@:noCompletion private function set_script (value:TextScript):TextScript {
__script = value;
#if (cpp || neko || nodejs)
lime_text_layout_set_script (__handle, value);
#end
__position ();
return value;
}
@:noCompletion private function set_size (value:Int):Int {
this.size = value;
__position ();
return value;
}
@:noCompletion private function set_text (value:String):String {
this.text = value;
__position ();
return value;
}
// Native Methods
#if (cpp || neko || nodejs)
private static var lime_text_layout_create = System.load ("lime", "lime_text_layout_create", 3);
private static var lime_text_layout_position = System.load ("lime", "lime_text_layout_position", 5);
private static var lime_text_layout_set_direction = System.load ("lime", "lime_text_layout_set_direction", 2);
private static var lime_text_layout_set_language = System.load ("lime", "lime_text_layout_set_language", 2);
private static var lime_text_layout_set_script = System.load ("lime", "lime_text_layout_set_script", 2);
#end
}

View File

@@ -60,14 +60,13 @@
<compilerflag value="-DLIME_FREETYPE" />
<file name="src/text/Font.cpp" />
<file name="src/text/GlyphSet.cpp" />
<section if="LIME_HARFBUZZ">
<compilerflag value="-I${NATIVE_TOOLKIT_PATH}/harfbuzz/src" />
<compilerflag value="-DLIME_HARFBUZZ" />
<file name="src/text/TextEngine.cpp" />
<file name="src/text/TextLayout.cpp" />
</section>

View File

@@ -4,7 +4,6 @@
#include <graphics/ImageBuffer.h>
#include <system/System.h>
#include <text/GlyphSet.h>
#include <utils/Resource.h>
#include <hx/CFFI.h>

View File

@@ -1,44 +0,0 @@
#ifndef LIME_TEXT_GLYPH_SET_H
#define LIME_TEXT_GLYPH_SET_H
#include <hx/CFFI.h>
#include <utils/QuickVec.h>
#include <string>
namespace lime {
struct GlyphRange {
unsigned long start, end;
GlyphRange () : start (-1), end (-1) {}
GlyphRange (unsigned long start, unsigned long end) : start (start), end (end) {}
};
class GlyphSet {
public:
GlyphSet (std::wstring glyphs = NULL, unsigned long rangeStart = -1, unsigned long rangeEnd = -1);
GlyphSet (value glyphSet);
void AddGlyphs (std::wstring glyphs);
void AddRange (unsigned long start = 0, unsigned long end = -1);
std::wstring glyphs;
QuickVec<GlyphRange> ranges;
};
}
#endif

View File

@@ -1,35 +0,0 @@
#ifndef LIME_TEXT_TEXT_ENGINE_H
#define LIME_TEXT_TEXT_ENGINE_H
#include <text/Font.h>
#include <hx/CFFI.h>
namespace lime {
class TextEngine {
public:
TextEngine (int direction, const char *script, const char *language);
~TextEngine ();
value Layout (Font *font, size_t size, const char *text);
private:
void *mBuffer;
long mDirection;
long mScript;
long mLanguage;
};
}
#endif

View File

@@ -0,0 +1,49 @@
#ifndef LIME_TEXT_TEXT_LAYOUT_H
#define LIME_TEXT_TEXT_LAYOUT_H
#include <text/Font.h>
#include <utils/ByteArray.h>
namespace lime {
typedef struct {
uint32_t index;
float advanceX;
float advanceY;
float offsetX;
float offsetY;
} GlyphPosition;
class TextLayout {
public:
TextLayout (int direction, const char *script, const char *language);
~TextLayout ();
void Position (Font *font, size_t size, const char *text, ByteArray *bytes);
void SetDirection (int direction);
void SetLanguage (const char* language);
void SetScript (const char* script);
private:
void *mBuffer;
long mDirection;
long mScript;
long mLanguage;
};
}
#endif

View File

@@ -20,8 +20,7 @@
#include <graphics/RenderEvent.h>
#include <system/System.h>
#include <text/Font.h>
#include <text/GlyphSet.h>
#include <text/TextEngine.h>
#include <text/TextLayout.h>
#include <ui/KeyEvent.h>
#include <ui/Mouse.h>
#include <ui/MouseCursor.h>
@@ -542,10 +541,10 @@ namespace lime {
}
void lime_text_engine_destroy (value textHandle) {
void lime_text_layout_destroy (value textHandle) {
#ifdef LIME_HARFBUZZ
TextEngine *text = (TextEngine*)(intptr_t)val_float (textHandle);
TextLayout *text = (TextLayout*)(intptr_t)val_float (textHandle);
delete text;
text = 0;
#endif
@@ -553,13 +552,13 @@ namespace lime {
}
value lime_text_engine_create (value direction, value script, value language) {
value lime_text_layout_create (value direction, value script, value language) {
#if defined(LIME_FREETYPE) && defined(LIME_HARFBUZZ)
TextEngine *text = new TextEngine (val_int (direction), val_string (script), val_string (language));
TextLayout *text = new TextLayout (val_int (direction), val_string (script), val_string (language));
value v = alloc_float ((intptr_t)text);
val_gc (v, lime_text_engine_destroy);
val_gc (v, lime_text_layout_destroy);
return v;
#else
@@ -571,19 +570,51 @@ namespace lime {
}
value lime_text_engine_layout (value textHandle, value fontHandle, value size, value textString) {
value lime_text_layout_position (value textHandle, value fontHandle, value size, value textString, value data) {
#if defined(LIME_FREETYPE) && defined(LIME_HARFBUZZ)
TextEngine *text = (TextEngine*)(intptr_t)val_float (textHandle);
TextLayout *text = (TextLayout*)(intptr_t)val_float (textHandle);
Font *font = (Font*)(intptr_t)val_float (fontHandle);
return text->Layout (font, val_int (size), val_string (textString));
ByteArray bytes = ByteArray (data);
text->Position (font, val_int (size), val_string (textString), &bytes);
#else
#endif
return alloc_null ();
}
value lime_text_layout_set_direction (value textHandle, value direction) {
#if defined(LIME_FREETYPE) && defined(LIME_HARFBUZZ)
TextLayout *text = (TextLayout*)(intptr_t)val_float (textHandle);
text->SetDirection (val_int (direction));
#endif
return alloc_null ();
}
value lime_text_layout_set_language (value textHandle, value direction) {
#if defined(LIME_FREETYPE) && defined(LIME_HARFBUZZ)
TextLayout *text = (TextLayout*)(intptr_t)val_float (textHandle);
text->SetLanguage (val_string (direction));
#endif
return alloc_null ();
}
value lime_text_layout_set_script (value textHandle, value direction) {
#if defined(LIME_FREETYPE) && defined(LIME_HARFBUZZ)
TextLayout *text = (TextLayout*)(intptr_t)val_float (textHandle);
text->SetScript (val_string (direction));
#endif
return alloc_null ();
}
@@ -699,8 +730,11 @@ namespace lime {
DEFINE_PRIM (lime_renderer_flip, 1);
DEFINE_PRIM (lime_render_event_manager_register, 2);
DEFINE_PRIM (lime_system_gettimer, 0);
DEFINE_PRIM (lime_text_engine_create, 3);
DEFINE_PRIM (lime_text_engine_layout, 4);
DEFINE_PRIM (lime_text_layout_create, 3);
DEFINE_PRIM (lime_text_layout_position, 5);
DEFINE_PRIM (lime_text_layout_set_direction, 2);
DEFINE_PRIM (lime_text_layout_set_language, 2);
DEFINE_PRIM (lime_text_layout_set_script, 2);
DEFINE_PRIM (lime_touch_event_manager_register, 2);
DEFINE_PRIM (lime_update_event_manager_register, 2);
DEFINE_PRIM (lime_window_close, 1);

View File

@@ -1,89 +0,0 @@
#include <text/GlyphSet.h>
namespace lime {
static int id_end;
static int id_glyphs;
static int id_ranges;
static int id_start;
static bool init = false;
GlyphSet::GlyphSet (std::wstring glyphs, unsigned long rangeStart, unsigned long rangeEnd) {
//this->glyphs = 0;
//ranges = new QuickVec<GlyphRange> ();
if (!glyphs.empty ()) {
AddGlyphs (glyphs);
}
if (rangeStart > -1) {
AddRange (rangeStart, rangeEnd);
}
}
GlyphSet::GlyphSet (value glyphSet) {
if (!init) {
id_end = val_id ("end");
id_glyphs = val_id ("glyphs");
id_ranges = val_id ("ranges");
id_start = val_id ("start");
init = true;
}
if (!val_is_null (glyphSet)) {
value glyphs = val_field (glyphSet, id_glyphs);
if (!val_is_null (glyphs)) {
this->glyphs = val_wstring (glyphs);
}
value ranges = val_field (glyphSet, id_ranges);
int length = val_array_size (ranges);
for (int i = 0; i < length; i++) {
value range = val_array_i (ranges, i);
AddRange (val_int (val_field (range, id_start)), val_int (val_field (range, id_end)));
}
}
}
void GlyphSet::AddGlyphs (std::wstring glyphs) {
if (!glyphs.empty ()) {
this->glyphs += glyphs;
}
}
void GlyphSet::AddRange (unsigned long start, unsigned long end) {
ranges.push_back (GlyphRange (start, end));
}
}

View File

@@ -1,4 +1,5 @@
#include <text/TextEngine.h>
#include <system/System.h>
#include <text/TextLayout.h>
#include <ft2build.h>
#include FT_FREETYPE_H
@@ -9,7 +10,7 @@
namespace lime {
TextEngine::TextEngine (int direction, const char *script, const char *language) {
TextLayout::TextLayout (int direction, const char *script, const char *language) {
if (strlen (script) != 4) return;
@@ -25,14 +26,14 @@ namespace lime {
}
TextEngine::~TextEngine () {
TextLayout::~TextLayout () {
hb_buffer_destroy ((hb_buffer_t*)mBuffer);
}
value TextEngine::Layout (Font *font, size_t size, const char *text) {
void TextLayout::Position (Font *font, size_t size, const char *text, ByteArray *bytes) {
font->SetSize (size);
@@ -47,39 +48,68 @@ namespace lime {
hb_font_t *hb_font = hb_ft_font_create ((FT_Face)font->face, NULL);
hb_shape (hb_font, (hb_buffer_t*)mBuffer, NULL, 0);
unsigned int glyph_count;
uint32_t glyph_count;
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos ((hb_buffer_t*)mBuffer, &glyph_count);
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions ((hb_buffer_t*)mBuffer, &glyph_count);
float hres = 100;
value pos_info = alloc_array (glyph_count);
int posIndex = 0;
int glyphSize = sizeof(GlyphPosition);
uint32_t dataSize = 4 + (glyph_count * glyphSize);
if (bytes->Size() < dataSize) {
bytes->Resize (dataSize);
}
unsigned char* bytesPosition = bytes->Bytes ();
*(bytesPosition) = glyph_count;
bytesPosition += 4;
hb_glyph_position_t pos;
GlyphPosition *data;
for (int i = 0; i < glyph_count; i++) {
//font->InsertCodepointFromIndex(glyph_info[i].codepoint);
hb_glyph_position_t pos = glyph_pos[i];
pos = glyph_pos[i];
value obj = alloc_empty_object ();
alloc_field (obj, val_id ("codepoint"), alloc_float (glyph_info[i].codepoint));
data = (GlyphPosition*)(bytesPosition);
value advance = alloc_empty_object ();
alloc_field (advance, val_id ("x"), alloc_float (pos.x_advance / (float)(hres * 64)));
alloc_field (advance, val_id ("y"), alloc_float (pos.y_advance / (float)64));
alloc_field (obj, val_id ("advance"), advance);
data->index = glyph_info[i].codepoint;
data->advanceX = (float)(pos.x_advance / (float)(hres * 64));
data->advanceY = (float)(pos.y_advance / (float)64);
data->offsetX = (float)(pos.x_offset / (float)(hres * 64));
data->offsetY = (float)(pos.y_offset / (float)64);
value offset = alloc_empty_object ();
alloc_field (offset, val_id ("x"), alloc_float (pos.x_offset / (float)(hres * 64)));
alloc_field (offset, val_id ("y"), alloc_float (pos.y_offset / (float)64));
alloc_field (obj, val_id ("offset"), offset);
val_array_set_i (pos_info, posIndex++, obj);
bytesPosition += glyphSize;
}
hb_font_destroy (hb_font);
return pos_info;
}
void TextLayout::SetDirection (int direction) {
mDirection = (hb_direction_t)direction;
}
void TextLayout::SetLanguage (const char* language) {
mLanguage = (long)hb_language_from_string (language, strlen (language));
}
void TextLayout::SetScript (const char* script) {
mScript = hb_script_from_string (script, -1);
}