From 93b20b38c0c59f803e8de161038c5297cb464c86 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 12 Mar 2015 21:26:18 -0700 Subject: [PATCH] Improve system for Font rendering, need to improve charCode -> glyphIndex mapping though --- lime/graphics/Image.hx | 2 + lime/text/Font.hx | 197 +++++++++++++-- lime/text/Glyph.hx | 6 +- project/include/system/System.h | 267 ++++++++++++++++++++ project/include/text/Font.h | 17 +- project/include/utils/stdint.h | 267 ++++++++++++++++++++ project/src/ExternalInterface.cpp | 72 ++++-- project/src/text/Font.cpp | 396 ++++++++++++++++-------------- 8 files changed, 989 insertions(+), 235 deletions(-) create mode 100644 project/include/utils/stdint.h diff --git a/lime/graphics/Image.hx b/lime/graphics/Image.hx index 6650f7468..ba7ffe57e 100644 --- a/lime/graphics/Image.hx +++ b/lime/graphics/Image.hx @@ -66,6 +66,8 @@ class Image { public var transparent (get, set):Bool; public var type:ImageType; public var width:Int; + public var x:Float; + public var y:Float; public function new (buffer:ImageBuffer = null, offsetX:Int = 0, offsetY:Int = 0, width:Int = -1, height:Int = -1, color:Null = null, type:ImageType = null) { diff --git a/lime/text/Font.hx b/lime/text/Font.hx index 50d3f302b..a3f8e5e6a 100644 --- a/lime/text/Font.hx +++ b/lime/text/Font.hx @@ -75,6 +75,17 @@ class Font { } + public function getCharIndex (char:String):Int { + + #if (cpp || neko || nodejs) + return lime_font_get_char_index (__handle, char); + #else + return -1; + #end + + } + + public function getGlyphMetrics (glyphs:GlyphSet = null):Map { if (glyphs == null) { @@ -89,7 +100,7 @@ class Font { for (value in array) { - var glyph = new Glyph (value.charCode, value.glyphIndex); + var glyph = new Glyph (value.charCode, value.index); var metrics = new GlyphMetrics (); metrics.height = value.height; @@ -102,7 +113,7 @@ class Font { glyph.metrics = metrics; - map.set (glyph.glyphIndex, glyph); + map.set (glyph.index, glyph); } @@ -114,41 +125,178 @@ class Font { } - public function renderGlyphs (fontSize:Int, glyphs:GlyphSet = null):Map { - - if (glyphs == null) { - - glyphs = new GlyphSet ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^`'\"/\\&*()[]{}<>|:;_-+=?,. "); - - } + public function renderGlyph (index:Int, fontSize:Int):Image { #if (cpp || neko || nodejs) - var data = lime_font_create_images (__handle, fontSize, glyphs); + lime_font_set_size (__handle, fontSize); - if (data == null) { + var bytes = new ByteArray (); + bytes.bigEndian = false; + + if (lime_font_render_glyph (__handle, index, bytes)) { - return null; + bytes.position = 0; - } else { + var index = bytes.readUnsignedInt (); + var width = bytes.readUnsignedInt (); + var height = bytes.readUnsignedInt (); + var x = bytes.readUnsignedInt (); + var y = bytes.readUnsignedInt (); - var buffer = new ImageBuffer (new UInt8Array (data.image.data), data.image.width, data.image.height, data.image.bpp); - var map = new Map (); + var data = new ByteArray (width * height); + bytes.readBytes (data, 0, width * height); - for (glyphData in cast (data.glyphs, Array)) { + var buffer = new ImageBuffer (new UInt8Array (data), width, height, 1); + var image = new Image (buffer, 0, 0, width, height); + image.x = x; + image.y = y; + + return image; + + } + + #end + + return null; + + } + + + public function renderGlyphs (indices:Array, fontSize:Int):Map { + + #if (cpp || neko || nodejs) + + lime_font_set_size (__handle, fontSize); + + var bytes = new ByteArray (); + bytes.bigEndian = false; + + if (lime_font_render_glyphs (__handle, indices, bytes)) { + + bytes.position = 0; + + var count = bytes.readUnsignedInt (); + + var bufferWidth = 128; + var bufferHeight = 128; + var offsetX = 0; + var offsetY = 0; + var maxRows = 0; + + var width, height; + var i = 0; + + while (i < count) { - if (glyphData != null) { + bytes.position += 4; + width = bytes.readUnsignedInt (); + height = bytes.readUnsignedInt (); + bytes.position += (4 * 2) + width * height; + + if (offsetX + width > bufferWidth) { - 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); + offsetY += maxRows + 1; + offsetX = 0; + maxRows = 0; + + } + + if (offsetY + height > bufferHeight) { + + if (bufferWidth < bufferHeight) { + + bufferWidth *= 2; + + } else { + + bufferHeight *= 2; + + } + + offsetX = 0; + offsetY = 0; + maxRows = 0; + + // TODO: make this better + + bytes.position = 4; + i = 0; + continue; + + } + + offsetX += width + 1; + + if (height > maxRows) { + + maxRows = height; + + } + + i++; + + } + + var map = new Map (); + var buffer = new ImageBuffer (null, bufferWidth, bufferHeight, 1); + var data = new ByteArray (bufferWidth * bufferHeight); + + bytes.position = 4; + offsetX = 0; + offsetY = 0; + maxRows = 0; + + var index, x, y, image; + + for (i in 0...count) { + + index = bytes.readUnsignedInt (); + width = bytes.readUnsignedInt (); + height = bytes.readUnsignedInt (); + x = bytes.readUnsignedInt (); + y = bytes.readUnsignedInt (); + + if (offsetX + width > bufferWidth) { + + offsetY += maxRows + 1; + offsetX = 0; + maxRows = 0; + + } + + for (i in 0...height) { + + data.position = ((i + offsetY) * bufferWidth) + offsetX; + //bytes.readBytes (data, 0, width); + + for (x in 0...width) { + + var byte = bytes.readUnsignedByte (); + data.writeByte (byte); + + } + + } + + image = new Image (buffer, offsetX, offsetY, width, height); + image.x = x; + image.y = y; + + map.set (index, image); + + offsetX += width + 1; + + if (height > maxRows) { + + maxRows = height; } } + buffer.data = new UInt8Array (data); + return map; } @@ -291,6 +439,7 @@ class Font { #if (cpp || neko || nodejs) private static var lime_font_get_ascender = System.load ("lime", "lime_font_get_ascender", 1); + private static var lime_font_get_char_index = System.load ("lime", "lime_font_get_char_index", 2); private static var lime_font_get_descender = System.load ("lime", "lime_font_get_descender", 1); private static var lime_font_get_family_name = System.load ("lime", "lime_font_get_family_name", 1); private static var lime_font_get_glyph_metrics = System.load ("lime", "lime_font_get_glyph_metrics", 2); @@ -300,8 +449,10 @@ 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_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); + private static var lime_font_render_glyph = System.load ("lime", "lime_font_render_glyph", 3); + private static var lime_font_render_glyphs = System.load ("lime", "lime_font_render_glyphs", 3); + private static var lime_font_set_size = System.load ("lime", "lime_font_set_size", 2); #end diff --git a/lime/text/Glyph.hx b/lime/text/Glyph.hx index 223f0ffcc..ef5aa1992 100644 --- a/lime/text/Glyph.hx +++ b/lime/text/Glyph.hx @@ -8,17 +8,17 @@ class Glyph { public var charCode:Int; - public var glyphIndex:Int; public var image:Image; + public var index:Int; public var metrics:GlyphMetrics; public var x:Int; public var y:Int; - public function new (charCode:Int = 0, glyphIndex:Int = 0) { + public function new (charCode:Int = -1, index:Int = -1) { this.charCode = charCode; - this.glyphIndex = glyphIndex; + this.index = index; } diff --git a/project/include/system/System.h b/project/include/system/System.h index 4ae2c5cee..358ad7f6e 100644 --- a/project/include/system/System.h +++ b/project/include/system/System.h @@ -44,4 +44,271 @@ namespace lime { } +#ifndef HX_WINDOWS +#include +#else + + +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#if _MSC_VER >= 1600 // [ +#include +#else // ] _MSC_VER >= 1600 [ + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with . +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +# define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +# define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + +#endif // _MSC_VER >= 1600 ] + +#endif // _MSC_STDINT_H_ ] +#endif + + #endif \ No newline at end of file diff --git a/project/include/text/Font.h b/project/include/text/Font.h index cd5841668..7f2725d26 100644 --- a/project/include/text/Font.h +++ b/project/include/text/Font.h @@ -3,6 +3,7 @@ #include +#include #include #include #include @@ -21,6 +22,18 @@ namespace lime { } GlyphInfo; + typedef struct { + + uint32_t index; + uint32_t width; + uint32_t height; + uint32_t x; + uint32_t y; + unsigned char data; + + } GlyphImage; + + class Font { @@ -30,9 +43,9 @@ namespace lime { Font (Resource *resource, int faceIndex = 0); ~Font (); - value CreateImages (int fontSize, GlyphSet *glyphSet, ImageBuffer *image); value Decompose (int em); int GetAscender (); + int GetCharIndex (char* character); int GetDescender (); wchar_t *GetFamilyName (); value GetGlyphMetrics (GlyphSet *glyphSet); @@ -41,6 +54,8 @@ namespace lime { int GetUnderlinePosition (); int GetUnderlineThickness (); int GetUnitsPerEM (); + int RenderGlyph (int index, ByteArray *bytes, int offset = 0); + int RenderGlyphs (value indices, ByteArray *bytes); void SetSize (size_t size); void* face; diff --git a/project/include/utils/stdint.h b/project/include/utils/stdint.h new file mode 100644 index 000000000..320e6c1f5 --- /dev/null +++ b/project/include/utils/stdint.h @@ -0,0 +1,267 @@ +#ifndef HX_WINDOWS +#include +#else + + +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#if _MSC_VER >= 1600 // [ +#include +#else // ] _MSC_VER >= 1600 [ + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with . +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +# define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +# define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + +#endif // _MSC_VER >= 1600 ] + +#endif // _MSC_STDINT_H_ ] + + +#endif \ No newline at end of file diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 31e362617..c626e380c 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -120,23 +120,6 @@ namespace lime { } - 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->CreateImages (val_int (fontSize), &glyphs, &image)); - alloc_field (data, val_id ("image"), image.Value ()); - return data; - #else - return alloc_null (); - #endif - - } - - void lime_font_destroy (value handle) { Font *font = (Font*)(intptr_t)val_float (handle); @@ -158,6 +141,18 @@ namespace lime { } + value lime_font_get_char_index (value fontHandle, value character) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)(intptr_t)val_float (fontHandle); + return alloc_int (font->GetCharIndex ((char*)val_wstring (character))); + #else + return alloc_int (-1); + #endif + + } + + value lime_font_get_descender (value fontHandle) { #ifdef LIME_FREETYPE @@ -299,6 +294,44 @@ namespace lime { } + value lime_font_render_glyph (value fontHandle, value index, value data) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)(intptr_t)val_float (fontHandle); + ByteArray bytes = ByteArray (data); + return alloc_bool (font->RenderGlyph (val_int (index), &bytes)); + #else + return alloc_bool (false); + #endif + + } + + + value lime_font_render_glyphs (value fontHandle, value indices, value data) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)(intptr_t)val_float (fontHandle); + ByteArray bytes = ByteArray (data); + return alloc_bool (font->RenderGlyphs (indices, &bytes)); + #else + return alloc_bool (false); + #endif + + } + + + value lime_font_set_size (value fontHandle, value fontSize) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)(intptr_t)val_float (fontHandle); + font->SetSize (val_int (fontSize)); + #endif + + return alloc_null (); + + } + + value lime_image_encode (value buffer, value type, value quality) { ImageBuffer imageBuffer = ImageBuffer (buffer); @@ -624,8 +657,8 @@ 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_images, 3); DEFINE_PRIM (lime_font_get_ascender, 1); + DEFINE_PRIM (lime_font_get_char_index, 2); DEFINE_PRIM (lime_font_get_descender, 1); DEFINE_PRIM (lime_font_get_family_name, 1); DEFINE_PRIM (lime_font_get_glyph_metrics, 2); @@ -636,6 +669,9 @@ namespace lime { DEFINE_PRIM (lime_font_get_units_per_em, 1); DEFINE_PRIM (lime_font_load, 1); DEFINE_PRIM (lime_font_outline_decompose, 2); + DEFINE_PRIM (lime_font_render_glyph, 3); + DEFINE_PRIM (lime_font_render_glyphs, 3); + DEFINE_PRIM (lime_font_set_size, 2); DEFINE_PRIM (lime_image_encode, 3); DEFINE_PRIM (lime_image_load, 1); DEFINE_PRIM (lime_jni_getenv, 0); diff --git a/project/src/text/Font.cpp b/project/src/text/Font.cpp index 2bcfbcc52..e88c01d4a 100644 --- a/project/src/text/Font.cpp +++ b/project/src/text/Font.cpp @@ -17,6 +17,117 @@ #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 { @@ -159,14 +270,18 @@ namespace { namespace lime { + static int id_buffer; static int id_charCode; static int id_codepoint; - static int id_glyphIndex; static int id_height; + static int id_index; static int id_horizontalAdvance; static int id_horizontalBearingX; static int id_horizontalBearingY; + static int id_image; static int id_offset; + static int id_offsetX; + static int id_offsetY; static int id_size; static int id_verticalAdvance; static int id_verticalBearingX; @@ -189,11 +304,15 @@ namespace lime { id_size = val_id ("size"); id_codepoint = val_id ("codepoint"); + id_buffer = val_id ("buffer"); 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_image = val_id ("image"); + id_index = val_id ("index"); + id_offsetX = val_id ("offsetX"); + id_offsetY = val_id ("offsetY"); id_verticalAdvance = val_id ("verticalAdvance"); id_verticalBearingX = val_id ("verticalBearingX"); id_verticalBearingY = val_id ("verticalBearingY"); @@ -341,193 +460,6 @@ 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; @@ -699,6 +631,15 @@ namespace lime { } + int Font::GetCharIndex (char* character) { + + long charCode = readNextChar (character); + + return FT_Get_Char_Index ((FT_Face)face, charCode); + + } + + int Font::GetDescender () { return ((FT_Face)face)->descender; @@ -768,7 +709,7 @@ namespace lime { 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_index, 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)); @@ -891,6 +832,81 @@ namespace lime { } + int Font::RenderGlyph (int index, ByteArray *bytes, int offset) { + + FT_Load_Glyph ((FT_Face)face, index, FT_LOAD_FORCE_AUTOHINT | FT_LOAD_DEFAULT); + + if (FT_Render_Glyph (((FT_Face)face)->glyph, FT_RENDER_MODE_NORMAL) == 0) { + + FT_Bitmap bitmap = ((FT_Face)face)->glyph->bitmap; + + int height = bitmap.rows; + int width = bitmap.width; + int pitch = bitmap.pitch; + + if (width == 0 || height == 0) return 0; + + uint32_t size = (4 * 5) + (width * height); + + if (bytes->Size() < size + offset) { + + bytes->Resize (size + offset); + + } + + GlyphImage *data = (GlyphImage*)(bytes->Bytes () + offset); + + data->index = index; + data->width = width; + data->height = height; + data->x = ((FT_Face)face)->glyph->bitmap_left; + data->y = ((FT_Face)face)->glyph->bitmap_top; + + unsigned char* position = &data->data; + + for (int i = 0; i < height; i++) { + + memcpy (position + (i * width), bitmap.buffer + (i * pitch), width); + + } + + return size; + + } + + return 0; + + } + + + int Font::RenderGlyphs (value indices, ByteArray *bytes) { + + int offset = 0; + int totalOffset = 4; + uint32_t count = 0; + + int numIndices = val_array_size (indices); + + for (int i = 0; i < numIndices; i++) { + + offset = RenderGlyph (val_int (val_array_i (indices, i)), bytes, totalOffset); + + if (offset > 0) { + + totalOffset += offset; + count++; + + } + + } + + *(bytes->Bytes ()) = count; + + return totalOffset; + + } + + void Font::SetSize (size_t size) { size_t hdpi = 72;