diff --git a/lime/Assets.hx b/lime/Assets.hx index 57f908388..12eb9e9c5 100644 --- a/lime/Assets.hx +++ b/lime/Assets.hx @@ -4,6 +4,7 @@ package lime; import haxe.Unserializer; import lime.graphics.Image; +import lime.graphics.Font; import lime.utils.ByteArray; @@ -456,11 +457,11 @@ class Assets { } - /*if (type == AssetType.FONT || type == null) { + if (type == AssetType.FONT || type == null) { if (cache.font.exists (id)) return true; - }*/ + } if (type == AssetType.SOUND || type == AssetType.MUSIC || type == null) { @@ -1100,13 +1101,13 @@ class AssetCache { public var enabled:Bool = true; public var image:Map; - //public var font:Map; + public var font:Map; public var sound:Map; public function new () { - //font = new Map (); + font = new Map (); image = new Map (); sound = new Map (); @@ -1117,7 +1118,7 @@ class AssetCache { if (prefix == null) { - //font = new Map (); + font = new Map (); image = new Map (); sound = new Map (); @@ -1135,7 +1136,7 @@ class AssetCache { } - /*var keys = font.keys (); + var keys = font.keys (); for (key in keys) { @@ -1145,7 +1146,7 @@ class AssetCache { } - }*/ + } var keys = sound.keys (); @@ -1462,22 +1463,22 @@ class Assets { #end var bytes = File.getBytes (path); - var resourceName = "NME_font_" + (classType.pack.length > 0 ? classType.pack.join ("_") + "_" : "") + classType.name; + var resourceName = "LIME_font_" + (classType.pack.length > 0 ? classType.pack.join ("_") + "_" : "") + classType.name; Context.addResource (resourceName, bytes); var fieldValue = { pos: position, expr: EConst(CString(resourceName)) }; fields.push ({ kind: FVar(macro :String, fieldValue), name: "resourceName", access: [ APublic, AStatic ], pos: position }); - //var constructor = macro { - // - //super(); - // - //fontName = resourceName; - // - //}; - // - //fields.push ({ name: "new", access: [ APublic ], kind: FFun({ args: [], expr: constructor, params: [], ret: null }), pos: Context.currentPos() }); + var constructor = macro { + + super(); + + fontName = resourceName; + + }; + + fields.push ({ name: "new", access: [ APublic ], kind: FFun({ args: [], expr: constructor, params: [], ret: null }), pos: Context.currentPos() }); return fields; diff --git a/lime/graphics/Font.hx b/lime/graphics/Font.hx index 7c013031b..4243979df 100644 --- a/lime/graphics/Font.hx +++ b/lime/graphics/Font.hx @@ -1,30 +1,205 @@ package lime.graphics; +import haxe.ds.StringMap; import lime.utils.UInt8Array; import lime.system.System; +#if js +import js.html.CanvasElement; +import js.html.CanvasRenderingContext2D; +#end + +typedef GlyphRect = { + var x:Float; + var y:Float; + var width:Float; + var height:Float; +} typedef GlyphData = { var image:Image; - var glyphs:Array; + var glyphs:StringMap; }; +@:autoBuild(lime.Assets.embedFont()) class Font { - #if (cpp || neko) - public var handle:Dynamic; + #if js + + private static var __canvas:CanvasElement; + private static var __context:CanvasRenderingContext2D; + + #elseif (cpp || neko) + + public var handle:GlyphRect; + #end + public var fontFace(default, null):String; + public function new (fontFace:String) { + this.fontFace = fontFace; + #if (cpp || neko) + handle = lime_font_load (fontFace); + #end } public function createImage (size:Int, glyphs:String="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^`'\"/\\&*()[]{}<>|:;_-+=?,. "):GlyphData { - #if (cpp || neko) + var glyphRects = new StringMap(); + + #if js + + 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 StringMap(); + x = y = i = 0; + continue; + + } + + __context.fillText (c, x + 2, y); + glyphRects.set(c, { + x: x, + y: y, + width: width, + height: height + }); + + x += width; + + } + + var image = new js.html.Image (); + image.src = __canvas.toDataURL(); + return { + glyphs: glyphRects, + image: new lime.graphics.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 StringMap(); + x = y = maxHeight = i = 0; + continue; + + } + + mat.identity (); + mat.translate (x, y); + bd.draw (tf, mat); + + glyphRects.set(c, { + x: x, + y: y, + width: tf.textWidth + 2, + height: tf.textHeight + 2 + }); + + x += tf.textWidth + 4; + + if (tf.textHeight + 4 > maxHeight) { + + maxHeight = tf.textHeight + 4; + + } + + } + + return { + glyphs: glyphRects, + image: new Image (bd, bd.width, bd.height) + } + + #elseif (cpp || neko) var data = lime_font_load_glyphs (handle, size, glyphs); @@ -34,8 +209,19 @@ class Font { } else { + for (glyph in cast (data.glyphs, Array)) { + + glyphRects.set (glyph.char, { + x: glyph.x, + y: glyph.y, + width: glyph.width, + height: glyph.height, + }); + + } + return { - glyphs: data.glyphs, + glyphs: glyphRects, image: new Image (new UInt8Array (data.image.data), data.image.width, data.image.height, data.image.bpp) }; @@ -43,8 +229,6 @@ class Font { #end - return null; - } #if (cpp || neko) diff --git a/templates/haxe/DefaultAssetLibrary.hx b/templates/haxe/DefaultAssetLibrary.hx index de7a21d88..266863fef 100644 --- a/templates/haxe/DefaultAssetLibrary.hx +++ b/templates/haxe/DefaultAssetLibrary.hx @@ -610,8 +610,8 @@ class DefaultAssetLibrary extends AssetLibrary { #elseif html5 -//::foreach assets::::if (type == "font")::@:keep class __ASSET__::flatName:: extends openfl.text.Font { #if (!openfl_html5_dom) public function new () { super (); fontName = "::id::"; } #end }::end:: -//::end:: +::foreach assets::::if (type == "font")::@:keep class __ASSET__::flatName:: extends lime.graphics.Font { public function new () { super ("::id::"); } }::end:: +::end:: #elseif (windows || mac || linux) @@ -621,7 +621,8 @@ class DefaultAssetLibrary extends AssetLibrary { //::elseif (type == "music")::@:sound("::sourcePath::") class __ASSET__::flatName:: extends openfl.media.Sound {} //::elseif (type == "font")::@:font("::sourcePath::") class __ASSET__::flatName:: extends openfl.text.Font {} //::else::@:file("::sourcePath::") class __ASSET__::flatName:: extends lime.utils.ByteArray {} -::end::::end::::end::::end:: +//::end::::end::::end:: +::end:: #end