ecere/gfx/LFBDisplayDriver: Fixed up outlines
[sdk] / ecere / src / gfx / drivers / LFBDisplayDriver.ec
index 277fa02..04d7d68 100644 (file)
@@ -4,19 +4,23 @@ namespace gfx::drivers;
 #define ECERE_NOTRUETYPE
 #endif
 
+#undef __BLOCKS__
 #define uint _uint
+#define strlen _strlen
 #if !defined(ECERE_NOTRUETYPE)
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #include FT_TRUETYPE_TABLES_H
-#include <freetype/ttunpat.h>
+#include FT_UNPATENTED_HINTING_H
 #define property  _property
 #include "harfbuzz.h"
 #undef property
 
 #if defined(__WIN32__)
 #define WIN32_LEAN_AND_MEAN
+#define String _String
 #include <windows.h>
+#undef String
 #elif !defined(ECERE_NOTRUETYPE) && !defined(ECERE_NOFONTCONFIG)
 #define set _set
 #include <fontconfig/fontconfig.h>
@@ -26,6 +30,7 @@ static FcConfig * fcConfig;
 
 #endif
 #undef uint
+#undef strlen
 
 #ifdef __MSC__
 #pragma warning(disable:4244)
@@ -57,7 +62,97 @@ import "Direct3D9DisplayDriver"
 
 #if !defined(ECERE_NOTRUETYPE)
 
-static unichar UTF16GetChar(uint16 *string, int * nw)
+#if !defined(ECERE_VANILLA)
+import "edtaa3func"
+
+static void ComputeOutline(byte *out, byte *src, uint w, uint h, float size, float fade)
+{
+   uint i, numPixels = w * h;
+   short * distx = new short[2 * numPixels], * disty = distx + numPixels;
+   float * data = new0 float[4 * numPixels], * gx = data + numPixels, * gy = gx + numPixels, * dist = gy + numPixels;
+   float rb = Max(1.5f, size), ra = rb - (rb-1)*fade - 1;
+   float inv_rw = 1/(rb-ra);
+
+   for(i = 0; i < numPixels; i++)
+      data[i] = src[i] / 255.0f;
+
+   computegradient(data, w, h, gx, gy);
+   edtaa3(data, gx, gy, w, h, distx, disty, dist);
+
+   for(i = 0; i < numPixels; i++)
+   {
+      float value = 1 - Max(0.0f, Min(1.0f, (dist[i]-ra)*inv_rw));
+      out[i] = (byte)(255 * value * value);
+   }
+   delete distx;
+   delete data;
+}
+
+static void BlitOutline(byte * dst, int dx, int dy, int w, int h, byte * src, int sx, int sy, int sw, int sh, int srcStride)
+{
+   sh = Min(h - dy, sh);
+   sw = Min(w - dx, sw);
+   if(sw > 0 && sh > 0)
+   {
+      int y;
+      for(y = 0; y < sh; y++)
+         memcpy(dst + w * (dy+y) + dx, src + srcStride * (sy+y) + sx, sw);
+   }
+}
+
+static void MeasureOutline(byte * image, int w, int h, int * _x1, int * _y1, int * _x2, int * _y2)
+{
+   int x1 = MAXINT, y1 = MAXINT, x2 = MININT, y2 = MININT;
+   int x, y;
+   for(x = 0; x < w && x1 == MAXINT; x++)
+   {
+      for(y = 0; y < h; y++)
+         if(image[(y*w)+x])
+         {
+            x1 = x;
+            break;
+         }
+   }
+   for(x = w-1; x >= 0 && x2 == MININT; x--)
+   {
+      for(y = 0; y < h; y++)
+         if(image[(y*w)+x])
+         {
+            x2 = x;
+            break;
+         }
+   }
+   for(y = 0; y < h && y1 == MAXINT; y++)
+   {
+      for(x = 0; x < w; x++)
+         if(image[(y*w)+x])
+         {
+            y1 = y;
+            break;
+         }
+   }
+   for(y = h-1; y >= 0 && y2 == MININT; y--)
+   {
+      for(x = 0; x < w; x++)
+         if(image[(y*w)+x])
+         {
+            y2 = y;
+            break;
+         }
+   }
+   *_x1 = x1;
+   *_y1 = y1;
+   *_x2 = x2;
+   *_y2 = y2;
+}
+
+#endif
+
+#define MAX_FONT_LINK_ENTRIES   10
+
+static HB_Script theCurrentScript;
+
+static unichar UTF16GetChar(const uint16 *string, int * nw)
 {
    unichar ch;
    if(HB_IsHighSurrogate(string[0]) && HB_IsLowSurrogate(string[1]))
@@ -73,9 +168,9 @@ static unichar UTF16GetChar(uint16 *string, int * nw)
    return ch;
 }
 
-static HB_Bool hb_stringToGlyphs(HB_Font font, uint16 * string, uint length, HB_Glyph *glyphs, uint *numGlyphs, HB_Bool rightToLeft)
+static HB_Bool hb_stringToGlyphs(HB_Font font, const uint16 * string, uint length, HB_Glyph *glyphs, uint *numGlyphs, HB_Bool rightToLeft)
 {
-   FT_Face face = (FT_Face)font->userData;
+   FT_Face face = ((FontEntry)font->userData).face;
    int glyph_pos = 0;
    int c, nw;
 
@@ -93,14 +188,42 @@ static HB_Bool hb_stringToGlyphs(HB_Font font, uint16 * string, uint length, HB_
 
 static void hb_getAdvances(HB_Font font, const HB_Glyph * glyphs, uint numGlyphs, HB_Fixed *advances, int flags)
 {
+   FontEntry entry = font->userData;
+   Font glFont = entry.font;
    int c;
+   uint lastPack = 0;
+   GlyphPack pack = glFont.asciiPack;
+   int fontEntryNum;
+   for(fontEntryNum = 0; fontEntryNum < MAX_FONT_LINK_ENTRIES; fontEntryNum++)
+   {
+      if(glFont.fontEntries[fontEntryNum] == entry)
+         break;
+   }
+
    for(c = 0; c < numGlyphs; c++)
-      advances[c] = 0; // ### not tested right now
+   {
+      GlyphInfo * glyph;
+      uint glyphNo = glyphs[c] | 0x80000000 | (theCurrentScript << 24);
+      uint packNo = glyphNo & 0xFFFFFF80;
+      if(packNo != lastPack)
+      {
+         pack = (GlyphPack)glFont.glyphPacks.Find((uintptr)packNo);
+         if(!pack)
+         {
+            glFont.glyphPacks.Add((pack = GlyphPack { key = (uintptr)packNo }));
+            pack.Render(glFont, fontEntryNum, glFont.displaySystem);
+            pack.bitmap.alphaBlend = true;
+         }
+         lastPack = packNo;
+      }
+      glyph = &pack.glyphs[glyphNo & 0x7F];
+      advances[c] = glyph->ax;
+   }
 }
 
-static HB_Bool hb_canRender(HB_Font font, uint16 * string, uint length)
+static HB_Bool hb_canRender(HB_Font font, const uint16 * string, uint length)
 {
-   FT_Face face = (FT_Face)font->userData;
+   FT_Face face = ((FontEntry)font->userData).face;
    int c, nw;
 
    for (c = 0; c < length; c += nw)
@@ -122,7 +245,7 @@ static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB
         return HB_Err_Invalid_Argument;
 
     error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
-    *length = ftlen;
+    *length = (uint)ftlen;
     return (HB_Error)error;
 }
 
@@ -137,30 +260,70 @@ static HB_Error hb_getPointInOutline(HB_Font font, HB_Glyph glyph, int flags, hb
         return error;
 
     if (face->glyph->format != ft_glyph_format_outline)
-        return (HB_Error)HB_Err_Invalid_GPOS_SubTable;
+        return (HB_Error)HB_Err_Invalid_SubTable;
 
     *nPoints = face->glyph->outline.n_points;
     if (!(*nPoints))
         return HB_Err_Ok;
 
     if (point > *nPoints)
-        return (HB_Error)HB_Err_Invalid_GPOS_SubTable;
+        return (HB_Error)HB_Err_Invalid_SubTable;
 
-    *xpos = face->glyph->outline.points[point].x;
-    *ypos = face->glyph->outline.points[point].y;
+    *xpos = (int)face->glyph->outline.points[point].x;
+    *ypos = (int)face->glyph->outline.points[point].y;
 
     return HB_Err_Ok;
 }
 
-static void hb_getGlyphMetrics(HB_Font font, HB_Glyph glyph, HB_GlyphMetrics *metrics)
+static void hb_getGlyphMetrics(HB_Font font, HB_Glyph theGlyph, HB_GlyphMetrics *metrics)
 {
-    // ###
-    metrics->x = metrics->y = metrics->width = metrics->height = metrics->xOffset = metrics->yOffset = 0;
+   FontEntry entry = font->userData;
+   Font glFont = entry.font;
+   uint lastPack = 0;
+   GlyphPack pack = glFont.asciiPack;
+   int fontEntryNum;
+   for(fontEntryNum = 0; fontEntryNum < MAX_FONT_LINK_ENTRIES; fontEntryNum++)
+   {
+      if(glFont.fontEntries[fontEntryNum] == entry)
+         break;
+   }
+   {
+      GlyphInfo * glyph;
+      uint glyphNo = theGlyph | 0x80000000 | (theCurrentScript << 24);
+      uint packNo = glyphNo & 0xFFFFFF80;
+      if(packNo != lastPack)
+      {
+         pack = (GlyphPack)glFont.glyphPacks.Find((uintptr)packNo);
+         if(!pack)
+         {
+            pack = { key = (uintptr)packNo };
+            glFont.glyphPacks.Add(pack);
+            pack.Render(glFont, fontEntryNum, glFont.displaySystem);
+            pack.bitmap.alphaBlend = true;
+         }
+         lastPack = packNo;
+      }
+      glyph = &pack.glyphs[glyphNo & 0x7F];
+
+      metrics->x = glyph->ax;
+      metrics->y = 0;
+      metrics->width = glyph->w;
+      metrics->height = glyph->h;
+      metrics->xOffset = glyph->bx;
+      metrics->yOffset = glyph->by;
+   }
 }
 
 static HB_Fixed hb_getFontMetric(HB_Font font, HB_FontMetric metric)
 {
-    return 0; // ####
+   FontEntry entry = font->userData;
+   FT_Face face = entry.face;
+
+   // Note that we aren't scanning the VDMX table which we probably would in
+   // an ideal world.
+   if(metric == HB_FontAscent)
+      return face->ascender;
+   return 0;
 }
 
 static HB_FontClass hb_fontClass =
@@ -169,11 +332,11 @@ static HB_FontClass hb_fontClass =
    hb_getPointInOutline, hb_getGlyphMetrics, hb_getFontMetric
 };
 
-static uint FT_stream_load(FT_Stream stream, uint offset, byte * buffer, uint count)
+static uint FT_stream_load(FT_Stream stream, long offset, byte * buffer, long count)
 {
     File f = stream->descriptor.pointer;
-    f.Seek(offset, start);
-    return count ? f.Read(buffer, 1, count) : 0;
+    f.Seek((int)offset, start);
+    return count ? f.Read(buffer, 1, (uint)count) : 0;
 }
 
 static void FT_stream_close(FT_Stream stream)
@@ -188,7 +351,7 @@ static int numFonts;
 #undef CompareString
 static BinaryTree loadedFonts
 {
-   CompareKey = (void *)BinaryTree::CompareString 
+   CompareKey = (void *)BinaryTree::CompareString
 };
 
 class FontEntry : BTNode
@@ -199,14 +362,15 @@ class FontEntry : BTNode
 
    int used;
    byte * buffer;
-   
+
    //If we don't save the FT_Stream before sacrificing it to FreeType, the garbage collector (if one is used) will destroy it prematurely
    FT_Stream stream;
+   Font font;
+   float scale;
 
    ~FontEntry()
    {
-      char * fileName = (char *)key;
-      delete fileName;
+      delete (char *)key;
       delete buffer;
       if(hbFace)
          HB_FreeFace(hbFace);
@@ -222,6 +386,37 @@ class FontEntry : BTNode
       }
    }
 }
