From ca05d8994c0b5ea33b4285d50b6a955aa91fd134 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 10 Mar 2015 01:14:39 -0700 Subject: [PATCH] More work on Font API --- lime/graphics/Image.hx | 6 +- lime/text/Font.hx | 304 ++++------------- lime/text/Glyph.hx | 26 ++ lime/text/GlyphMetrics.hx | 26 +- project/include/text/Font.h | 9 +- project/src/ExternalInterface.cpp | 39 +-- project/src/text/Font.cpp | 544 ++++++++++++------------------ project/src/text/TextEngine.cpp | 2 +- 8 files changed, 337 insertions(+), 619 deletions(-) create mode 100644 lime/text/Glyph.hx diff --git a/lime/graphics/Image.hx b/lime/graphics/Image.hx index 26bb440c8..6650f7468 100644 --- a/lime/graphics/Image.hx +++ b/lime/graphics/Image.hx @@ -68,7 +68,7 @@ class Image { public var width:Int; - public function new (buffer:ImageBuffer = null, offsetX:Int = 0, offsetY:Int = 0, width:Int = 0, height:Int = 0, color:Null = null, type:ImageType = null) { + public function new (buffer:ImageBuffer = null, offsetX:Int = 0, offsetY:Int = 0, width:Int = -1, height:Int = -1, color:Null = null, type:ImageType = null) { this.offsetX = offsetX; this.offsetY = offsetY; @@ -953,13 +953,13 @@ class Image { if (buffer != null) { - if (width == 0) { + if (width == -1) { this.width = buffer.width; } - if (height == 0) { + if (height == -1) { this.height = buffer.height; diff --git a/lime/text/Font.hx b/lime/text/Font.hx index 91767ae83..50d3f302b 100644 --- a/lime/text/Font.hx +++ b/lime/text/Font.hx @@ -3,6 +3,8 @@ package lime.text; import lime.graphics.Image; import lime.graphics.ImageBuffer; +import lime.math.Vector2; +import lime.text.Glyph; import lime.utils.ByteArray; import lime.utils.UInt8Array; import lime.system.System; @@ -12,6 +14,7 @@ import js.html.CanvasElement; import js.html.CanvasRenderingContext2D; #end +@:access(lime.text.Glyph) @:autoBuild(lime.Assets.embedFont()) @@ -27,11 +30,6 @@ class Font { public var underlineThickness (get, null):Int; public var unitsPerEM (get, null):Int; - - - public var image:Image; - public var glyphs:Map>; - @:noCompletion private var __fontPath:String; @:noCompletion private var __handle:Dynamic; @@ -39,184 +37,6 @@ class Font { public function new (name:String = null) { this.name = name; - 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; } @@ -255,10 +75,38 @@ class Font { } - public function getGlyphMetrics (glyphs:GlyphSet):Array { + public function getGlyphMetrics (glyphs:GlyphSet = null):Map { + + if (glyphs == null) { + + glyphs = new GlyphSet ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^`'\"/\\&*()[]{}<>|:;_-+=?,. "); + + } #if (cpp || neko || nodejs) - return lime_font_get_glyph_metrics (__handle, glyphs); + var array:Array = lime_font_get_glyph_metrics (__handle, glyphs); + var map = new Map (); + + for (value in array) { + + var glyph = new Glyph (value.charCode, value.glyphIndex); + var metrics = new GlyphMetrics (); + + 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; + + glyph.metrics = metrics; + + map.set (glyph.glyphIndex, glyph); + + } + + return map; #else return null; #end @@ -266,41 +114,49 @@ class 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) { + public function renderGlyphs (fontSize:Int, glyphs:GlyphSet = null):Map { if (glyphs == null) { - glyphs = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^`'\"/\\&*()[]{}<>|:;_-+=?,. "; + glyphs = new GlyphSet ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^`'\"/\\&*()[]{}<>|:;_-+=?,. "); } - #if (flash || js) + #if (cpp || neko || nodejs) - //this.glyphs = glyphs; + var data = lime_font_create_images (__handle, fontSize, glyphs); - #elseif (cpp || neko || nodejs) - - if (__handle == null) throw "Uninitialized font handle."; - lime_font_load_glyphs (__handle, size, glyphs); + if (data == null) { + + return null; + + } else { + + var buffer = new ImageBuffer (new UInt8Array (data.image.data), data.image.width, data.image.height, data.image.bpp); + var map = new Map (); + + for (glyphData in cast (data.glyphs, Array)) { + + if (glyphData != null) { + + var glyph = new Glyph (glyphData.charCode, glyphData.glyphIndex); + glyph.image = new Image (buffer, glyphData.x, glyphData.y, glyphData.width, glyphData.height); + glyph.x = glyphData.offset.x; + glyph.y = glyphData.offset.y; + map.set (glyph.glyphIndex, glyph); + + } + + } + + return map; + + } #end + return null; + } @@ -444,9 +300,7 @@ class Font { private static var lime_font_get_underline_thickness = System.load ("lime", "lime_font_get_underline_thickness", 1); private static var lime_font_get_units_per_em = System.load ("lime", "lime_font_get_units_per_em", 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_create_images = System.load ("lime", "lime_font_create_images", 3); private static var lime_font_outline_decompose = System.load ("lime", "lime_font_outline_decompose", 2); #end @@ -454,32 +308,6 @@ class Font { } -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; diff --git a/lime/text/Glyph.hx b/lime/text/Glyph.hx new file mode 100644 index 000000000..223f0ffcc --- /dev/null +++ b/lime/text/Glyph.hx @@ -0,0 +1,26 @@ +package lime.text; + + +import lime.graphics.Image; + + +class Glyph { + + + public var charCode:Int; + public var glyphIndex:Int; + public var image:Image; + public var metrics:GlyphMetrics; + public var x:Int; + public var y:Int; + + + public function new (charCode:Int = 0, glyphIndex:Int = 0) { + + this.charCode = charCode; + this.glyphIndex = glyphIndex; + + } + + +} \ No newline at end of file diff --git a/lime/text/GlyphMetrics.hx b/lime/text/GlyphMetrics.hx index ab02c54b6..2e4b1ce2e 100644 --- a/lime/text/GlyphMetrics.hx +++ b/lime/text/GlyphMetrics.hx @@ -1,15 +1,23 @@ package lime.text; -typedef GlyphMetrics = { +class GlyphMetrics { + + + 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 function new () { + + + + } - var height:Int; - var horizontalAdvance:Int; - var horizontalBearingX:Int; - var horizontalBearingY:Int; - var index:Int; - var verticalAdvance:Int; - var verticalBearingX:Int; - var verticalBearingY:Int; } \ No newline at end of file diff --git a/project/include/text/Font.h b/project/include/text/Font.h index b54fac338..cd5841668 100644 --- a/project/include/text/Font.h +++ b/project/include/text/Font.h @@ -6,7 +6,6 @@ #include #include #include -#include namespace lime { @@ -31,6 +30,7 @@ namespace lime { Font (Resource *resource, int faceIndex = 0); ~Font (); + value CreateImages (int fontSize, GlyphSet *glyphSet, ImageBuffer *image); value Decompose (int em); int GetAscender (); int GetDescender (); @@ -41,19 +41,12 @@ namespace lime { int GetUnderlinePosition (); int GetUnderlineThickness (); int GetUnitsPerEM (); - 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); void* face; private: - bool InsertCodepoint (unsigned long codepoint, bool b = true); - - std::list glyphList; size_t mSize; }; diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 131d39b73..31e362617 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -120,13 +120,14 @@ namespace lime { } - value lime_font_create_image (value fontHandle) { + value lime_font_create_images (value fontHandle, value fontSize, value glyphSet) { #ifdef LIME_FREETYPE ImageBuffer image; Font *font = (Font*)(intptr_t)val_float (fontHandle); + GlyphSet glyphs = GlyphSet (glyphSet); value data = alloc_empty_object (); - alloc_field (data, val_id ("glyphs"), font->RenderToImage (&image)); + alloc_field (data, val_id ("glyphs"), font->CreateImages (val_int (fontSize), &glyphs, &image)); alloc_field (data, val_id ("image"), image.Value ()); return data; #else @@ -275,7 +276,7 @@ namespace lime { if (font) { value v = alloc_float ((intptr_t)font); - //val_gc (v, lime_font_destroy); + val_gc (v, lime_font_destroy); return v; } @@ -286,32 +287,6 @@ 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->SetSize (val_int (size)); - font->LoadGlyphs (val_string (glyphs)); - #endif - - return alloc_null (); - - } - - - value lime_font_load_range (value fontHandle, value size, value start, value end) { - - #ifdef LIME_FREETYPE - Font *font = (Font*)(intptr_t)val_float (fontHandle); - font->SetSize (val_int (size)); - font->LoadRange (val_int (start), val_int (end)); - #endif - - return alloc_null (); - - } - - value lime_font_outline_decompose (value fontHandle, value size) { #ifdef LIME_FREETYPE @@ -540,7 +515,7 @@ namespace lime { TextEngine *text = new TextEngine (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_engine_destroy); return v; #else @@ -649,7 +624,7 @@ namespace lime { DEFINE_PRIM (lime_application_quit, 1); DEFINE_PRIM (lime_application_update, 1); DEFINE_PRIM (lime_audio_load, 1); - DEFINE_PRIM (lime_font_create_image, 1); + DEFINE_PRIM (lime_font_create_images, 3); DEFINE_PRIM (lime_font_get_ascender, 1); DEFINE_PRIM (lime_font_get_descender, 1); DEFINE_PRIM (lime_font_get_family_name, 1); @@ -660,8 +635,6 @@ namespace lime { DEFINE_PRIM (lime_font_get_underline_thickness, 1); DEFINE_PRIM (lime_font_get_units_per_em, 1); 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_encode, 3); DEFINE_PRIM (lime_image_load, 1); diff --git a/project/src/text/Font.cpp b/project/src/text/Font.cpp index 9272e83aa..2bcfbcc52 100644 --- a/project/src/text/Font.cpp +++ b/project/src/text/Font.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #ifdef LIME_FREETYPE @@ -16,117 +17,6 @@ #endif -// 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))) - - -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... - - unsigned char c1, c2, *ptr = (unsigned char*) p; - unsigned long uc = 0; - int seqlen; - - 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 { @@ -269,12 +159,13 @@ namespace { namespace lime { + static int id_charCode; static int id_codepoint; + static int id_glyphIndex; static int id_height; static int id_horizontalAdvance; static int id_horizontalBearingX; static int id_horizontalBearingY; - static int id_index; static int id_offset; static int id_size; static int id_verticalAdvance; @@ -286,20 +177,6 @@ namespace lime { static bool init = false; - 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 && a.size < b.size; - - } - - static void initialize () { if (!init) { @@ -312,10 +189,11 @@ namespace lime { id_size = val_id ("size"); id_codepoint = val_id ("codepoint"); + id_charCode = val_id ("charCode"); + id_glyphIndex = val_id ("glyphIndex"); id_horizontalAdvance = val_id ("horizontalAdvance"); id_horizontalBearingX = val_id ("horizontalBearingX"); id_horizontalBearingY = val_id ("horizontalBearingY"); - id_index = val_id ("index"); id_verticalAdvance = val_id ("verticalAdvance"); id_verticalBearingX = val_id ("verticalBearingX"); id_verticalBearingY = val_id ("verticalBearingY"); @@ -463,6 +341,193 @@ namespace lime { } + value Font::CreateImages (int fontSize, GlyphSet *glyphSet, ImageBuffer *image) { + + initialize (); + + std::list charCodes = std::list (); + + if (!glyphSet->glyphs.empty ()) { + + FT_ULong charCode; + + for (unsigned int i = 0; i < glyphSet->glyphs.length (); i++) { + + charCodes.push_back (glyphSet->glyphs[i]); + + } + + } + + GlyphRange range; + + for (int i = 0; i < glyphSet->ranges.size (); i++) { + + range = glyphSet->ranges[i]; + + if (range.start == 0 && range.end == -1) { + + FT_UInt glyphIndex; + FT_ULong charCode = FT_Get_First_Char ((FT_Face)face, &glyphIndex); + + while (glyphIndex != 0) { + + charCodes.push_back (charCode); + charCode = FT_Get_Next_Char ((FT_Face)face, charCode, &glyphIndex); + + } + + } else { + + unsigned long end = range.end; + + FT_ULong charCode = range.start; + FT_UInt glyphIndex = FT_Get_Char_Index ((FT_Face)face, charCode); + + while (charCode <= end || end < 0) { + + if (glyphIndex > 0) { + + charCodes.push_back (charCode); + + } + + glyphIndex = -1; + charCode = FT_Get_Next_Char ((FT_Face)face, charCode, &glyphIndex); + + if (glyphIndex == 0) { + + break; + + } + + } + + } + + } + + charCodes.unique (); + + image->Resize (128, 128, 1); + int x = 0, y = 0, maxRows = 0; + unsigned char *bytes = image->data->Bytes (); + + value rects = alloc_array (charCodes.size ()); + int rectsIndex = 0; + + 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 ((FT_Face)face, 0, (int)(fontSize*64), (int)(hdpi * hres), vdpi); + FT_Set_Transform ((FT_Face)face, &matrix, NULL); + FT_UInt glyphIndex; + FT_ULong charCode; + + for (std::list::iterator it = charCodes.begin (); it != charCodes.end (); it++) { + + charCode = (*it); + glyphIndex = FT_Get_Char_Index ((FT_Face)face, charCode); + + FT_Load_Glyph ((FT_Face)face, glyphIndex, FT_LOAD_FORCE_AUTOHINT | FT_LOAD_DEFAULT); + + if (FT_Render_Glyph (((FT_Face)face)->glyph, FT_RENDER_MODE_NORMAL) != 0) continue; + + FT_Bitmap bitmap = ((FT_Face)face)->glyph->bitmap; + + if (x + bitmap.width > image->width) { + + y += maxRows + 1; + x = maxRows = 0; + + } + + if (y + bitmap.rows > image->height) { + + if (image->width < image->height) { + + image->width *= 2; + + } else { + + image->height *= 2; + + } + + image->Resize (image->width, image->height, 1); + rectsIndex = 0; + it = charCodes.begin (); + it--; + x = y = maxRows = 0; + continue; + + } + + if (image->bpp == 1) { + + image->Blit (bitmap.buffer, x, y, bitmap.width, bitmap.rows); + + } else { + + for (int row = 0; row < bitmap.rows; row++) { + + unsigned char *out = &bytes[((row + y) * image->width + x) * image->bpp]; + const unsigned char *line = &bitmap.buffer[row * bitmap.width]; // scanline + const unsigned char *const end = line + bitmap.width; + + while (line != end) { + + *out++ = 0xFF; + *out++ = 0xFF; + *out++ = 0xFF; + *out++ = *line; + + line++; + + } + + } + + } + + value v = alloc_empty_object (); + alloc_field (v, id_x, alloc_int (x)); + alloc_field (v, id_y, alloc_int (y)); + alloc_field (v, id_width, alloc_int (bitmap.width)); + alloc_field (v, id_height, alloc_int (bitmap.rows)); + + value offset = alloc_empty_object (); + alloc_field (offset, id_x, alloc_int (((FT_Face)face)->glyph->bitmap_left)); + alloc_field (offset, id_y, alloc_int (((FT_Face)face)->glyph->bitmap_top)); + alloc_field (v, id_offset, offset); + + alloc_field (v, id_charCode, alloc_int (charCode)); + alloc_field (v, id_glyphIndex, alloc_int (glyphIndex)); + //alloc_field (v, id_size, alloc_int ((*it).size)); + val_array_set_i (rects, rectsIndex++, v); + + x += bitmap.width + 1; + + if (bitmap.rows > maxRows) { + + maxRows = bitmap.rows; + + } + + } + + return rects; + + } + + value Font::Decompose (int em) { int result, i, j; @@ -696,17 +761,18 @@ namespace lime { } - void GetGlyphMetrics_Push (FT_Face face, FT_UInt glyphIndex, value glyphList) { + void GetGlyphMetrics_Push (FT_Face face, FT_ULong charCode, FT_UInt glyphIndex, value glyphList) { if (FT_Load_Glyph (face, glyphIndex, FT_LOAD_NO_BITMAP | FT_LOAD_FORCE_AUTOHINT | FT_LOAD_DEFAULT) == 0) { value metrics = alloc_empty_object (); + alloc_field (metrics, id_charCode, alloc_int (charCode)); + alloc_field (metrics, id_glyphIndex, alloc_int (glyphIndex)); alloc_field (metrics, id_height, alloc_int (((FT_Face)face)->glyph->metrics.height)); alloc_field (metrics, id_horizontalBearingX, alloc_int (((FT_Face)face)->glyph->metrics.horiBearingX)); alloc_field (metrics, id_horizontalBearingY, alloc_int (((FT_Face)face)->glyph->metrics.horiBearingY)); alloc_field (metrics, id_horizontalAdvance, alloc_int (((FT_Face)face)->glyph->metrics.horiAdvance)); - alloc_field (metrics, id_index, alloc_int (glyphIndex)); alloc_field (metrics, id_verticalBearingX, alloc_int (((FT_Face)face)->glyph->metrics.vertBearingX)); alloc_field (metrics, id_verticalBearingY, alloc_int (((FT_Face)face)->glyph->metrics.vertBearingY)); alloc_field (metrics, id_verticalAdvance, alloc_int (((FT_Face)face)->glyph->metrics.vertAdvance)); @@ -726,9 +792,12 @@ namespace lime { if (!glyphSet->glyphs.empty ()) { + FT_ULong charCode; + for (unsigned int i = 0; i < glyphSet->glyphs.length (); i++) { - GetGlyphMetrics_Push ((FT_Face)face, FT_Get_Char_Index ((FT_Face)face, glyphSet->glyphs[i]), glyphList); + charCode = glyphSet->glyphs[i]; + GetGlyphMetrics_Push ((FT_Face)face, charCode, FT_Get_Char_Index ((FT_Face)face, charCode), glyphList); } @@ -747,7 +816,7 @@ namespace lime { while (glyphIndex != 0) { - GetGlyphMetrics_Push ((FT_Face)face, glyphIndex, glyphList); + GetGlyphMetrics_Push ((FT_Face)face, charCode, glyphIndex, glyphList); charCode = FT_Get_Next_Char ((FT_Face)face, charCode, &glyphIndex); } @@ -756,15 +825,25 @@ namespace lime { unsigned long end = range.end; - if (end < 0) { - - end = ((FT_Face)face)->num_glyphs - 1; - - } + FT_ULong charCode = range.start; + FT_UInt glyphIndex = FT_Get_Char_Index ((FT_Face)face, charCode); - for (unsigned long i = range.start; i <= end; i++) { + while (charCode <= end || end < 0) { - GetGlyphMetrics_Push ((FT_Face)face, i, glyphList); + if (glyphIndex > 0) { + + GetGlyphMetrics_Push ((FT_Face)face, charCode, glyphIndex, glyphList); + + } + + glyphIndex = -1; + charCode = FT_Get_Next_Char ((FT_Face)face, charCode, &glyphIndex); + + if (glyphIndex == 0) { + + break; + + } } @@ -812,75 +891,6 @@ namespace lime { } - bool Font::InsertCodepoint (unsigned long codepoint, bool fromIndex) { - - GlyphInfo info; - info.codepoint = codepoint; - info.size = mSize; - - // search for duplicates, if any - std::list::iterator first = glyphList.begin (); - first = std::lower_bound (first, glyphList.end (), info, CompareGlyphCodepoint); - - // skip duplicates unless they are different sizes - // if (codepoint < (*first).codepoint || - // (codepoint == (*first).codepoint && mSize != (*first).size)) { - - if (fromIndex) { - - info.index = FT_Get_Char_Index ((FT_Face)face, codepoint); - - } else { - - info.index = codepoint; - - } - - if (FT_Load_Glyph ((FT_Face)face, info.index, FT_LOAD_DEFAULT) != 0) return false; - info.height = ((FT_Face)face)->glyph->metrics.height; - - glyphList.insert (first, info); - - return true; - - // } - - //return false; - - } - - - bool Font::InsertCodepointFromIndex (unsigned long codepoint) { - - return InsertCodepoint (codepoint, false); - - } - - - 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; @@ -901,124 +911,4 @@ namespace lime { } - value Font::RenderToImage (ImageBuffer *image) { - - initialize (); - - glyphList.sort (CompareGlyphHeight); - - image->Resize (128, 128, 1); - int x = 0, y = 0, maxRows = 0; - unsigned char *bytes = image->data->Bytes (); - - value rects = alloc_array (glyphList.size ()); - int rectsIndex = 0; - - 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) - }; - - for (std::list::iterator it = glyphList.begin (); it != glyphList.end (); it++) { - - // recalculate the character size for each glyph since it will vary - FT_Set_Char_Size ((FT_Face)face, 0, (int)((*it).size*64), (int)(hdpi * hres), vdpi); - FT_Set_Transform ((FT_Face)face, &matrix, NULL); - - FT_Load_Glyph ((FT_Face)face, (*it).index, FT_LOAD_DEFAULT); - - if (FT_Render_Glyph (((FT_Face)face)->glyph, FT_RENDER_MODE_NORMAL) != 0) continue; - - FT_Bitmap bitmap = ((FT_Face)face)->glyph->bitmap; - - if (x + bitmap.width > image->width) { - - y += maxRows + 1; - x = maxRows = 0; - - } - - if (y + bitmap.rows > image->height) { - - if (image->width < image->height) { - - image->width *= 2; - - } else { - - image->height *= 2; - - } - - image->Resize (image->width, image->height, 1); - rectsIndex = 0; - it = glyphList.begin (); - it--; - x = y = maxRows = 0; - continue; - - } - - if (image->bpp == 1) { - - image->Blit (bitmap.buffer, x, y, bitmap.width, bitmap.rows); - - } else { - - for (int row = 0; row < bitmap.rows; row++) { - - unsigned char *out = &bytes[((row + y) * image->width + x) * image->bpp]; - const unsigned char *line = &bitmap.buffer[row * bitmap.width]; // scanline - const unsigned char *const end = line + bitmap.width; - - while (line != end) { - - *out++ = 0xFF; - *out++ = 0xFF; - *out++ = 0xFF; - *out++ = *line; - - line++; - - } - - } - - } - - value v = alloc_empty_object (); - alloc_field (v, id_x, alloc_int (x)); - alloc_field (v, id_y, alloc_int (y)); - alloc_field (v, id_width, alloc_int (bitmap.width)); - alloc_field (v, id_height, alloc_int (bitmap.rows)); - - value offset = alloc_empty_object (); - alloc_field (offset, id_x, alloc_int (((FT_Face)face)->glyph->bitmap_left)); - alloc_field (offset, id_y, alloc_int (((FT_Face)face)->glyph->bitmap_top)); - alloc_field (v, id_offset, offset); - - alloc_field (v, id_codepoint, alloc_int ((*it).index)); - alloc_field (v, id_size, alloc_int ((*it).size)); - val_array_set_i (rects, rectsIndex++, v); - - x += bitmap.width + 1; - - if (bitmap.rows > maxRows) { - - maxRows = bitmap.rows; - - } - - } - - return rects; - - } - - } diff --git a/project/src/text/TextEngine.cpp b/project/src/text/TextEngine.cpp index 5809ffbeb..cd40e23ba 100644 --- a/project/src/text/TextEngine.cpp +++ b/project/src/text/TextEngine.cpp @@ -57,7 +57,7 @@ namespace lime { for (int i = 0; i < glyph_count; i++) { - font->InsertCodepointFromIndex(glyph_info[i].codepoint); + //font->InsertCodepointFromIndex(glyph_info[i].codepoint); hb_glyph_position_t pos = glyph_pos[i]; value obj = alloc_empty_object ();