diff --git a/lime/text/Font.hx b/lime/text/Font.hx new file mode 100644 index 000000000..65f614781 --- /dev/null +++ b/lime/text/Font.hx @@ -0,0 +1,403 @@ +package lime.text; + + +import lime.graphics.Image; +import lime.graphics.ImageBuffer; +import lime.utils.ByteArray; +import lime.utils.UInt8Array; +import lime.system.System; + +#if (js && html5) +import js.html.CanvasElement; +import js.html.CanvasRenderingContext2D; +#end + +@:autoBuild(lime.Assets.embedFont()) + + +class Font { + + + public var fontName (default, null):String; + public var image:Image; + public var glyphs:Map>; + + @:noCompletion private var __fontPath:String; + @:noCompletion private var __handle:Dynamic; + + + public function new (fontName:String = null) { + + this.fontName = fontName; + this.glyphs = new Map> (); + + } + + + public function createImage ():ImageBuffer { + + glyphs = new Map> (); + + #if (js && html5) + + /* + if (__canvas == null) { + + __canvas = cast js.Browser.document.createElement ("canvas"); + __context = cast __canvas.getContext ("2d"); + + } + + __canvas.width = __canvas.height = 128; + __context.fillStyle = "#000000"; + __context.textBaseline = "top"; + __context.textAlign = "left"; + __context.font = size + "px " + fontFace; + + // canvas doesn't give the appropriate metrics so the values have to be padded... + var padding = size / 4; + + var x = 0.0, y = 0.0, i = 0; + + var height = size + padding; + + while (i < glyphs.length) { + + var c = glyphs.charAt(i++); + var metrics = __context.measureText (c); + var width = metrics.width + 4; // fudge because of incorrect text metrics + + if (x + width > __canvas.width) { + + y += height + 1; + x = 0; + + } + + if (y + height > __canvas.height) { + + if (__canvas.width < __canvas.height) { + + __canvas.width *= 2; + + } else { + + __canvas.height *= 2; + + } + + __context.clearRect (0, 0, __canvas.width, __canvas.height); + __context.textBaseline = "top"; + __context.textAlign = "left"; + __context.fillStyle = "#000000"; + __context.font = size + "px " + fontFace; + + glyphRects = new IntMap(); + x = y = i = 0; + continue; + + } + + __context.fillText (c, x + 2, y); + glyphRects.set(c, new GlyphRect(x, y, width, height, Std.int(width))); + + x += width; + + } + + var image = new js.html.Image (); + image.src = __canvas.toDataURL(); + return new Image (image, __canvas.width, __canvas.height);*/ + + #elseif flash + + /*var bd = new flash.display.BitmapData(128, 128, true, 0); + var tf = new flash.text.TextField (); + var format = new flash.text.TextFormat (); + format.size = size; + format.font = fontFace; + tf.defaultTextFormat = format; + // tf.embedFonts = true; + var mat = new flash.geom.Matrix (); + + var i = 0, x = 0.0, y = 0.0, maxHeight = 0.0; + + while (i < glyphs.length) { + + var c = glyphs.charAt(i++); + tf.text = c; + + if (x + tf.textWidth > bd.width) { + + y += maxHeight + 1; + x = maxHeight = 0; + + } + + if (y + tf.textHeight > bd.height) { + + if (bd.width < bd.height) { + + bd = new flash.display.BitmapData(bd.width * 2, bd.height, true, 0); + + } else { + + bd = new flash.display.BitmapData(bd.width, bd.height * 2, true, 0); + + } + + glyphRects = new IntMap(); + x = y = maxHeight = i = 0; + continue; + + } + + mat.identity (); + mat.translate (x, y); + bd.draw (tf, mat); + + glyphRects.set(c, new GlyphRect (x, y, tf.textWidth + 2, tf.textHeight + 2, Std.int(tf.textWidth + 2))); + + x += tf.textWidth + 4; + + if (tf.textHeight + 4 > maxHeight) { + + maxHeight = tf.textHeight + 4; + + } + + } + + return new ImageBuffer (bd, bd.width, bd.height);*/ + + #elseif (cpp || neko || nodejs) + + if (__handle == null) throw "Uninitialized font handle."; + var data = lime_font_create_image (__handle); + + if (data == null) { + + return null; + + } else { + + var glyphRects:Map; + + for (glyph in cast (data.glyphs, Array)) { + + if (glyphs.exists (glyph.size)) { + + glyphRects = glyphs.get (glyph.size); + + } else { + + glyphRects = new Map (); + glyphs.set (glyph.size, glyphRects); + + } + + glyphRects.set (glyph.codepoint, new GlyphRect (glyph.x, glyph.y, glyph.width, glyph.height, glyph.offset.x, glyph.offset.y)); + + } + + return new ImageBuffer (new UInt8Array (data.image.data), data.image.width, data.image.height, data.image.bpp); + + } + + #end + + return null; + + } + + + public function decompose ():NativeFontData { + + #if (cpp || neko || nodejs) + + if (__handle == null) throw "Uninitialized font handle."; + return lime_font_outline_decompose (__handle, 1024 * 20); + + #else + + return null; + + #end + + } + + + public static function fromBytes (bytes:ByteArray):Font { + + var font = new Font (); + font.__fromBytes (bytes); + return font; + + } + + + public static function fromFile (path:String):Font { + + var font = new Font (); + font.__fromFile (path); + return font; + + } + + + public function loadRange (size:Int, start:Int, end:Int) { + + #if (flash || js) + + // this.glyphs = glyphs; + + #elseif (cpp || neko || nodejs) + + if (__handle == null) throw "Uninitialized font handle."; + lime_font_load_range (__handle, size, start, end); + + #end + + } + + + public function loadGlyphs (size:Int, glyphs:String=null) { + + if (glyphs == null) { + + glyphs = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^`'\"/\\&*()[]{}<>|:;_-+=?,. "; + + } + + #if (flash || js) + + //this.glyphs = glyphs; + + #elseif (cpp || neko || nodejs) + + if (__handle == null) throw "Uninitialized font handle."; + lime_font_load_glyphs (__handle, size, glyphs); + + #end + + } + + + @:noCompletion private function __fromBytes (bytes:ByteArray):Void { + + __fontPath = null; + + #if (cpp || neko || nodejs) + + __handle = lime_font_load (bytes); + + if (__handle != null) { + + fontName = lime_font_get_family_name (__handle); + + } + + #end + + } + + + @:noCompletion private function __fromFile (path:String):Void { + + __fontPath = path; + + #if (cpp || neko || nodejs) + + __handle = lime_font_load (__fontPath); + + if (__handle != null) { + + fontName = lime_font_get_family_name (__handle); + + } + + #end + + } + + + #if (cpp || neko || nodejs) + private static var lime_font_get_family_name = System.load ("lime", "lime_font_get_family_name", 1); + private static var lime_font_load:Dynamic = System.load ("lime", "lime_font_load", 1); + 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 + + +} + + +class GlyphRect { + + + public var x:Float; + public var y:Float; + public var width:Float; + public var height:Float; + public var xOffset:Int; + public var yOffset:Int; + + + public function new (x:Float, y:Float, width:Float, height:Float, xOffset:Int=0, yOffset:Int=0) { + + this.x = x; + this.y = y; + this.xOffset = xOffset; + this.yOffset = yOffset; + this.width = width; + this.height = height; + + } + + +} + + +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; + var kerning:Array; + +} + + +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; + +} + + +typedef NativeKerningData = { + + var left_glyph:Int; + var right_glyph:Int; + var x:Int; + var y:Int; + +} diff --git a/lime/text/TextDirection.hx b/lime/text/TextDirection.hx new file mode 100644 index 000000000..1c8bdbd15 --- /dev/null +++ b/lime/text/TextDirection.hx @@ -0,0 +1,70 @@ +package lime.text; + + +@:enum abstract TextDirection(Int) to (Int) { + + + var INVALID = 0; + var LEFT_TO_RIGHT = 4; + var RIGHT_TO_LEFT = 5; + var TOP_TO_BOTTOM = 6; + var BOTTOM_TO_TOP = 7; + + + public var backward (get, never):Bool; + public var forward (get, never):Bool; + public var horizontal (get, never):Bool; + public var vertical (get, never):Bool; + + + public inline function reverse ():Void { + + this = this ^ 1; + + } + + + public inline function toString ():String { + + return switch (this) { + + case LEFT_TO_RIGHT: "leftToRight"; + case RIGHT_TO_LEFT: "rightToLeft"; + case TOP_TO_BOTTOM: "topToBottom"; + case BOTTOM_TO_TOP: "bottomToTop"; + default: ""; + + } + + } + + + private inline function get_backward ():Bool { + + return (this & ~2) == 5; + + } + + + private inline function get_forward ():Bool { + + return (this & ~2) == 4; + + } + + + private inline function get_horizontal ():Bool { + + return (this & ~1) == 4; + + } + + + private inline function get_vertical ():Bool { + + return (this & ~1) == 6; + + } + + +} \ No newline at end of file diff --git a/lime/text/TextFormat.hx b/lime/text/TextFormat.hx new file mode 100644 index 000000000..800bd964d --- /dev/null +++ b/lime/text/TextFormat.hx @@ -0,0 +1,65 @@ +package lime.text; + + +import lime.system.System; + +@:access(lime.text.Font) + + +class TextLayout { + + + public var direction(default, null):TextDirection; + + #if (cpp || neko || nodejs) + public var handle:Dynamic; + #end + + + public function new (direction:TextDirection, script:TextScript, language:String) { + + #if (cpp || neko || nodejs) + handle = lime_text_create (direction, script, language); + #end + + this.direction = direction; + + } + + + public function fromString (font:Font, size:Int, text:String):Array { + + #if (cpp || neko || nodejs) + + if (font.__handle == null) throw "Uninitialized font handle."; + return lime_text_from_string (handle, font.__handle, size, text); + + #else + + return null; + + #end + + } + + + #if (cpp || neko || nodejs) + private static var lime_text_create = System.load ("lime", "lime_text_create", 3); + private static var lime_text_from_string = System.load ("lime", "lime_text_from_string", 4); + #end + + +} + + +typedef Point = { + var x:Float; + var y:Float; +}; + + +typedef PosInfo = { + var codepoint:UInt; + var advance:Point; + var offset:Point; +}; \ No newline at end of file diff --git a/lime/text/TextLayout.hx b/lime/text/TextLayout.hx new file mode 100644 index 000000000..83a477b0d --- /dev/null +++ b/lime/text/TextLayout.hx @@ -0,0 +1,75 @@ +package lime.text; + + +import lime.system.System; + +@:access(lime.text.Font) + + +class TextLayout { + + + 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_layout_create (direction, script, language); + #end + + this.direction = direction; + + } + + + public function layout (font:Font, size:Int, text:String):Array { + + #if (cpp || neko || nodejs) + + if (font.__handle == null) throw "Uninitialized font handle."; + return lime_text_layout_layout (__handle, font.__handle, size, text); + + #else + + return null; + + #end + + } + + + #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_layout = System.load ("lime", "lime_text_layout_layout", 4); + #end + + +} + + +typedef Point = { + + var x:Float; + var y:Float; + +}; + + +typedef PosInfo = { + + var codepoint:UInt; + var advance:Point; + var offset:Point; + +}; \ No newline at end of file diff --git a/lime/text/TextScript.hx b/lime/text/TextScript.hx new file mode 100644 index 000000000..1298fc6d4 --- /dev/null +++ b/lime/text/TextScript.hx @@ -0,0 +1,162 @@ +package lime.text; + + +@:enum abstract TextScript(String) to (String) { + + var COMMON = "Zyyy"; + var INHERITED = "Zinh"; + var UNKNOWN = "Zzzz"; + + var ARABIC = "Arab"; + var ARMENIAN = "Armn"; + var BENGALI = "Beng"; + var CYRILLIC = "Cyrl"; + var DEVANAGARI = "Deva"; + var GEORGIAN = "Geor"; + var GREEK = "Grek"; + var GUJARATI = "Gujr"; + var GURMUKHI = "Guru"; + var HANGUL = "Hang"; + var HAN = "Hani"; + var HEBREW = "Hebr"; + var HIRAGANA = "Hira"; + var KANNADA = "Knda"; + var KATAKANA = "Kana"; + var LAO = "Laoo"; + var LATIN = "Latn"; + var MALAYALAM = "Mlym"; + var ORIYA = "Orya"; + var TAMIL = "Taml"; + var TELUGA = "Telu"; + var THAI = "Thai"; + + var TIBETAN = "Tibt"; + + var BOPOMOFO = "Bopo"; + var BRAILLE = "Brai"; + var CANADIAN_SYLLABICS = "Cans"; + var CHEROKEE = "Cher"; + var ETHIOPIC = "Ethi"; + var KHMER = "Khmr"; + var MONGOLIAN = "Mong"; + var MYANMAR = "Mymr"; + var OGHAM = "Ogam"; + var RUNIC = "Runr"; + var SINHALA = "Sinh"; + var SYRIAC = "Syrc"; + var THAANA = "Thaa"; + var YI = "Yiii"; + + var DESERET = "Dsrt"; + var GOTHIC = "Goth"; + var OLD_ITALIC = "Ital"; + + var BUHID = "Buhd"; + var HANUNOO = "Hano"; + var TAGALOG = "Tglg"; + var TAGBANWA = "Tagb"; + + var CYPRIOT = "Cprt"; + var LIMBU = "Limb"; + var LINEAR_B = "Linb"; + var OSMANYA = "Osma"; + var SHAVIAN = "Shaw"; + var TAI_LE = "Tale"; + var UGARITIC = "Ugar"; + + var BUGINESE = "Bugi"; + var COPTIC = "Copt"; + var GLAGOLITIC = "Glag"; + var KHAROSHTHI = "Khar"; + var NEW_TAI_LUE = "Talu"; + var OLD_PERSIAN = "Xpeo"; + var SYLOTI_NAGRI = "Sylo"; + var TIFINAGH = "Tfng"; + + var BALINESE = "Bali"; + var CUNEIFORM = "Xsux"; + var NKO = "Nkoo"; + var PHAGS_PA = "Phag"; + var PHOENICIAN = "Phnx"; + + var CARIAN = "Cari"; + var CHAM = "Cham"; + var KAYAH_LI = "Kali"; + var LEPCHA = "Lepc"; + var LYCIAN = "Lyci"; + var LYDIAN = "Lydi"; + var OL_CHIKI = "Olck"; + var REJANG = "Rjng"; + var SAURASHTRA = "Saur"; + var SUNDANESE = "Sund"; + var VAI = "Vaii"; + + var AVESTAN = "Avst"; + var BAMUM = "Bamu"; + var EGYPTIAN_HIEROGLYPHS = "Egyp"; + var IMPERIAL_ARAMAIC = "Armi"; + var INSCRIPTIONAL_PAHLAVI = "Phli"; + var INSCRIPTIONAL_PARTHIAN = "Prti"; + var JAVANESE = "Java"; + var KAITHI = "Kthi"; + var LISU = "Lisu"; + var MEETEI_MAYEK = "Mtei"; + var OLD_SOUTH_ARABIAN = "Sarb"; + var OLD_TURKIC = "Orkh"; + var SAMARITAN = "Samr"; + var TAI_THAM = "Lana"; + var TAI_VIET = "Tavt"; + + var BATAK = "Batk"; + var BRAHMI = "Brah"; + var MANDAIC = "Mand"; + + var CHAKMA = "Cakm"; + var MEROITIC_CURSIVE = "Merc"; + var MEROITIC_HIEROGLYPHS = "Mero"; + var MIAO = "Plrd"; + var SHARADA = "Shrd"; + var SORA_SOMPENG = "Sora"; + var TAKRI = "Takr"; + + var BASSA_VAH = "Bass"; + var CAUCASIAN_ALBANIAN = "Aghb"; + var DUPLOYAN = "Dupl"; + var ELBASAN = "Elba"; + var GRANTHA = "Gran"; + var KHOJKI = "Khoj"; + var KHUDAWADI = "Sind"; + var LINEAR_A = "Lina"; + var MAHAJANI = "Mahj"; + var MANICHAEAN = "Mani"; + var MENDE_KIKAKUI = "Mend"; + var MODI = "Modi"; + var MRO = "Mroo"; + var NABATAEAN = "Nbat"; + var OLD_NORTH_ARABIAN = "Narb"; + var OLD_PERMIC = "Perm"; + var PAHAWH_HMONG = "Hmng"; + var PALMYRENE = "Palm"; + var PAU_CIN_HAU = "Pauc"; + var PSALTER_PAHLAVI = "Phlp"; + var SIDDHAM = "Sidd"; + var TIRHUTA = "Tirh"; + var WARANG_CITI = "Wara"; + + + public var rightToLeft (get, never):Bool; + + + private inline function get_rightToLeft ():Bool { + + return switch (this) { + + case HEBREW, ARABIC, SYRIAC, THAANA, NKO, SAMARITAN, MANDAIC, IMPERIAL_ARAMAIC, PHOENICIAN, LYDIAN, CYPRIOT, KHAROSHTHI, OLD_SOUTH_ARABIAN, AVESTAN, INSCRIPTIONAL_PAHLAVI, PSALTER_PAHLAVI, OLD_TURKIC: true; + //case KURDISH: true; + default: false; + + } + + } + +} \ No newline at end of file diff --git a/project/Build.xml b/project/Build.xml index 6c845dd72..7be2f259d 100644 --- a/project/Build.xml +++ b/project/Build.xml @@ -59,14 +59,14 @@ - +
- +
diff --git a/project/include/graphics/Text.h b/project/include/graphics/Text.h deleted file mode 100644 index 43f77da85..000000000 --- a/project/include/graphics/Text.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef LIME_GRAPHICS_TEXT_H -#define LIME_GRAPHICS_TEXT_H - - -#include -#include - - -namespace lime { - - - class Font; - - - class Text { - - - public: - - Text (hb_tag_t direction, const char *script, const char *language); - ~Text (); - - value FromString (Font *font, size_t size, const char *text); - - private: - - hb_buffer_t *mBuffer; - hb_direction_t mDirection; - hb_script_t mScript; - hb_language_t mLanguage; - - - }; - - -} - - -#endif diff --git a/project/include/graphics/Font.h b/project/include/text/Font.h similarity index 59% rename from project/include/graphics/Font.h rename to project/include/text/Font.h index 7d843a1f5..a18edb081 100644 --- a/project/include/graphics/Font.h +++ b/project/include/text/Font.h @@ -1,20 +1,11 @@ -#ifndef LIME_GRAPHICS_FONT_H -#define LIME_GRAPHICS_FONT_H +#ifndef LIME_TEXT_FONT_H +#define LIME_TEXT_FONT_H +#include +#include #include #include -#include - -#ifdef LIME_FREETYPE -#include -#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 namespace lime { @@ -27,13 +18,8 @@ namespace lime { unsigned long codepoint; size_t size; - #ifdef LIME_FREETYPE - FT_UInt index; - FT_Pos height; - #else int index; int height; - #endif } GlyphInfo; @@ -43,25 +29,22 @@ namespace lime { public: - static Font *FromFile (const char *fontFace); + Font (void* face = 0); + Font (Resource *resource, int faceIndex = 0); + ~Font (); value Decompose (int em); - value GetFamilyName (); + wchar_t *GetFamilyName (); + bool InsertCodepointFromIndex (unsigned long codepoint); void LoadGlyphs (const char *glyphs); void LoadRange (unsigned long start, unsigned long end); value RenderToImage (ImageBuffer *image); void SetSize (size_t size); - bool InsertCodepointFromIndex (unsigned long codepoint); - - #ifdef LIME_FREETYPE - Font (FT_Face face); - FT_Face face; - #else + void* face; - #endif private: - + bool InsertCodepoint (unsigned long codepoint, bool b = true); std::list glyphList; diff --git a/project/include/text/TextLayout.h b/project/include/text/TextLayout.h new file mode 100644 index 000000000..7427a012a --- /dev/null +++ b/project/include/text/TextLayout.h @@ -0,0 +1,35 @@ +#ifndef LIME_TEXT_TEXT_LAYOUT_H +#define LIME_TEXT_TEXT_LAYOUT_H + + +#include +#include + + +namespace lime { + + + class TextLayout { + + + public: + + TextLayout (int direction, const char *script, const char *language); + ~TextLayout (); + + value Layout (Font *font, size_t size, const char *text); + + private: + + void *mBuffer; + int mDirection; + int mScript; + int mLanguage; + + }; + + +} + + +#endif \ No newline at end of file diff --git a/project/include/utils/ByteArray.h b/project/include/utils/ByteArray.h index 06bfa7c10..03172b12c 100644 --- a/project/include/utils/ByteArray.h +++ b/project/include/utils/ByteArray.h @@ -35,6 +35,7 @@ namespace lime { ByteArray (); ByteArray (struct _value *Value); ByteArray (const QuickVec &inValue); + ByteArray (const OSChar *inFilename); void Resize (int inSize); int Size() const; @@ -44,7 +45,6 @@ namespace lime { struct _value *mValue; - static ByteArray FromFile (const OSChar *inFilename); static int ToFile (const OSChar *inFilename, const ByteArray array); diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 695d98b7e..7c1aab6b5 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -15,14 +15,12 @@ #include