+
+static float FaceSetCharSize(FT_Face face, float size)
+{
+   float scale = 1;
+   if(FT_Set_Char_Size(face, (int)(size * 64), (int)(size * 64), 96, 96))
+   {
+      if(face->num_fixed_sizes)
+      {
+         int c;
+         int bestDiff = MAXINT, best = 0;
+         FT_Bitmap_Size * sizes = face->available_sizes;
+         int wishedHeight = (int)(size * 96 / 72);
+         for(c = 0; c < face->num_fixed_sizes; c++)
+         {
+            int diff = abs(sizes[c].height - wishedHeight);
+            if(diff < bestDiff)
+            {
+               best = c;
+               bestDiff = diff;
+            }
+         }
+         FT_Set_Pixel_Sizes(face, sizes[best].width, sizes[best].height);
+
+         if(!face->ascender)
+            face->ascender = sizes[best].height;
+         scale = (float)wishedHeight / sizes[best].height;
+      }
+   }
+   return scale;
+}
+
 #endif
 
 struct GlyphInfo
@@ -230,15 +425,17 @@ struct GlyphInfo
    int x, y;
    int w, h;
    int left, top;
+   int bx, by;
    int glyphNo;
+   float scale;
 };
 
-#define MAX_FONT_LINK_ENTRIES   10
-
 class GlyphPack : BTNode
 {
    GlyphInfo glyphs[256];
    Bitmap bitmap { };
+   BinaryTree outlines { };
+   int cellWidth, cellHeight;
 
    void Render(Font font, int startFontEntry, DisplaySystem displaySystem)
    {
@@ -249,8 +446,9 @@ class GlyphPack : BTNode
       int width, height;
       FontEntry fontEntry = null;
       FT_Face faces[128];
-      bool isGlyph = key & 0x80000000;
-      int curScript = (key & 0x7F000000) >> 24;
+      float scales[128];
+      bool isGlyph = ((uint)key & 0x80000000) != 0;
+      //int curScript = ((uint)key & 0x7F000000) >> 24;
       unichar testChar = 0;
       /*
       if(isGlyph)
@@ -262,7 +460,7 @@ class GlyphPack : BTNode
                // printf("\nRendering arabic in %s (%d)\n", font.faceName, key & 0xFFFFFF);
                break;
             case HB_Script_Devanagari:
-               testChar = 0x905; 
+               testChar = 0x905;
                break;
             case 60: testChar = 'あ'; break;
             case 61: testChar = 0x3400; break;
@@ -284,7 +482,7 @@ class GlyphPack : BTNode
       FT_Set_Char_Size( fontEntry.face, (int)(font.size * 64), (int)(font.size * 64), 96, 96);
       */
 
-      maxWidth = 0; 
+      maxWidth = 0;
       maxHeight = 0;
 
       for(c = 0; c < MAX_FONT_LINK_ENTRIES; c++)
@@ -294,7 +492,7 @@ class GlyphPack : BTNode
          {
             FT_Matrix matrix;
             FT_Vector pen = { 0, 0 };
-            
+
             if(font.fakeItalic)
             {
                matrix.xx = (FT_Fixed)( 1.0 * 0x10000L );
@@ -303,12 +501,22 @@ class GlyphPack : BTNode
                matrix.yy = (FT_Fixed)( 1.0 * 0x10000L );
                FT_Set_Transform(fontEntry.face, &matrix, &pen);
             }
-            FT_Set_Char_Size(fontEntry.face, (int)(font.size * 64), (int)(font.size * 64), 96, 96);
+            //FT_Set_Char_Size(fontEntry.face, (int)(font.size * 64), (int)(font.size * 64), 96, 96);
+            fontEntry.scale = FaceSetCharSize(fontEntry.face, font.size);
+            if(!font.scale)
+               font.scale = fontEntry.scale;
+            if(!c)
+            {
+               if(!fontEntry.face->units_per_EM)
+                  font.ascent = (int)((double)fontEntry.face->ascender);
+               else
+                  font.ascent = (int)((double)fontEntry.face->ascender * fontEntry.face->size->metrics.y_ppem / fontEntry.face->units_per_EM);
+            }
 
             fontEntry.hbFont.x_ppem  = fontEntry.face->size->metrics.x_ppem;
             fontEntry.hbFont.y_ppem  = fontEntry.face->size->metrics.y_ppem;
-            fontEntry.hbFont.x_scale = fontEntry.face->size->metrics.x_scale;
-            fontEntry.hbFont.y_scale = fontEntry.face->size->metrics.y_scale;
+            fontEntry.hbFont.x_scale = (int)fontEntry.face->size->metrics.x_scale;
+            fontEntry.hbFont.y_scale = (int)fontEntry.face->size->metrics.y_scale;
          }
       }
 
@@ -318,7 +526,7 @@ class GlyphPack : BTNode
          int entry = 0;
          if(isGlyph)
          {
-            uint glyph = (key | c) & 0xFFFFFF;
+            uint glyph = ((uint)key | c) & 0xFFFFFF;
             for(entry = startFontEntry; entry < MAX_FONT_LINK_ENTRIES; entry++)
             {
                fontEntry = font.fontEntries[entry];
@@ -326,7 +534,6 @@ class GlyphPack : BTNode
                {
                   if(!FT_Load_Glyph(fontEntry.face, glyph, FT_LOAD_DEFAULT /*FT_LOAD_NO_HINTING*/) || entry == MAX_FONT_LINK_ENTRIES-1 || !font.fontEntries[entry+1])
                   {
-                     
                      //printf("%s: Accepted entry %d ", font.faceName, entry);
                      break;
                   }
@@ -339,23 +546,30 @@ class GlyphPack : BTNode
             {
                uint glyph;
                fontEntry = font.fontEntries[entry];
-               if((glyph = FT_Get_Char_Index(fontEntry.face, (key | c) & 0xFFFFFF)) || entry == MAX_FONT_LINK_ENTRIES-1 || !font.fontEntries[entry+1])
+               if((glyph = FT_Get_Char_Index(fontEntry.face, ((uint)key | c) & 0xFFFFFF)) || entry == MAX_FONT_LINK_ENTRIES-1 || !font.fontEntries[entry+1])
                {
                   if(!FT_Load_Glyph(fontEntry.face, glyph, FT_LOAD_DEFAULT /*FT_LOAD_NO_HINTING*/) || entry == MAX_FONT_LINK_ENTRIES-1 || !font.fontEntries[entry+1])
                      break;
                }
             }
          }
+         scales[c] = fontEntry.scale;
          faces[c] = fontEntry.face;
-         maxWidth = Max(maxWidth, ((faces[c]->glyph->metrics.width + 64 + (64 - faces[c]->glyph->metrics.width & 0x3F)) >> 6));
-         maxHeight = Max(maxHeight, ((faces[c]->glyph->metrics.height + 64 + (64 - faces[c]->glyph->metrics.height & 0x3F)) >> 6));
+         maxWidth = Max(maxWidth, ((faces[c]->glyph->metrics.width + 64 + (64 - (faces[c]->glyph->metrics.width & 0x3F))) >> 6));
+         maxHeight = Max(maxHeight, ((faces[c]->glyph->metrics.height + 64 + (64 - (faces[c]->glyph->metrics.height & 0x3F))) >> 6));
          //maxHeight = Max(maxHeight, ((faces[c]->glyph->metrics.height) >> 6));
       }
-      cellWidth = maxWidth;
-      cellHeight = maxHeight;
+      this.cellWidth = cellWidth = maxWidth;
+      this.cellHeight = cellHeight = maxHeight;
 
-      width = pow2i(maxWidth * 16);
-      height = pow2i(maxHeight * 8);
+      width = maxWidth * 16;
+      height = maxHeight * 8;
+
+      if(true)
+      {
+         width = pow2i(height * 16);
+         height = pow2i(height * 8);
+      }
 
       if(bitmap.Allocate(null, width, height, 0, pixelFormatAlpha, false /*true*/))
       {
@@ -374,19 +588,19 @@ class GlyphPack : BTNode
             GlyphInfo * glyph = &glyphs[c];
             FT_GlyphSlot slot = faces[c]->glyph;
             double em_size = 1.0 * faces[c]->units_per_EM;
-            double x_scale = faces[c]->size->metrics.x_ppem / em_size;
-            double y_scale = faces[c]->size->metrics.y_ppem / em_size;
+            //double x_scale = faces[c]->size->metrics.x_ppem / em_size;
+            double y_scale = em_size ? (faces[c]->size->metrics.y_ppem / em_size) : 1;
             double ascender = faces[c]->ascender * y_scale;
-            int glyphNo = isGlyph ? ((key | c) & 0x00FFFFFF) : FT_Get_Char_Index(faces[c], key | c);
+            int glyphNo = isGlyph ? (((uint)key | c) & 0x00FFFFFF) : FT_Get_Char_Index(faces[c], (uint)key | c);
 
             FT_Load_Glyph(faces[c], glyphNo, /*FT_LOAD_DEFAULT | FT_LOAD_FORCE_AUTOHINT*/ FT_LOAD_DEFAULT /*FT_LOAD_NO_HINTING*/); // FT_LOAD_RENDER // FT_LOAD_NO_HINTING
-            
+
             FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
 
             x = sx;
             y = sy;
             //printf("%d, %d\n", maxHeight, faces[c]->size->metrics.height >> 6);
-            
+
             glyph->left = slot->bitmap_left;
             // glyph->top = ((64 + (64 - faces[c]->glyph->metrics.height & 0x3F)) >> 6) + (int)(ascender - slot->bitmap_top) + font.height - (faces[c]->size->metrics.height >> 6);
             // glyph->top = (int)(ascender - slot->bitmap_top) + 2 * (font.height - maxHeight);
@@ -400,9 +614,9 @@ class GlyphPack : BTNode
 
             //glyph->top = (int)(ascender - slot->bitmap_top); // + ((faces[c]->size->metrics.height >> 6) - (faces[0]->size->metrics.height >> 6)) + (font.height - (faces[c]->size->metrics.height >> 6));
             //glyph->top = (int)(ascender - slot->bitmap_top); // + ((faces[c]->size->metrics.height >> 6) - (faces[0]->size->metrics.height >> 6)) + (font.height - (faces[c]->size->metrics.height >> 6));
-            
+
             //glyph->top = (int)(ascender - slot->bitmap_top);// + (font.height - maxHeight);
-            glyph->top = (int)(ascender - slot->bitmap_top) + (font.height - (faces[c]->size->metrics.height >> 6)) / 2;
+            glyph->top = (int)(ascender - slot->bitmap_top) + (int)(font.height - (faces[c]->size->metrics.height >> 6)) / 2;
 
             // printf("[char: %d] mode: %d, width: %d, height: %d, pitch: %d\n", key + c, slot->bitmap.pixel_mode, slot->bitmap.width, slot->bitmap.rows, slot->bitmap.pitch);
             xMax = x + slot->bitmap.width;
@@ -411,7 +625,7 @@ class GlyphPack : BTNode
             {
                int total = 0;
                int numPixels = 0;
-               int max;
+               //int max;
                if(slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
                {
                   for(j = y, q = 0; j<yMax; j++)
@@ -428,7 +642,7 @@ class GlyphPack : BTNode
                      q += slot->bitmap.pitch;
                   }
                }
-               max = numPixels ? (total / numPixels) : 1;
+               //max = numPixels ? (total / numPixels) : 1;
 
                for(j = y, q = 0; j<yMax; j++)
                {
@@ -439,7 +653,7 @@ class GlyphPack : BTNode
                      {
                         picture[j * bitmap.stride + i] = (slot->bitmap.buffer[q + p] & bit) ? 255 : 0;
                         bit >>= 1;
-                        if(!bit) { bit = 0x80; p++; }                     
+                        if(!bit) { bit = 0x80; p++; }
                      }
                      else
                      {
@@ -455,9 +669,12 @@ class GlyphPack : BTNode
             glyph->w = slot->bitmap.width;
             glyph->h = slot->bitmap.rows;
             glyph->glyphNo = glyphNo;
+            glyph->bx = (int)faces[c]->glyph->metrics.horiBearingX;
+            glyph->by = (int)faces[c]->glyph->metrics.horiBearingY;
+            glyph->scale = scales[c];
 
-            glyph->ax = slot->advance.x;
-            glyph->ay = slot->advance.y + (64 - slot->advance.y % 64);
+            glyph->ax = (int)slot->advance.x;
+            glyph->ay = (int)(slot->advance.y + (64 - slot->advance.y % 64));
          }
          #if 0
          {
@@ -465,9 +682,9 @@ class GlyphPack : BTNode
             char fileName[256];
             static int fid = 0;
             for(c = 0; c<256; c++)
-               bitmap.palette[c] = ColorAlpha { 255, { c,c,c } };
+               bitmap.palette[c] = ColorAlpha { 255, { (byte)c,(byte)c,(byte)c } };
             bitmap.pixelFormat = pixelFormat8;
-            
+
             /*
             //strcpy(fileName, faceName);
             if(flags)
@@ -483,6 +700,7 @@ class GlyphPack : BTNode
 
          if(displaySystem && displaySystem.pixelFormat != pixelFormat4) // TODO: Add none PixelFormat
          {
+            bitmap.keepData = true; // For outlines
             displaySystem.Lock();
 #if defined(__WIN32__)
             // Is this check still required?
@@ -496,37 +714,170 @@ class GlyphPack : BTNode
       }
 #endif
    }
-}
 
-#if !defined(ECERE_NOTRUETYPE)
-default:
-HB_LineBreakClass HB_GetLineBreakClass(unichar ch)
-{
-   return 0; //(HB_LineBreakClass)QUnicodeTables::lineBreakClass(ch);
-}
+   void RenderOutline(GlyphPack outline, Font font, DisplaySystem displaySystem)
+   {
+#if !defined(ECERE_NOTRUETYPE) && !defined(ECERE_VANILLA)
+      unichar c;
+      int pCellWidth = this.cellWidth, pCellHeight = this.cellHeight;
+      int cellWidth, cellHeight;
+      int width, height;
+      uintptr key = outline.key;
+      float outlineSize = (float)(key >> 16);
+      float fade = ((uint32)key & 0xFFFF) / 255.f;
+      GlyphInfo * widest = null, * highest = null;
+      uint widestIndex = 0, highestIndex = 0;
+      GlyphInfo * glyph;
+      int minX1 = MAXINT, minY1 = MAXINT;
+      int maxX2 = MININT, maxY2 = MININT;
+      int timesBigger = 2;
+      byte * bigger = new byte[pCellWidth * pCellHeight * timesBigger*timesBigger];
+      byte * field = new byte[pCellWidth * pCellHeight * timesBigger*timesBigger];
+      int ox, oy;
+
+      // Test biggest glyphs to determine cell width & height:
+      for(c = 0; c < 128; c++)
+      {
+         glyph = &glyphs[c];
+         if(glyph->w > (widest ? widest->w : 0))
+            widest = glyph, widestIndex = c;
+         if(glyph->h > (highest ? highest->h : 0))
+            highest = glyph, highestIndex = c;
+      }
 
-void HB_GetUnicodeCharProperties(unichar ch, HB_CharCategory *category, int *combiningClass)
-{
-   *category = GetCharCategory(ch); //(HB_CharCategory)QChar::category(ch);
-   *combiningClass = 0; //QChar::combiningClass(ch);
-}
+      cellWidth = 0;
+      cellHeight = 0;
+      for(glyph = widest; glyph; glyph = (glyph == widest && glyph != highest) ? highest : null)
+      {
+         int index = (glyph == widest) ? widestIndex : highestIndex;
+         int x = (index & 0xF) * pCellWidth, y = (index >> 4) * pCellHeight;
+         int w = pCellWidth * timesBigger, h = pCellHeight * timesBigger;
+         int x1,y1,x2,y2;
 
-HB_CharCategory HB_GetUnicodeCharCategory(unichar ch)
-{
-  return GetCharCategory(ch);
-}
+         memset(bigger, 0, w * h);
+         BlitOutline(bigger, (w - pCellWidth)/2, (h - pCellHeight)/2, w, h, bitmap.picture, x, y, pCellWidth, pCellHeight, bitmap.width);
+         ComputeOutline(field, bigger, w, h, outlineSize, fade);
+         MeasureOutline(field, w, h, &x1, &y1, &x2, &y2);
+         minX1 = Min(minX1, x1);
+         minY1 = Min(minY1, y1);
+         maxX2 = Max(maxX2, x2);
+         maxY2 = Max(maxY2, y2);
+      }
+      {
+         int x1 = (timesBigger*pCellWidth - pCellWidth)  / 2,  x2 = x1 + pCellWidth-1;
+         int y1 = (timesBigger*pCellHeight - pCellHeight) / 2,  y2 = y1 + pCellHeight-1;
+         ox = -Max(0, x1 - minX1);
+         oy = -Max(0, y1 - minY1);
+         cellWidth  = pCellWidth  - ox + Max(0, (maxX2 > x2) ? (maxX2 - x2) : 0);
+         cellHeight = pCellHeight - oy + Max(0, (maxY2 > y2) ? (maxY2 - y2) : 0);
+      }
 
-int HB_GetUnicodeCharCombiningClass(unichar ch)
-{
-   return 0; // QChar::combiningClass(ch);
-}
+      width = cellWidth * 16;
+      height = cellHeight * 8;
+      if(true) //TEXTURES_MUST_BE_POWER_OF_2)
+      {
+          width = pow2i(width);
+          height = pow2i(height);
+      }
 
-uint16 HB_GetMirroredChar(uint16 ch)
-{
-   return 0; //QChar::mirroredChar(ch);
+      if(outline.bitmap.Allocate(null, width, height, 0, pixelFormatAlpha, false))
+      {
+         Bitmap bitmap = outline.bitmap;
+         byte * picture = (byte *)bitmap.picture;
+         memset(picture, 0, width * height);
+
+         for(c = 0; c < 128; c++)
+         {
+            GlyphInfo * glyph = &outline.glyphs[c];
+            int x1 = MAXINT, y1 = MAXINT, x2 = MININT, y2 = MININT;
+            int w = 0, h = 0;
+            memset(bigger, 0, cellWidth * cellHeight);
+            BlitOutline(bigger, -ox, -oy, cellWidth, cellHeight,
+                 this.bitmap.picture,
+                 (c & 0xF) * pCellWidth, (c >> 4) * pCellHeight,
+                 pCellWidth, pCellHeight,
+                 this.bitmap.width);
+
+            // Don't waste time on empty glyphs
+            if(glyphs[c].w)
+            {
+               ComputeOutline(field, bigger, cellWidth, cellHeight, outlineSize, fade);
+               MeasureOutline(field, cellWidth, cellHeight, &x1, &y1, &x2, &y2);
+               if(x2 > x1) w = x2-x1+1;
+               if(y2 > y1) h = y2-y1+1;
+            }
+            else
+               memset(field, 0, cellWidth * cellHeight);
+
+            glyph->x = (c & 0xF) * cellWidth;
+            glyph->y = (c >> 4)  * cellHeight;
+            BlitOutline(picture, glyph->x, glyph->y, width, height, field, 0, 0, cellWidth, cellHeight, cellWidth);
+
+            glyph->glyphNo = glyphs[c].glyphNo;
+            glyph->scale = glyphs[c].scale;
+            glyph->left = glyphs[c].left + ox;
+            glyph->top = glyphs[c].top + oy;
+            if(w) { glyph->x += x1; glyph->left += x1; }
+            if(h) { glyph->y += y1; glyph->top  += y1; }
+            glyph->w = w;
+            glyph->h = h;
+            glyph->bx = glyphs[c].bx;
+            glyph->by = glyphs[c].by;
+            glyph->ax = glyphs[c].ax;
+            glyph->ay = glyphs[c].ay;
+         }
+
+   #if 0
+         {
+            int c;
+            char fileName[256];
+            static int fid = 0;
+            for(c = 0; c<256; c++)
+               outline.bitmap.palette[c] = ColorAlpha { 255, { (byte)c,(byte)c,(byte)c } };
+            outline.bitmap.pixelFormat = pixelFormat8;
+
+            /*
+            //strcpy(fileName, faceName);
+            if(flags)
+               strcat(fileName, "Bold");
+            */
+            sprintf(fileName, "outline%d", fid++);
+            ChangeExtension(fileName, "pcx", fileName);
+
+            outline.bitmap.Save(fileName, null, 0);
+            outline.bitmap.pixelFormat = pixelFormatAlpha;
+         }
+
+         /*{
+            static int num = 0;
+            char fileName[MAX_LOCATION];
+
+            sprintf(fileName, "template%03d.png", num);
+            bitmap.Save(fileName, null, 0);
+            sprintf(fileName, "outline%03d.png", num++);
+            outline.bitmap.Save(fileName, null, 0);
+         }*/
+   #endif
+         if(displaySystem && displaySystem.pixelFormat != pixelFormat4) // TODO: Add none PixelFormat
+         {
+            displaySystem.Lock();
+#if defined(__WIN32__)
+            // Is this check still required?
+            if(displaySystem.driver == class(OpenGLDisplayDriver) ||
+               displaySystem.driver == class(Direct3D8DisplayDriver) ||
+               displaySystem.driver == class(Direct3D9DisplayDriver))
+#endif
+               bitmap.MakeDD(displaySystem);
+            displaySystem.Unlock();
+         }
+      }
+      delete bigger;
+      delete field;
+#endif
+   }
 }
-private:
 
+#if !defined(ECERE_NOTRUETYPE)
 static HB_ShaperItem shaper_item;
 
 static uint * shaping(FontEntry entry, uint16 * string, int len, HB_Script script, int *numGlyphs, bool * rightToLeft)
@@ -550,14 +901,14 @@ static uint * shaping(FontEntry entry, uint16 * string, int len, HB_Script scrip
    shaper_item.num_glyphs = shaper_item.item.length;
    shaper_item.glyphIndicesPresent = 0;
    shaper_item.initialGlyphCount = 0;
-   shaper_item.num_glyphs = 0;   
-   shaper_item.glyphs = null;   
+   shaper_item.num_glyphs = 0;
+   shaper_item.glyphs = null;
 
    while(!HB_ShapeItem(&shaper_item))
    {
       if(shaper_item.num_glyphs > maxGlyphs)
       {
-         maxGlyphs = shaper_item.num_glyphs;                                                                                                            
+         maxGlyphs = shaper_item.num_glyphs;
          glyphs = shaper_item.glyphs = renew0 glyphs HB_Glyph[maxGlyphs];
          shaper_item.attributes   = renew0 shaper_item.attributes HB_GlyphAttributes[maxGlyphs];
          shaper_item.advances     = renew0 shaper_item.advances HB_Fixed[maxGlyphs];
@@ -568,11 +919,11 @@ static uint * shaping(FontEntry entry, uint16 * string, int len, HB_Script scrip
       {
          shaper_item.glyphs = glyphs;
          shaper_item.num_glyphs = maxGlyphs;
-      } 
+      }
   }
 
    *numGlyphs = shaper_item.num_glyphs;
-   *rightToLeft = shaper_item.item.bidiLevel % 2;
+   *rightToLeft = (bool)(shaper_item.item.bidiLevel % 2);
    return shaper_item.glyphs;
 }
 
@@ -597,6 +948,9 @@ public class Font : struct
    int height;
    FontFlags flags;
    char faceName[512];
+   DisplaySystem displaySystem;
+   int ascent;
+   float scale;
 
    ~Font()
    {
@@ -609,6 +963,10 @@ public class Font : struct
       }
 #endif
    }
+   public property int ascent
+   {
+      get { return (int)(this ? ascent * scale : 0); }
+   }
 };
 
 public class LFBDisplay : struct
@@ -681,6 +1039,7 @@ public:
    bool opaqueText;
    int xOffset;
    bool writingText;
+   bool writingOutline;
 
    Bitmap bitmap;
 
@@ -714,34 +1073,35 @@ struct FontData
 {
    char fileName[MAX_FILENAME];
    FontFlags flags;
+   bool forgive;
 };
 
 static int CALLBACK MyFontProc(ENUMLOGFONTEX * font, NEWTEXTMETRICEX *lpntme, int fontType, LPARAM lParam)
 {
-   if(fontType == TRUETYPE_FONTTYPE)
+   //if(fontType == TRUETYPE_FONTTYPE)
    {
       FontData * fontData = (FontData *) lParam;
       char * fileName = (char *)lParam;
       HKEY key;
       int weight = (fontData->flags.bold) ? FW_BOLD : FW_NORMAL;
       int italic = (fontData->flags.italic) ? 1 : 0;
-      if(weight == font->elfLogFont.lfWeight && italic == (font->elfLogFont.lfItalic != 0))
+      if((fontData->forgive || weight == font->elfLogFont.lfWeight) && italic == (font->elfLogFont.lfItalic != 0))
       {
          if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",0,KEY_READ,&key) ||
             !RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts",0,KEY_READ,&key))
-         {  
+         {
             int value = 0;
             while(true)
             {
                char entryName[1024];
                char fontFileName[1024];
-               uint32 type;
-               int size = 1024;
-               int sizeFileName = 1024;
+               DWORD type;
+               DWORD size = 1024;
+               DWORD sizeFileName = 1024;
                char * occurence;
-               if(RegEnumValue(key, value++, entryName, &size, null, &type, fontFileName, &sizeFileName) != ERROR_SUCCESS)
+               if(RegEnumValue(key, value++, entryName, &size, null, (PDWORD)&type, (LPBYTE)fontFileName, &sizeFileName) != ERROR_SUCCESS)
                   break;
-               if((occurence = SearchString(entryName, 0, font->elfFullName, false, false)))
+               if((occurence = SearchString(entryName, 0, (const char *)font->elfFullName, false, false)))
                {
                   int c;
                   for(c = (int)(occurence - entryName) - 1; c >= 0; c--)
@@ -751,30 +1111,35 @@ static int CALLBACK MyFontProc(ENUMLOGFONTEX * font, NEWTEXTMETRICEX *lpntme, in
                      else if(ch != ' ') break;
                   }
                   if(c >= 0) continue;
-                  for(c = (int)(occurence - entryName) + strlen(font->elfFullName); ; c++)
+                  for(c = (int)(occurence - entryName) + strlen((char *)font->elfFullName); ; c++)
                   {
                      char ch = entryName[c];
                      if(ch == 0 || ch == '&' || ch == '(') { c = -1; break; }
                      else if(ch != ' ') break;
                   }
+
+                  if(atoi(entryName + c))
+                     c = -1;
                   if(c >= 0) continue;
 
                   strcpy(fileName, fontFileName);
                   RegCloseKey(key);
                   return 0;
-               }               
+               }
             }
             RegCloseKey(key);
             return 1;
          }
       }
    }
-   return 1;   
+   return 1;
 }
 #endif
 
+#if !defined(ECERE_NOTRUETYPE)
 static int utf16BufferSize = 0;
 static uint16 * utf16 = null;
+#endif
 
 public class LFBDisplayDriver : DisplayDriver
 {
@@ -810,7 +1175,7 @@ public class LFBDisplayDriver : DisplayDriver
             case 2: stride = width;                    break;
          }
       }
-      bitmap.stride = stride;   
+      bitmap.stride = stride;
       bitmap.width = width;
       bitmap.height = height;
       bitmap.size = (uint32) stride * (uint32)height;
@@ -847,7 +1212,7 @@ public class LFBDisplayDriver : DisplayDriver
    }
 
    bool ConvertBitmap(DisplaySystem displaySystem, Bitmap src, PixelFormat format, ColorAlpha * palette)
-   {  
+   {
       bool result = false;
       LFBSystem lfbSystem = displaySystem ? displaySystem.driverData : null;
 
@@ -860,7 +1225,7 @@ public class LFBDisplayDriver : DisplayDriver
                /*
                DWORD c;
                DWORD * picture = (DWORD *)src.picture;
-               
+
                for(c = 0; c<src.size; c++, picture++)
                {
                   if(*picture & 0xFFFFFF)
@@ -902,6 +1267,8 @@ public class LFBDisplayDriver : DisplayDriver
                   src.picture = bitmap.picture;
                   src.palette = bitmap.palette;
                   src.stride = bitmap.stride;
+                  src.size = bitmap.size;
+                  src.sizeBytes = bitmap.sizeBytes;
                   src.pixelFormat = bitmap.pixelFormat;
 
                   result = true;
@@ -1023,7 +1390,7 @@ public class LFBDisplayDriver : DisplayDriver
    {
       if(bitmap.pixelFormat != pixelFormatAlpha)
       {
-         if(!ConvertBitmap(displaySystem, bitmap, bitmap.alphaBlend ? pixelFormat888 : displaySystem.pixelFormat, null))
+         if(!ConvertBitmap(displaySystem, bitmap, /*bitmap.alphaBlend ? pixelFormat888 : */displaySystem.pixelFormat, null))
          {
             FreeBitmap(displaySystem, bitmap);
             return false;
@@ -1130,7 +1497,7 @@ public class LFBDisplayDriver : DisplayDriver
       LFBDisplay lfbDisplay = display ? display.driverData : null;
       LFBSurface lfbSurface = surface.driverData;
       uint index;
-      if(display) color = color /*& 0xFFFFFF*/;
+      //if(display) color = color & 0xFFFFFF;
       lfbSurface.foregroundRgb = color;
 
       if(lfbSurface.font && lfbDisplay)
@@ -1152,7 +1519,7 @@ public class LFBDisplayDriver : DisplayDriver
          case pixelFormat565:  lfbSurface.foreground = (Color565)color; break;
          case pixelFormat888:  lfbSurface.foreground = color; break;
          case pixelFormatRGBA: lfbSurface.foreground = (ColorRGBA)color; break;
-         case pixelFormatText: 
+         case pixelFormatText:
             if(display)
                lfbSurface.foreground = BestColorMatch(lfbDisplay.bitmap.palette,0,15,color) << 8;
             else
@@ -1165,7 +1532,7 @@ public class LFBDisplayDriver : DisplayDriver
    {
       LFBDisplay lfbDisplay = display ? display.driverData : null;
       LFBSurface lfbSurface = surface.driverData;
-      color = color /*& 0xFFFFFF*/;
+      //color = color & 0xFFFFFF;
       switch(lfbSurface.bitmap.pixelFormat)
       {
          case pixelFormat8:
@@ -1179,7 +1546,7 @@ public class LFBDisplayDriver : DisplayDriver
          case pixelFormat565:  lfbSurface.background = (Color565)color; break;
          case pixelFormat888:  lfbSurface.background = color; break;
          case pixelFormatRGBA: lfbSurface.background = (ColorRGBA)color; break;
-         case pixelFormatText: 
+         case pixelFormatText:
             if(display)
                lfbSurface.background = BestColorMatch(lfbDisplay.bitmap.palette,0,15,color) << 12;
             else
@@ -1379,7 +1746,7 @@ public class LFBDisplayDriver : DisplayDriver
                         ((uint16 *)lfbSurface.bitmap.picture)[offset]=(uint16)color;
                      else
                      {
-                        ((uint16 *)lfbSurface.bitmap.picture)[offset] = 
+                        ((uint16 *)lfbSurface.bitmap.picture)[offset] =
                            (((uint16 *)lfbSurface.bitmap.picture)[offset] & 0xF000) | (uint16)color;
                      }
                   }
@@ -1410,7 +1777,7 @@ public class LFBDisplayDriver : DisplayDriver
                break;
          }
       }
-      else 
+      else
       {
          if(x2 >= x1)
          {
@@ -1595,14 +1962,14 @@ public class LFBDisplayDriver : DisplayDriver
    void memset_32_aligned(void *buf, int val, int dwords)
    {
             // Qword align
-            if ((int)(buf) & 4) 
+            if ((int)(buf) & 4)
             {
                     *((uint32 *)(buf)) = val;
                     buf = ((uint32 *)(buf))+1;
                     dwords--;
             }
-    
-            if (dwords > 1) 
+
+            if (dwords > 1)
             {
                     __asm {
                             cld
@@ -1622,7 +1989,7 @@ public class LFBDisplayDriver : DisplayDriver
                             emms
                     };
             }
-    
+
             // Final dword
             if (dwords & 1) *((int*)(buf)) = val;
    }*/
@@ -1714,21 +2081,21 @@ public class LFBDisplayDriver : DisplayDriver
    void memset_32(void *buf, uint32 val, uint32 dwords)
    {
       int align = 0;
-      if ((uint32)(buf) & 3) 
+      if ((uint32)(buf) & 3)
       {
          align = 4;
          dwords--;
-         
+
          if (((uint32)(buf) & 1))
          {
-            *(byte *)(buf) = (byte)(val&0xFF); 
+            *(byte *)(buf) = (byte)(val&0xFF);
             buf = ((byte *)(buf))+1;
             val = ((val& 0xFF) << 24) || ((val& 0xFFFFFF00) >> 8);
             align --;
          }
          if (((uint32)(buf) & 2))
          {
-            *(uint16 *)(buf) = (uint16)(val&0xFFFF); 
+            *(uint16 *)(buf) = (uint16)(val&0xFFFF);
             buf = ((uint16 *)(buf))+1;
             val = ((val& 0xFFFF) << 16) || ((val& 0xFFFF0000) >> 16);
             align-=2;
@@ -1739,12 +2106,12 @@ public class LFBDisplayDriver : DisplayDriver
       {
          if (align == 1)
          {
-            *(byte *)(buf) = (byte)(val&0xFF); 
+            *(byte *)(buf) = (byte)(val&0xFF);
          }
          else
          {
-            *(uint16 *)(buf) = (uint16)(val&0xFFFF); 
-            if (align & 1) *((byte *)(buf)+2) = (byte)((val>>16)&0xFF); 
+            *(uint16 *)(buf) = (uint16)(val&0xFFFF);
+            if (align & 1) *((byte *)(buf)+2) = (byte)((val>>16)&0xFF);
          }
       }
    }
@@ -1775,7 +2142,7 @@ public class LFBDisplayDriver : DisplayDriver
       {
          int w,y;
          byte * theOffset;
-         
+
          w = x2-x1+1;
          if(w<1) return;
 
@@ -1799,7 +2166,7 @@ public class LFBDisplayDriver : DisplayDriver
             }
             else
             {
-               if(surface.background.a == 255 || lfbSurface.clearing)
+               if(!surface.blend || surface.background.a == 255 || lfbSurface.clearing)
                {
                   switch(GetColorDepthShifts(lfbSurface.bitmap.pixelFormat))
                   {
@@ -1836,7 +2203,7 @@ public class LFBDisplayDriver : DisplayDriver
                         {
                            int bla = (lfbSurface.bitmap.stride - w) * sizeof(uint32);
                            //memset_32((uint32 *) theOffset,color,w);
-                           /*_asm
+                           /-*_asm
                            {
                               push edi
                               push ecx
@@ -1850,14 +2217,14 @@ public class LFBDisplayDriver : DisplayDriver
                               mov eax,color
                               mov edx,y
                               mov ecx,w
-                              
+
                               start:
                                  push ecx
-                                 
+
                                  rep stosd
                                  add edi,ebx
                                  pop ecx
-                                 dec edx                        
+                                 dec edx
                                  jnz start
                               pop edx
                               pop ebx
@@ -1896,8 +2263,8 @@ public class LFBDisplayDriver : DisplayDriver
                         {
                            int c;
                            for(c = 0; c < w; c++, dest++)
-                           {                              
-                              Color destColor;
+                           {
+                              Color destColor = 0;
                               if(pixelFormat == pixelFormat565)      { destColor = (Color)*(Color565 *)dest; }
                               else if(pixelFormat == pixelFormat555) { destColor = (Color)*(Color555 *)dest; }
                               else if(pixelFormat == pixelFormat444) { destColor = (Color)*(Color444 *)dest; }
@@ -1934,7 +2301,7 @@ public class LFBDisplayDriver : DisplayDriver
                         {
                            int c;
                            for(c = 0; c < w; c++, dest++)
-                           {                              
+                           {
                               int dr = dest->color.r;
                               int dg = dest->color.g;
                               int db = dest->color.b;
@@ -2079,39 +2446,88 @@ public class LFBDisplayDriver : DisplayDriver
             int x, y;
             if(src.pixelFormat == pixelFormatAlpha)
             {
-               ColorAlpha * picture = ((ColorAlpha *)lfbSurface.bitmap.picture) + (lfbSurface.bitmap.stride * dy) + dx;
-               byte * source = ((byte *)src.picture) + (src.stride * sy) + sx;
-               ColorAlpha color = lfbSurface.writingText ? surface.foreground : surface.blitTint;
-               for(y = 0; y < h; y++)
+               if(lfbSurface.bitmap.pixelFormat == pixelFormat888)
                {
-                  for(x = 0; x < w; x++, picture++, source++)
+                  ColorAlpha * picture = ((ColorAlpha *)lfbSurface.bitmap.picture) + (lfbSurface.bitmap.stride * dy) + dx;
+                  byte * source = ((byte *)src.picture) + (src.stride * sy) + sx;
+                  ColorAlpha color = lfbSurface.writingText ? surface.foreground : surface.blitTint;
+                  for(y = 0; y < h; y++)
                   {
-                     int a = *source * color.a;
-                     ColorAlpha dest = *picture;
-                     int r = (a * color.color.r + ((255 * 255 - a) * dest.color.r)) / (255 * 255);
-                     int g = (a * color.color.g + ((255 * 255 - a) * dest.color.g)) / (255 * 255);
-                     int b = (a * color.color.b + ((255 * 255 - a) * dest.color.b)) / (255 * 255);
-                     if(r > 255) r = 255;
-                     if(g > 255) g = 255;
-                     if(b > 255) b = 255;
-                     picture->color = { (byte)r, (byte)g, (byte)b };
-                     if(alphaWrite == blend)
+                     for(x = 0; x < w; x++, picture++, source++)
                      {
-                        int ca = (a * 255 + (255 * 255 - a) * dest.a) / (255 * 255);
-                        if(ca > 255) ca = 255;
-                        picture->a = (byte)ca;
+                        int a = *source * color.a;
+                        ColorAlpha dest = *picture;
+                        int r = (a * color.color.r + ((255 * 255 - a) * dest.color.r)) / (255 * 255);
+                        int g = (a * color.color.g + ((255 * 255 - a) * dest.color.g)) / (255 * 255);
+                        int b = (a * color.color.b + ((255 * 255 - a) * dest.color.b)) / (255 * 255);
+                        if(r > 255) r = 255;
+                        if(g > 255) g = 255;
+                        if(b > 255) b = 255;
+                        picture->color = { (byte)r, (byte)g, (byte)b };
+                        if(alphaWrite == blend)
+                        {
+                           int ca = (a * 255 + (255 * 255 - a) * dest.a) / (255 * 255);
+                           if(ca > 255) ca = 255;
+                           picture->a = (byte)ca;
+                        }
+                        else if(alphaWrite)
+                           picture->a = (byte)(a / 255);
                      }
-                     else if(alphaWrite)
-                        picture->a = (byte)(a / 255);
+                     picture += lfbSurface.bitmap.stride - w;
+                     source += src.stride - w;
+                  }
+               }
+               else if(lfbSurface.bitmap.pixelFormat == pixelFormat555)
+               {
+                  Color555 * picture = ((Color555 *)lfbSurface.bitmap.picture) + (lfbSurface.bitmap.stride * dy) + dx;
+                  byte * source = ((byte *)src.picture) + (src.stride * sy) + sx;
+                  ColorAlpha color = lfbSurface.writingText ? surface.foreground : surface.blitTint;
+                  for(y = 0; y < h; y++)
+                  {
+                     for(x = 0; x < w; x++, picture++, source++)
+                     {
+                        int a = *source * color.a;
+                        Color dest = *picture;
+                        int r = (a * color.color.r + ((255 * 255 - a) * dest.r)) / (255 * 255);
+                        int g = (a * color.color.g + ((255 * 255 - a) * dest.g)) / (255 * 255);
+                        int b = (a * color.color.b + ((255 * 255 - a) * dest.b)) / (255 * 255);
+                        if(r > 255) r = 255;
+                        if(g > 255) g = 255;
+                        if(b > 255) b = 255;
+                        *picture = Color { (byte)r, (byte)g, (byte)b };
+                     }
+                     picture += lfbSurface.bitmap.stride - w;
+                     source += src.stride - w;
+                  }
+               }
+               else if(lfbSurface.bitmap.pixelFormat == pixelFormat565)
+               {
+                  Color565 * picture = ((Color565 *)lfbSurface.bitmap.picture) + (lfbSurface.bitmap.stride * dy) + dx;
+                  byte * source = ((byte *)src.picture) + (src.stride * sy) + sx;
+                  ColorAlpha color = lfbSurface.writingText ? surface.foreground : surface.blitTint;
+                  for(y = 0; y < h; y++)
+                  {
+                     for(x = 0; x < w; x++, picture++, source++)
+                     {
+                        int a = *source * color.a;
+                        Color dest = *picture;
+                        int r = (a * color.color.r + ((255 * 255 - a) * dest.r)) / (255 * 255);
+                        int g = (a * color.color.g + ((255 * 255 - a) * dest.g)) / (255 * 255);
+                        int b = (a * color.color.b + ((255 * 255 - a) * dest.b)) / (255 * 255);
+                        if(r > 255) r = 255;
+                        if(g > 255) g = 255;
+                        if(b > 255) b = 255;
+                        *picture = Color { (byte)r, (byte)g, (byte)b };
+                     }
+                     picture += lfbSurface.bitmap.stride - w;
+                     source += src.stride - w;
                   }
-                  picture += lfbSurface.bitmap.stride - w;
-                  source += src.stride - w;
                }
             }
             else
             {
                ColorAlpha * source = ((ColorAlpha *)src.picture) + (src.stride * sy) + sx;
-               if(lfbSurface.bitmap.pixelFormat == pixelFormat888)               
+               if(lfbSurface.bitmap.pixelFormat == pixelFormat888)
                {
                   ColorAlpha * picture = ((ColorAlpha *)lfbSurface.bitmap.picture) + (lfbSurface.bitmap.stride * dy) + dx;
                   for(y = 0; y < h; y++)
@@ -2168,11 +2584,11 @@ public class LFBDisplayDriver : DisplayDriver
                   {
                      for(x = 0; x < w; x++, picture++, source++)
                      {
-                        ColorAlpha src = *source;
+                        ColorAlpha psrc = *source;
                         Color555 dest = *picture;
-                        int r = src.a * src.color.r * 31 / 255 + ((255 - src.a) * dest.r);
-                        int g = src.a * src.color.g * 31 / 255 + ((255 - src.a) * dest.g);
-                        int b = src.a * src.color.b * 31 / 255 + ((255 - src.a) * dest.b);
+                        int r = psrc.a * psrc.color.r * 31 / 255 + ((255 - psrc.a) * dest.r);
+                        int g = psrc.a * psrc.color.g * 31 / 255 + ((255 - psrc.a) * dest.g);
+                        int b = psrc.a * psrc.color.b * 31 / 255 + ((255 - psrc.a) * dest.b);
                         if(r > 255 * 31) r = 255 * 31;
                         if(g > 255 * 31) g = 255 * 31;
                         if(b > 255 * 31) b = 255 * 31;
@@ -2201,7 +2617,7 @@ public class LFBDisplayDriver : DisplayDriver
       if(bitmap.pixelFormat != lfbDisplay.bitmap.pixelFormat || bitmap.width < w || bitmap.height < h)
       {
          bitmap.Free();
-         bitmap.Allocate(null, w,h,w, lfbDisplay.bitmap.pixelFormat, 
+         bitmap.Allocate(null, w,h,w, lfbDisplay.bitmap.pixelFormat,
             (lfbDisplay.bitmap.pixelFormat == pixelFormat8)?true:false);
       }
       if(bitmap)
@@ -2232,7 +2648,7 @@ public class LFBDisplayDriver : DisplayDriver
       {
          w = Abs(w);
          sw = Abs(sw);
-         flip = true; 
+         flip = true;
       }
 
       s2dw=(float)w / sw;
@@ -2308,7 +2724,7 @@ public class LFBDisplayDriver : DisplayDriver
             ColorAlpha * backsrc;
             ColorAlpha * source = ((ColorAlpha *) src.picture) + sy * addsource + sx;
             ColorAlpha * dest = ((ColorAlpha *) lfbSurface.bitmap.picture) + dy * adddest   + dx;
-            if(flip < 0) source += sw-1;
+            if(flip) source += sw-1;
             adddest -= w;
             yerr = 0;
             for(y=0; y<sh; y++)
@@ -2376,7 +2792,7 @@ public class LFBDisplayDriver : DisplayDriver
       {
          w = Abs(w);
          sw = Abs(sw);
-         flip = true; 
+         flip = true;
       }
 
       s2dw=(float)w / sw;
@@ -2446,10 +2862,7 @@ public class LFBDisplayDriver : DisplayDriver
          AlphaWriteMode alphaWrite = surface.alphaWrite;
          if(src.alphaBlend && surface.blend)
          {
-            int x, y;
-            uint xerr,yerr;
             uint adddest = lfbSurface.bitmap.stride, addsource = src.stride;
-            ColorAlpha * backsrc;
             ColorAlpha * source = ((ColorAlpha *) src.picture) + sy * addsource + sx;
             ColorAlpha * dest = ((ColorAlpha *) lfbSurface.bitmap.picture) + dy * adddest   + dx;
             float scaleX = (float)sw / w;
@@ -2475,7 +2888,6 @@ public class LFBDisplayDriver : DisplayDriver
                      int x0 = x * sw / w;
                      int x1 = Min(x0 + 1, sw - 1);
                      float beta = x * scaleX - x0;
-                     ColorAlpha color;
                      ColorAlpha src00, src01, src10, src11;
                      float a1,r1,g1,b1,a2,r2,g2,b2;
                      float a,r,g,b;
@@ -2514,12 +2926,12 @@ public class LFBDisplayDriver : DisplayDriver
                         else if(alphaWrite)
                            dest->a = (byte)a;
                      }
-                  } 
+                  }
                   dest += adddest;
                }
             }
-            else 
-            { 
+            else
+            {
                int y;
                for (y = 0; y < h; y++)
                {
@@ -2533,7 +2945,6 @@ public class LFBDisplayDriver : DisplayDriver
                      float a = 0, r = 0, g = 0, b = 0;
                      int numPixels = 0;
                      int i, j;
-                     ColorAlpha color;
                      for (i = y0; i <= y1; i++)
                         for (j = x0; j <= x1; j++)
                         {
@@ -2543,13 +2954,12 @@ public class LFBDisplayDriver : DisplayDriver
                            g += pixel.color.g;
                            b += pixel.color.b;
                            numPixels++;
-                        } 
+                        }
                      a /= numPixels;
                      r /= numPixels;
                      g /= numPixels;
                      b /= numPixels;
                      {
-                        ColorAlpha src = *source;
                         ColorAlpha dst = *dest;
                         int cr = (int)(a * r / 255 + ((255 - a) * dst.color.r / 255));
                         int cg = (int)(a * g / 255 + ((255 - a) * dst.color.g / 255));
@@ -2569,7 +2979,7 @@ public class LFBDisplayDriver : DisplayDriver
                      }
                   }
                   dest += adddest;
-               } 
+               }
             }
          }
          else if(!src.paletteShades && src.pixelFormat == lfbSurface.bitmap.pixelFormat)
@@ -2617,13 +3027,13 @@ public class LFBDisplayDriver : DisplayDriver
                   delete fontEntry;
                }
             }
-         } 
+         }
 #endif
          delete font;
       }
    }
 
-   Font LoadFont(DisplaySystem displaySystem, char * faceName, float size, FontFlags flags)
+   Font LoadFont(DisplaySystem displaySystem, const char * faceName, float size, FontFlags flags)
    {
       void * result = null;
 
@@ -2633,21 +3043,25 @@ public class LFBDisplayDriver : DisplayDriver
       {
          char fileName[MAX_LOCATION];
          bool fakeItalic = flags.italic;
-         char linkCfgPath[MAX_LOCATION];
          int fontID = 0;
 #if !defined(__WIN32__)
          File linkCfg;
 #endif
-         char * ecereFonts = getenv("ECERE_FONTS");
+         const char * ecereFonts = getenv("ECERE_FONTS");
          if(!ecereFonts) ecereFonts = "<:ecere>";
 #if !defined(__WIN32__)
-         strcpy(linkCfgPath, ecereFonts);
-         PathCat(linkCfgPath, "linking.cfg");
-         linkCfg = FileOpen(linkCfgPath, read);
+         {
+            char linkCfgPath[MAX_LOCATION];
+
+            strcpy(linkCfgPath, ecereFonts);
+            PathCat(linkCfgPath, "linking.cfg");
+            linkCfg = FileOpen(linkCfgPath, read);
+         }
 #endif
          strcpy(fileName, faceName);
          strcpy(font.faceName, faceName);
          font.flags = flags;
+         font.displaySystem = displaySystem;
 
          if(!FileExists(fileName))
          {
@@ -2659,7 +3073,7 @@ public class LFBDisplayDriver : DisplayDriver
             strcat(fileName, ".ttf");
             strlwr(fileName);
             fakeItalic = false;
-            
+
             if(flags.italic && !FileExists(fileName))
             {
                strcpy(fileName, ecereFonts);
@@ -2670,28 +3084,54 @@ public class LFBDisplayDriver : DisplayDriver
                fakeItalic = true;
             }
 
+            // Search in current working directory
+            if(!FileExists(fileName))
+            {
+               strcpy(fileName, faceName);
+               if(flags.bold && flags.italic) strcat(fileName, "bi");
+               else if(flags.bold) strcat(fileName, "bd");
+               else if(flags.italic) strcat(fileName, "i");
+               strcat(fileName, ".ttf");
+               strlwr(fileName);
+               fakeItalic = false;
+
+               if(flags.italic && !FileExists(fileName))
+               {
+                  strcpy(fileName, faceName);
+                  if(flags.bold) strcat(fileName, "bd");
+                  strcat(fileName, ".ttf");
+                  strlwr(fileName);
+                  fakeItalic = true;
+               }
+            }
+
    #if defined(__WIN32__)
             if(!FileExists(fileName))
             {
                FontData fontData = { { 0 } };
                LOGFONT logFont = { 0 };
                HDC hdc = GetDC(0);
-      
+
                fakeItalic = false;
-      
+
                logFont.lfCharSet = DEFAULT_CHARSET;
                strcpy(logFont.lfFaceName, faceName);
                fontData.flags = flags;
-                  
-               EnumFontFamiliesEx(hdc, &logFont, (void *)MyFontProc, (DWORD)&fontData, 0);
+
+               EnumFontFamiliesEx(hdc, &logFont, (void *)MyFontProc, (LPARAM)&fontData, 0);
+               if(!fontData.fileName[0] && flags.bold)
+               {
+                  fontData.forgive = true;
+                  EnumFontFamiliesEx(hdc, &logFont, (void *)MyFontProc, (LPARAM)&fontData, 0);
+               }
                if(!fontData.fileName[0])
                {
                   // Fake italic
                   fontData.flags.italic = false;
-                  EnumFontFamiliesEx(hdc, &logFont, (void *)MyFontProc, (DWORD)&fontData, 0);
+                  EnumFontFamiliesEx(hdc, &logFont, (void *)MyFontProc, (LPARAM)&fontData, 0);
                   fakeItalic = true;
                }
-      
+
                if(fontData.fileName[0])
                {
                   GetWindowsDirectory(fileName, MAX_LOCATION);
@@ -2699,8 +3139,8 @@ public class LFBDisplayDriver : DisplayDriver
                   PathCat(fileName, fontData.fileName);
                }
                ReleaseDC(0, hdc);
-            }  
-   #else
+            }
+   #elif !defined(ECERE_NOFONTCONFIG)
             {
                char * fileName2;
                FcResult result = 0;
@@ -2721,7 +3161,7 @@ public class LFBDisplayDriver : DisplayDriver
 
                if(testChar)
                   FcCharSetAddChar(charSet, testChar);
-   
+
                pattern = FcPatternBuild(null,
                                //FC_SOURCE, FcTypeString, "freetype",
                                FC_FAMILY, FcTypeString, faceName,
@@ -2738,13 +3178,13 @@ public class LFBDisplayDriver : DisplayDriver
                // printf("Locating %s\n", faceName);
                if(matched)
                {
-                  FcPatternGetString(matched, FC_FAMILY, 0, &family);
+                  FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family);
                   //printf("Fontconfig returned %s\n", family);
                }
                if(matched && (result == FcResultMatch /*|| result == FcResultNoId*/) /*&& !strcmpi(family, faceName)*/)
                {
                   double fontSize;
-                  FcPatternGetString (matched, FC_FILE, 0, &fileName2);
+                  FcPatternGetString (matched, FC_FILE, 0, (FcChar8 **)&fileName2);
                   FcPatternGetInteger(matched, FC_INDEX, 0, &fontID);
                   FcPatternGetDouble(matched, FC_SIZE, 0, &fontSize);
                   strcpy(fileName, fileName2);
@@ -2778,11 +3218,12 @@ public class LFBDisplayDriver : DisplayDriver
             links[0] = 0;
             if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink",0,KEY_READ,&key) ||
                !RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\FontLink\\SystemLink",0,KEY_READ,&key))
-            {  
-               int value = 0;
-               uint32 type;
-               int size = 1024;
-               RegQueryValueEx(key, faceName,null, &type, links, &size);
+            {
+               // int value = 0;
+               DWORD type;
+               DWORD size = 1024;
+               RegQueryValueEx(key, faceName, null, &type, (LPBYTE)links, &size);
+               memset(links + size, 0, 1024 - size);
                RegCloseKey(key);
             }
 #else
@@ -2823,11 +3264,11 @@ public class LFBDisplayDriver : DisplayDriver
                      FT_Open_Args args = { 0 };
                      FT_Parameter param = { FT_PARAM_TAG_UNPATENTED_HINTING };
                      FT_Stream stream = new0 FT_StreamRec[1];
-                     
+
                      if(!ftLibrary)
                         FT_Init_FreeType( &ftLibrary );
 
-                     fontEntry = FontEntry { key = (uint)CopyString(fileName) };
+                     fontEntry = FontEntry { key = (uintptr)CopyString(fileName) };
                      fontEntry.stream = stream;
 
                      /*
@@ -2857,7 +3298,7 @@ public class LFBDisplayDriver : DisplayDriver
                      {
                         fontEntry.hbFace = HB_NewFace(fontEntry.face, hb_getSFntTable);
                         fontEntry.hbFont.klass = &hb_fontClass;
-                        fontEntry.hbFont.userData = fontEntry.face;
+                        fontEntry.hbFont.userData = fontEntry; //.face;
 
                         numFonts++;
                         loadedFonts.Add(fontEntry);
@@ -2881,10 +3322,17 @@ public class LFBDisplayDriver : DisplayDriver
                         matrix.xy = (FT_Fixed)( 0.3 * 0x10000L );
                         matrix.yx = (FT_Fixed)( 0.0 * 0x10000L );
                         matrix.yy = (FT_Fixed)( 1.0 * 0x10000L );
-                        FT_Set_Transform(fontEntry.face, &matrix, &pen );
                      }
-                     FT_Set_Char_Size( fontEntry.face, (int)(size * 64), (int)(size * 64), 96, 96);
-                     font.height = ((fontEntry.face->size->metrics.height) >> 6); //* y_scale;
+                     else
+                     {
+                        matrix.xx = (FT_Fixed)( 1.0 * 0x10000L );
+                        matrix.xy = (FT_Fixed)( 0.0 * 0x10000L );
+                        matrix.yx = (FT_Fixed)( 0.0 * 0x10000L );
+                        matrix.yy = (FT_Fixed)( 1.0 * 0x10000L );
+                     }
+                     FT_Set_Transform(fontEntry.face, &matrix, &pen );
+                     FaceSetCharSize(fontEntry.face, size);
+                     font.height = (int)((fontEntry.face->size->metrics.height) >> 6); //* y_scale;
                      // printf("Font height is %d\n", font.height);
                      font.fakeItalic = fakeItalic;
                      font.size = size;
@@ -2911,7 +3359,7 @@ public class LFBDisplayDriver : DisplayDriver
                      GetWindowsDirectory(fileName, MAX_LOCATION);
                      PathCat(fileName, "fonts");
                      PathCat(fileName, fontName);
-#elif defined(ECERE_NOFONTCONFIG)
+#elif !defined(ECERE_NOFONTCONFIG)
                      if(getenv("ECERE_FONTS"))
                      {
                         strcpy(fileName, ecereFonts);
@@ -2940,14 +3388,14 @@ public class LFBDisplayDriver : DisplayDriver
                            matched = FcFontMatch (0, pattern, &result);
                            if(matched)
                            {
-                              FcPatternGetString(matched, FC_FAMILY, 0, &family);
+                              FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family);
                               // printf("Fontconfig returned %s\n", family);
                            }
                            if(matched && (result == FcResultMatch /*|| result == FcResultNoId*/) &&
-                              FcPatternGetString(matched, FC_FAMILY, 0, &family) == FcResultMatch /*&& !strcmpi(family, links + linksPos + c + 1)*/)
+                              FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family) == FcResultMatch /*&& !strcmpi(family, links + linksPos + c + 1)*/)
                            {
                               double fontSize;
-                              FcPatternGetString (matched, FC_FILE, 0, &fileName2);
+                              FcPatternGetString (matched, FC_FILE, 0, (FcChar8 **)&fileName2);
                               FcPatternGetInteger(matched, FC_INDEX, 0, &fontID);
                               FcPatternGetDouble(matched, FC_SIZE, 0, &fontSize);
                               strcpy(fileName, fileName2);
@@ -2963,15 +3411,15 @@ public class LFBDisplayDriver : DisplayDriver
                         }
                      }
 #endif
-                     
+
                   }
                   linksPos += c;
-                  while(links[linksPos]) linksPos++;
+                  while(links[linksPos] && links[linksPos] != ',') linksPos++;
                   linksPos++;
                }
             }
          }
-            
+
          if(!result)
             UnloadFont(displaySystem, font);
          else
@@ -2987,48 +3435,54 @@ public class LFBDisplayDriver : DisplayDriver
    }
 
 #if !defined(ECERE_NOTRUETYPE)
-   void ::ProcessString(Font font, DisplaySystem displaySystem, byte * text, int len, 
-                        void (* callback)(Surface surface, Display display, int * x, int y, GlyphInfo * glyph, Bitmap bitmap, bool rightToLeft),
+   void ::ProcessString(Font font, DisplaySystem displaySystem, const byte * text, int len,
+                        void (* callback)(Surface surface, Display display, int x, int y, GlyphInfo * glyph, Bitmap bitmap),
                         Surface surface, Display display, int * x, int y)
    {
       if(font && font.fontEntries && font.fontEntries[0])
       {
+         LFBSurface lfbSurface = surface ? surface.driverData : null;
          int previousGlyph = 0;
+         FT_Face previousFace = 0;
          int c, nb, glyphIndex = 0;
-         unichar lastPack = 0;
-         GlyphPack pack = font.asciiPack;
-         int wc;
-         uint * glyphs;
+         unichar lastPack = lfbSurface && lfbSurface.writingOutline ? -1 : 0;
+         GlyphPack pack = font.asciiPack, outline = null;
+         int wc = 0;
+         uint * glyphs = null;
          int numGlyphs = 0;
          bool rightToLeft = false;
-         int rightToLeftOffset = 0;
          int fontEntryNum = 0;
-         bool foundArabic = false;
          int glyphScript = 0;
-         
+         FontEntry curFontEntry;
+
          pack.bitmap.alphaBlend = true;
 
-         for(c = 0; c < len || glyphIndex < numGlyphs;)
+         for(c = 0; c < len || (numGlyphs && (rightToLeft ? (glyphIndex >= 0) : (glyphIndex < numGlyphs)));)
          {
-            uint glyphNo;
+            uint glyphNo = 0;
             uint packNo;
-            if(glyphIndex < numGlyphs)
+            if(numGlyphs && (rightToLeft ? (glyphIndex >= 0) : (glyphIndex < numGlyphs)))
             {
-               glyphNo = glyphs[glyphIndex++] | 0x80000000 | (glyphScript << 24);
+               glyphNo = glyphs[glyphIndex] | 0x80000000 | (glyphScript << 24);
+               rightToLeft ? glyphIndex-- : glyphIndex++;
             }
             else
             {
                HB_Script curScript = HB_Script_Common;
-               byte * scriptStart = text + c;
+               const byte * scriptStart = text + c;
+               //unichar nonASCIIch = 0;
                unichar ch;
                unichar ahead = 0;
                unichar testChar = 0;
-               char * testLang = null;
-               
+#if !defined(__WIN32__) && !defined(ECERE_NOFONTCONFIG)
+               const char * testLang = null;
+#endif
+
                while(true)
                {
                   HB_Script script = HB_Script_Common;
-                  ch = UTF8GetChar(text + c, &nb);
+                  ch = UTF8GetChar((const char *)text + c, &nb);
+                  //if(ch > 127) nonASCIIch = ch;
                   if(!nb) break;
                   if(ch == 32 && curScript)
                   {
@@ -3045,9 +3499,9 @@ public class LFBDisplayDriver : DisplayDriver
                         if(a < c + len)
                         {
                            int nb;
-                           unichar ahead = UTF8GetChar(text + a, &nb);
+                           unichar ahead = UTF8GetChar((const char *)text + a, &nb);
                            if((ahead >= 0x590 && ahead <= 0x7C0) || (ahead >= 0xFB1D && ahead <= 0xFB4F) || (ahead >= 0xFB50 && ahead <= 0xFDFF))
-                              script = curScript;                           
+                              script = curScript;
                         }
                         else
                            script = curScript;
@@ -3081,7 +3535,7 @@ public class LFBDisplayDriver : DisplayDriver
                      script = HB_Script_Hangul;
                   else if(ch >= 0x1680 && ch <= 0x169F) script = HB_Script_Ogham;
                   else if(ch >= 0x16A0 && ch <= 0x16FF) script = HB_Script_Runic;
-                  else if(ch >= 0x1780 && ch <= 0x17FF || ch >= 0x19E0 && ch <= 0x19FF) script = HB_Script_Khmer;
+                  else if((ch >= 0x1780 && ch <= 0x17FF) || (ch >= 0x19E0 && ch <= 0x19FF)) script = HB_Script_Khmer;
                   else if(ch >= 0x3040 && ch <= 0x309F) script = 60;
                   else if(ch >= 0x3400 && ch <= 0x9FBF) script = 61;
                   //else if(ch >= 0x4E00 && ch <= 0x9FBF) script = 61;
@@ -3096,7 +3550,7 @@ public class LFBDisplayDriver : DisplayDriver
                      if(c >= len)
                         break;
                   }
-                  else 
+                  else
                   {
                      if(!script || script > HB_ScriptCount) { c += nb; if(script > HB_ScriptCount) curScript = script; break; }
                      if(!script) { c += nb; break; }
@@ -3110,6 +3564,7 @@ public class LFBDisplayDriver : DisplayDriver
                {
                   rightToLeft = false;
                   glyphNo = ch;
+                  theCurrentScript = 0;
                }
                else
                {
@@ -3120,19 +3575,25 @@ public class LFBDisplayDriver : DisplayDriver
                      utf16 = renew utf16 uint16[max];
                      utf16BufferSize = max;
                   }
-                  wc = UTF8toUTF16BufferLen(scriptStart, utf16, max, len);
-                  glyphScript = curScript;
+                  wc = UTF8toUTF16BufferLen((const char *)scriptStart, utf16, max, len);
+                  theCurrentScript = glyphScript = curScript;
                }
                switch(curScript)
                {
                   case HB_Script_Arabic:        testChar = 0x621; /*testLang = "ar"; */
                      //printf("Arabic ");
                      break;
-                  case HB_Script_Devanagari:    testChar = 0x905; testLang = "sa"; 
+                  case HB_Script_Devanagari:    testChar = 0x905;
+#if !defined(__WIN32__) && !defined(ECERE_NOFONTCONFIG)
+                     testLang = "sa";
+#endif
                      //printf("Devanagari ");
                      break;
+                  case HB_Script_Hebrew:        testChar = 0x05EA /*'ת'*/; /*testLang = "he"; */
+                     //printf("Hebrew ");
+                     break;
                   default:
-                     testChar = ch;
+                     testChar = (ch == '\t') ? ' ' : ch;
                   /*
                   case 60: testChar = 'あ'; break;
                   case 61: testChar = 0x3400; break; //'愛'; break;
@@ -3150,10 +3611,10 @@ public class LFBDisplayDriver : DisplayDriver
                         printf("Not found in %s\n", (char *)font.fontEntries[fontEntryNum].key);*/
                   }
                }
-               
-               if(fontEntryNum == MAX_FONT_LINK_ENTRIES) 
+
+               if(fontEntryNum == MAX_FONT_LINK_ENTRIES)
                {
-#if !defined(__WIN32__)
+#if !defined(__WIN32__) && !defined(ECERE_NOFONTCONFIG)
                   int fontID = 0;
                   double fontSize = font.size;
                   FcResult result = 0;
@@ -3163,15 +3624,14 @@ public class LFBDisplayDriver : DisplayDriver
                   char * family;
                   FontEntry fontEntry;
                   char * fileName = null;
-                  bool fakeItalic = false;
                   for(fontEntryNum = 0; fontEntryNum<MAX_FONT_LINK_ENTRIES; fontEntryNum++)
                      if(!font.fontEntries[fontEntryNum])
                         break;
                   if(fontEntryNum == MAX_FONT_LINK_ENTRIES)
 #endif
                      continue;
-            
-#if !defined(__WIN32__)
+
+#if !defined(__WIN32__) && !defined(ECERE_NOFONTCONFIG)
                   {
                      charSet = FcCharSetCreate();
                      FcCharSetAddChar(charSet, testChar);
@@ -3194,12 +3654,12 @@ public class LFBDisplayDriver : DisplayDriver
                      matched = FcFontMatch (0, pattern, &result);
                      if(matched)
                      {
-                        FcPatternGetString(matched, FC_FAMILY, 0, &family);
+                        FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family);
                         //printf("Fontconfig returned %s\n", family);
                      }
-                     if(matched && (result == FcResultMatch) && FcPatternGetString(matched, FC_FAMILY, 0, &family) == FcResultMatch)
+                     if(matched && (result == FcResultMatch) && FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family) == FcResultMatch)
                      {
-                        FcPatternGetString (matched, FC_FILE, 0, &fileName);
+                        FcPatternGetString (matched, FC_FILE, 0, (FcChar8 **)&fileName);
                         FcPatternGetInteger(matched, FC_INDEX, 0, &fontID);
                         FcPatternGetDouble(matched, FC_SIZE, 0, &fontSize);
                         // printf("\nMatched to %s, %f\n", fileName, fontSize);
@@ -3218,16 +3678,16 @@ public class LFBDisplayDriver : DisplayDriver
                         if(file)
                         {
                            FileSize fileSize = file.GetSize();
-                           FT_Open_Args args = { 0 };                            
+                           FT_Open_Args args = { 0 };
                            FT_Parameter param = { FT_PARAM_TAG_UNPATENTED_HINTING };
                            FT_Stream stream = new0 FT_StreamRec[1];
-                           
+
                            if(!ftLibrary)
                               FT_Init_FreeType( &ftLibrary );
 
-                           fontEntry = FontEntry { key = (uint)CopyString(fileName) };
+                           fontEntry = FontEntry { key = (uintptr)CopyString(fileName) };
                            fontEntry.stream = stream;
-                                                
+
                            //args.num_params = 1;
                            args.params = &param;
 
@@ -3248,9 +3708,9 @@ public class LFBDisplayDriver : DisplayDriver
                            // delete file;
                            if(fontEntry.face)
                            {
-                              fontEntry.hbFace = HB_NewFace(fontEntry.face, hb_getSFntTable);            
+                              fontEntry.hbFace = HB_NewFace(fontEntry.face, hb_getSFntTable);
                               fontEntry.hbFont.klass = &hb_fontClass;
-                              fontEntry.hbFont.userData = fontEntry.face;
+                              fontEntry.hbFont.userData = fontEntry; //.face;
 
                               numFonts++;
                               loadedFonts.Add(fontEntry);
@@ -3264,13 +3724,13 @@ public class LFBDisplayDriver : DisplayDriver
                      }
                      if(fontEntry)
                      {
-                        FT_Set_Char_Size( fontEntry.face, (int)(font.size * 64), (int)(font.size * 64), 96, 96);
+                        FaceSetCharSize(fontEntry.face, font.size);
 
                         font.fontEntries[fontEntryNum] = fontEntry;
                         fontEntry.used++;
                      }
                   }
-                  if(pattern) FcPatternDestroy(pattern);          
+                  if(pattern) FcPatternDestroy(pattern);
                   if(matched) FcPatternDestroy(matched);
                   if(charSet) FcCharSetDestroy(charSet);
 #endif
@@ -3278,79 +3738,82 @@ public class LFBDisplayDriver : DisplayDriver
                if(curScript > HB_ScriptCount) curScript = HB_Script_Common;
                if(curScript != HB_Script_Common && curScript < HB_ScriptCount)
                {
-                  int c;
+                  font.fontEntries[fontEntryNum].font = font;
                   glyphs = shaping(font.fontEntries[fontEntryNum], utf16, wc, curScript, &numGlyphs, &rightToLeft);
                   if(!numGlyphs)
                      continue;
-                  if(rightToLeft /*&& surface*/)
-                  {
-                     int c;
-                     rightToLeftOffset = 0;
-                     for(c = 0; c<numGlyphs; c++)
-                     {
-                        GlyphInfo * glyph;
-                        glyphNo = glyphs[c] | 0x80000000 | (glyphScript << 24);
-                        packNo = glyphNo & 0xFFFFFF80;
-                        if(packNo != lastPack)
-                        {
-                           pack = (GlyphPack)font.glyphPacks.Find(packNo);
-                           if(!pack)
-                           {
-                              pack = GlyphPack { key = packNo };
-                              font.glyphPacks.Add(pack);
-                              pack.Render(font, fontEntryNum, displaySystem);
-                           }
-                           pack.bitmap.alphaBlend = true;
-                           lastPack = packNo;
-                        }
-                        glyph = &pack.glyphs[glyphNo & 0x7F];
-
-                        rightToLeftOffset += (int)glyph->ax - glyph->left;
-                     }
-                     *x += rightToLeftOffset;
-                  }
 
-                  glyphIndex = 0;
-                  glyphNo = glyphs[glyphIndex++] | 0x80000000 | (glyphScript << 24);
+                  glyphIndex = rightToLeft ? (numGlyphs - 1) : 0;
+                  glyphNo = glyphs[glyphIndex] | 0x80000000 | (glyphScript << 24);
+                  rightToLeft ? glyphIndex-- : glyphIndex++;
                }
             }
+
+            curFontEntry = font.fontEntries[fontEntryNum];
+
             packNo = glyphNo & 0xFFFFFF80;
 
             if(packNo != lastPack)
             {
-               if(glyphNo < 128) 
+               if(glyphNo < 128)
                   pack = font.asciiPack;
                else
                {
-                  pack = (GlyphPack)font.glyphPacks.Find(packNo);
+                  pack = (GlyphPack)font.glyphPacks.Find((uintptr)packNo);
                   if(!pack)
                   {
-                     pack = GlyphPack { key = packNo };
+                     pack = GlyphPack { key = (uintptr)packNo };
                      font.glyphPacks.Add(pack);
                      pack.Render(font, fontEntryNum, displaySystem);
                   }
                }
                pack.bitmap.alphaBlend = true;
                lastPack = packNo;
+#if !defined(ECERE_VANILLA)
+               if(lfbSurface && lfbSurface.writingOutline)
+               {
+                  uint outlineNo = (((uint)surface.outline.size) << 16) | (uint16)(Min(surface.outline.fade, 257.0f) * 255);
+                  outline = (GlyphPack)pack.outlines.Find(outlineNo);
+                  if(!outline)
+                  {
+                     outline = { key = outlineNo };
+                     pack.outlines.Add(outline);
+                     pack.RenderOutline(outline, font, displaySystem);
+                  }
+               }
+#endif
             }
             if(pack)
             {
-               GlyphInfo * glyph = &pack.glyphs[glyphNo & 0x7F];
+               int index = rightToLeft ? (glyphIndex + 1) : (glyphIndex-1);
+               GlyphInfo * glyph = &(outline ? outline : pack).glyphs[glyphNo & 0x7F];
+
+               int ax = (int)((numGlyphs ? shaper_item.advances[index] : glyph->ax) * glyph->scale);
+               int offset = numGlyphs ? shaper_item.offsets[index].x : 0;
+               int oy = 0;//numGlyphs ? shaper_item.offsets[index].y : 0;
 
-               /*if(previousGlyph)
+               ax += offset;
+
+               if(previousGlyph && curFontEntry.face == previousFace)
                {
-                  FT_Vector delta;
-                  FT_Get_Kerning(font.fontEntries[fontEntryNum].face, previousGlyph, glyph->glyphNo, FT_KERNING_UNFITTED, &delta );
-                  *x += delta.x;
+                  FT_Vector delta = { 0, 0 };
+                  FT_Get_Kerning(curFontEntry.face, previousGlyph, glyph->glyphNo, FT_KERNING_UNFITTED, &delta );
+                  if(delta.x < 0)  delta.x += (-delta.x) % 64;
+                  else if(delta.x) delta.x += 64 - (delta.x % 64);
+                  *x += delta.x * glyph->scale;
                }
-               previousGlyph = glyph->glyphNo;*/
-               callback(surface, display, x, y, glyph, pack.bitmap, rightToLeft);
+               else
+                  FaceSetCharSize(curFontEntry.face, font.size);
+
+               previousGlyph = glyph->glyphNo;
+               previousFace = curFontEntry.face;
+
+               if(callback)
+                  callback(surface, display, ((*x) >> 6), y + (oy >> 6), glyph, (outline ? outline : pack).bitmap);
+               *x += ax;
             }
-            if(numGlyphs && glyphIndex == numGlyphs)
-            {
-               *x += rightToLeftOffset;
+            if(numGlyphs && (rightToLeft ? (glyphIndex < 0) : (glyphIndex == numGlyphs)))
                numGlyphs = 0;
-            }
          }
       }
       if(surface)
@@ -3360,23 +3823,12 @@ public class LFBDisplayDriver : DisplayDriver
       }
    }
 
-   void ::AddWidth(Surface surface, Display display, int * x, int y, GlyphInfo * glyph, Bitmap bitmap, bool rightToLeft)
-   {
-      if(rightToLeft)
-      {
-         *x -= (int)glyph->ax - glyph->left;
-      }
-      else
-      {
-         *x += glyph->ax;
-      }
-   }
 #endif
-   void FontExtent(DisplaySystem displaySystem, Font font, byte * text, int len, int * width, int * height)
+   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height)
    {
       if(displaySystem && displaySystem.flags.text && len)
       {
-         if(width) 
+         if(width)
          {
             int num = len;
             *width = num * textCellW;
@@ -3389,7 +3841,7 @@ public class LFBDisplayDriver : DisplayDriver
          {
             int w = 0;
 #if !defined(ECERE_NOTRUETYPE)
-            ProcessString(font, displaySystem, text, len, AddWidth, null, null, &w, 0);
+            ProcessString(font, displaySystem, (const byte *)text, len, null, null, null, &w, 0);
 #endif
             //*width = (w + 64 - w % 64) >> 6;
             *width = w >> 6;
@@ -3405,24 +3857,13 @@ public class LFBDisplayDriver : DisplayDriver
    }
 
 #if !defined(ECERE_NOTRUETYPE)
-   void ::OutputGlyph(Surface surface, Display display, int * x, int y, GlyphInfo * glyph, Bitmap bitmap, bool rightToLeft)
+   void ::OutputGlyph(Surface surface, Display display, int x, int y, GlyphInfo * glyph, Bitmap bitmap)
    {
-      LFBSurface lfbSurface = surface.driverData;
-      //lfbSurface.xOffset = (*x & 0x3F);
-      if(rightToLeft)
-      {
-         surface.driver.Blit(display, surface, bitmap, (*x >> 6) - glyph->w, y + glyph->top, glyph->x, glyph->y, glyph->w, glyph->h);
-         *x -= (int)glyph->ax - glyph->left;
-      }
-      else
-      {
-         surface.driver.Blit(display, surface, bitmap, (*x >> 6) + glyph->left, y + glyph->top, glyph->x, glyph->y, glyph->w, glyph->h);
-         *x += glyph->ax;
-      }
+      surface.driver.Blit(display, surface, bitmap, x + glyph->left, y + glyph->top, glyph->x, glyph->y, glyph->w, glyph->h);
    }
 #endif
 
-   void WriteText(Display display, Surface surface, int x, int y, byte * text, int len)
+   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len)
    {
       LFBSurface lfbSurface = surface.driverData;
       if(display && display.displaySystem.flags.text)
@@ -3434,7 +3875,7 @@ public class LFBDisplayDriver : DisplayDriver
          x /= textCellW;
          y /= textCellH;
 
-         if(y > surface.box.bottom || y < surface.box.top) 
+         if(y > surface.box.bottom || y < surface.box.top)
             return;
          coffset += (y+surface.offset.y) * lfbSurface.bitmap.stride + x + surface.offset.x;
          for(c=0; (c<len && x < surface.box.left); c++, x++,coffset++);
@@ -3446,17 +3887,17 @@ public class LFBDisplayDriver : DisplayDriver
                *coffset = (uint16) (((*coffset)&0xF000)|lfbSurface.foreground|text[c]);
          }
       }
-      else 
+      else
       {
          lfbSurface.writingText = true;
 #if !defined(ECERE_NOTRUETYPE)
          x <<= 6;
-         ProcessString(lfbSurface.font, surface.displaySystem, text, len, OutputGlyph, surface, display, &x, y);
+         ProcessString(lfbSurface.font, surface.displaySystem, (const byte *)text, len, OutputGlyph, surface, display, &x, y);
 #endif
          lfbSurface.writingText = false;
       }
    }
-   
+
    void TextFont(Display display, Surface surface, Font font)
    {
       LFBSurface lfbSurface = surface.driverData;
@@ -3465,11 +3906,10 @@ public class LFBDisplayDriver : DisplayDriver
 
    void TextOpacity(Display display, Surface surface, bool opaque)
    {
-      LFBSurface lfbSurface = surface.driverData;
 
    }
 
-   void TextExtent(Display display, Surface surface, byte * text, int len, int * width, int * height)
+   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height)
    {
       LFBSurface lfbSurface = surface.driverData;
       FontExtent(surface.displaySystem, lfbSurface.font, text, len, width, height);
@@ -3498,14 +3938,67 @@ public class LFBDisplayDriver : DisplayDriver
          delete mesh.texCoords;
    }
 
-   bool AllocateMesh(DisplaySystem displaySystem, Mesh mesh)
+   bool AllocateMesh(DisplaySystem displaySystem, Mesh mesh, MeshFeatures flags, int nVertices)
    {
       bool result = false;
-
-      if((!mesh.flags.vertices   || mesh.vertices  || (mesh.vertices  = new Vector3Df[mesh.nVertices])) &&
-         (!mesh.flags.normals    || mesh.normals   || (mesh.normals   = new Vector3Df[mesh.nVertices])) &&
-         (!mesh.flags.texCoords1 || mesh.texCoords || (mesh.texCoords = new Pointf  [mesh.nVertices])))
+      if(mesh.nVertices == nVertices)
+      {
+         result = true;
+         // Same number of vertices, adding features (Leaves the other features pointers alone)
+         if(mesh.flags != flags)
+         {
+            if(!mesh.flags.vertices && flags.vertices)
+            {
+               if(flags.doubleVertices)
+               {
+                  mesh.vertices = (Vector3Df *)new Vector3D[nVertices];
+               }
+               else
+                  mesh.vertices = new Vector3Df[nVertices];
+            }
+            if(!mesh.flags.normals && flags.normals)
+            {
+               if(flags.doubleNormals)
+               {
+                  mesh.normals = (Vector3Df *)new Vector3D[nVertices];
+               }
+               else
+                  mesh.normals = new Vector3Df[nVertices];
+            }
+            if(!mesh.flags.texCoords1 && flags.texCoords1)
+               mesh.texCoords = new Pointf[nVertices];
+            if(!mesh.flags.colors && flags.colors)
+               mesh.colors = new ColorRGBAf[nVertices];
+         }
+      }
+      else
+      {
          result = true;
+         // New number of vertices, reallocate all current and new features
+         flags |= mesh.flags;
+         if(flags.vertices)
+         {
+            if(flags.doubleVertices)
+            {
+               mesh.vertices = (Vector3Df *)renew mesh.vertices Vector3D[nVertices];
+            }
+            else
+               mesh.vertices = renew mesh.vertices Vector3Df[nVertices];
+         }
+         if(flags.normals)
+         {
+            if(flags.doubleNormals)
+            {
+               mesh.normals = (Vector3Df *)renew mesh.normals Vector3D[nVertices];
+            }
+            else
+               mesh.normals = renew mesh.normals Vector3Df[nVertices];
+         }
+         if(flags.texCoords1)
+            mesh.texCoords = renew mesh.texCoords Pointf[nVertices];
+         if(flags.colors)
+            mesh.colors = renew mesh.colors ColorRGBAf[nVertices];
+      }
       return result;
    }