ecere/gfx/drivers/LFB; gui/EditBox: Splitting Font Rendering & Management; Italic...
authorJerome St-Louis <jerome@ecere.com>
Sat, 23 May 2015 06:49:37 +0000 (02:49 -0400)
committerJerome St-Louis <jerome@ecere.com>
Sat, 2 Jul 2016 20:42:01 +0000 (16:42 -0400)
- FontConfig/Windows font lookup and linking moved to fontManagement.ec
- Text rendering with FreeType and HarfBuzz moved to fontRendering.ec
- Fixed extent of italic fonts
- EditBox: Drawing selection background once for entire line
- Fixed compilation with ECERE_STATIC, no _GLES
- Fixed crashes on null FontEntry, triggered by character 0x80

20 files changed:
ecere/Makefile
ecere/ecere.epj
ecere/src/gfx/Display.ec
ecere/src/gfx/DisplaySystem.ec
ecere/src/gfx/Surface.ec
ecere/src/gfx/drivers/CocoaOpenGLDisplayDriver.ec
ecere/src/gfx/drivers/Direct3D8DisplayDriver.ec
ecere/src/gfx/drivers/Direct3D9DisplayDriver.ec
ecere/src/gfx/drivers/DirectDrawDisplayDriver.ec
ecere/src/gfx/drivers/GDIDisplayDriver.ec
ecere/src/gfx/drivers/LFBDisplayDriver.ec
ecere/src/gfx/drivers/NCursesDisplayDriver.ec
ecere/src/gfx/drivers/OpenGLDisplayDriver.ec
ecere/src/gfx/drivers/Win32BitmapPrinterDisplayDriver.ec
ecere/src/gfx/drivers/Win32ConsoleDisplayDriver.ec
ecere/src/gfx/drivers/Win32PrinterDisplayDriver.ec
ecere/src/gfx/drivers/XDisplayDriver.ec
ecere/src/gfx/fontManagement.ec [new file with mode: 0644]
ecere/src/gfx/fontRendering.ec [new file with mode: 0644]
ecere/src/gui/controls/EditBox.ec

index 49a5b46..1d6c13b 100644 (file)
@@ -117,6 +117,8 @@ _ECSOURCES2 = \
        src/gfx/FontResource.ec \
        src/gfx/Resource.ec \
        src/gfx/Surface.ec \
+       src/gfx/fontManagement.ec \
+       src/gfx/fontRendering.ec \
        src/gui/controls/Button.ec \
        src/gui/controls/CalendarControl.ec \
        src/gui/controls/DataBox.ec \
@@ -812,6 +814,12 @@ $(OBJ)Resource.sym: src/gfx/Resource.ec
 $(OBJ)Surface.sym: src/gfx/Surface.ec
        $(ECP) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c src/gfx/Surface.ec -o $(OBJ)Surface.sym
 
+$(OBJ)fontManagement.sym: src/gfx/fontManagement.ec
+       $(ECP) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c $(call quote_path,src/gfx/fontManagement.ec) -o $(call quote_path,$@)
+
+$(OBJ)fontRendering.sym: src/gfx/fontRendering.ec
+       $(ECP) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c $(call quote_path,src/gfx/fontRendering.ec) -o $(call quote_path,$@)
+
 $(OBJ)Button.sym: src/gui/controls/Button.ec
        $(ECP) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c src/gui/controls/Button.ec -o $(OBJ)Button.sym
 
@@ -1224,6 +1232,12 @@ $(OBJ)Resource.c: src/gfx/Resource.ec $(OBJ)Resource.sym | $(SYMBOLS)
 $(OBJ)Surface.c: src/gfx/Surface.ec $(OBJ)Surface.sym | $(SYMBOLS)
        $(ECC) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c src/gfx/Surface.ec -o $(OBJ)Surface.c -symbols $(OBJ)
 
+$(OBJ)fontManagement.c: src/gfx/fontManagement.ec $(OBJ)fontManagement.sym | $(SYMBOLS)
+       $(ECC) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) $(FVISIBILITY) -c $(call quote_path,src/gfx/fontManagement.ec) -o $(call quote_path,$@) -symbols $(OBJ)
+
+$(OBJ)fontRendering.c: src/gfx/fontRendering.ec $(OBJ)fontRendering.sym | $(SYMBOLS)
+       $(ECC) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) $(FVISIBILITY) -c $(call quote_path,src/gfx/fontRendering.ec) -o $(call quote_path,$@) -symbols $(OBJ)
+
 $(OBJ)Button.c: src/gui/controls/Button.ec $(OBJ)Button.sym | $(SYMBOLS)
        $(ECC) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c src/gui/controls/Button.ec -o $(OBJ)Button.c -symbols $(OBJ)
 
@@ -1702,6 +1716,12 @@ $(OBJ)Resource.o: $(OBJ)Resource.c
 $(OBJ)Surface.o: $(OBJ)Surface.c
        $(CC) $(CFLAGS) $(PRJ_CFLAGS) -c $(OBJ)Surface.c -o $(OBJ)Surface.o
 
+$(OBJ)fontManagement$(O): $(OBJ)fontManagement.c
+       $(CC) $(CFLAGS) $(PRJ_CFLAGS) $(FVISIBILITY) -c $(call quote_path,$(OBJ)fontManagement.c) -o $(call quote_path,$@)
+
+$(OBJ)fontRendering$(O): $(OBJ)fontRendering.c
+       $(CC) $(CFLAGS) $(PRJ_CFLAGS) $(FVISIBILITY) -c $(call quote_path,$(OBJ)fontRendering.c) -o $(call quote_path,$@)
+
 $(OBJ)Button.o: $(OBJ)Button.c
        $(CC) $(CFLAGS) $(PRJ_CFLAGS) -c $(OBJ)Button.c -o $(OBJ)Button.o
 
index d332271..1771a3c 100644 (file)
@@ -1645,7 +1645,9 @@ if distributed with the Ecere SDK Windows installer.
                   "DisplaySystem.ec",
                   "FontResource.ec",
                   "Resource.ec",
-                  "Surface.ec"
+                  "Surface.ec",
+                  "fontManagement.ec",
+                  "fontRendering.ec"
                ],
                "Configurations" : [
                   {
index dd430aa..586fa60 100644 (file)
@@ -148,9 +148,9 @@ public:
    virtual void ::FilterDI(Display, Surface, Bitmap, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh);
    virtual void ::TextFont(Display, Surface, Font);
    virtual void ::TextOpacity(Display, Surface, bool);
-   virtual void ::WriteText(Display, Surface, int x, int y, const String text, int len);
-   virtual void ::TextExtent(Display, Surface, const String text, int len, int * tw, int * th);
-   virtual void ::FontExtent(DisplaySystem, Font, const String text, int len, int * tw, int * th);
+   virtual void ::WriteText(Display, Surface, int x, int y, const String text, int len, int prevGlyph, int * rPrevGlyph);
+   virtual void ::TextExtent(Display, Surface, const String text, int len, int * tw, int * th, int prevGlyph, int * rPrevGlyph, int * overHang);
+   virtual void ::FontExtent(DisplaySystem, Font, const String text, int len, int * tw, int * th, int prevGlyph, int * rPrevGlyph, int * overHang);
    virtual void ::DrawingChar(Display, Surface, char ch);
    virtual void ::NextPage(Display);
 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
@@ -506,6 +506,13 @@ public:
 
    void FontExtent(Font font, const char * text, int len, int * width, int * height)
    {
+      int overHang;
+      FontExtent2(font, text, len, width, height, 0, null, &overHang);
+      if(width) *width += overHang;
+   }
+
+   void FontExtent2(Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * overHang)
+   {
       // Fix for OnLoadGraphics time alpha blended window text extent on GDI
 #if defined(__WIN32__) && !defined(ECERE_NOTRUETYPE)
       if(this && alphaBlend && pixelFormat == pixelFormat888 &&
@@ -515,14 +522,14 @@ public:
          if(s)
          {
             s.font = font;
-            s.TextExtent(text, len, width, height);
+            s.TextExtent2(text, len, width, height, prevGlyph, rPrevGlyph, overHang);
             delete s;
          }
       }
       else
 #endif
          // TODO: Should really pass display here...
-         DisplaySystem::FontExtent(this ? displaySystem : null, font, text, len, width, height);
+         DisplaySystem::FontExtent2(this ? displaySystem : null, font, text, len, width, height, prevGlyph, rPrevGlyph, overHang);
    }
 
    void SetPalette(ColorAlpha * palette, bool colorMatch)
index f043da2..dff6d7a 100644 (file)
@@ -112,7 +112,22 @@ public:
    void FontExtent(Font font, const char * text, int len, int * width, int * height)
    {
       if(this && text)
-         driver.FontExtent(this, font, text, len, width, height);
+      {
+         int advance = 0;
+         driver.FontExtent(this, font, text, len, width, height, 0, null, &advance);
+         if(width) *width += advance;
+      }
+      else
+      {
+         if(width) *width = 0;
+         if(height) *height = 0;
+      }
+   }
+
+   void FontExtent2(Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * overHang)
+   {
+      if(this && text)
+         driver.FontExtent(this, font, text, len, width, height, prevGlyph, rPrevGlyph, overHang);
       else
       {
          if(width) *width = 0;
index 1368a29..847e92b 100644 (file)
@@ -281,12 +281,26 @@ public:
    void WriteText(int x, int y, const char * text, int len)
    {
       if(text)
-         driver.WriteText(display, this, x,y, text, len);
+         driver.WriteText(display, this, x,y, text, len, 0, null); //, null);
+   }
+
+   void WriteText2(int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
+   {
+      if(text)
+         driver.WriteText(display, this, x,y, text, len, prevGlyph, rPrevGlyph);
    }
 
    void TextExtent(const char * text, int len, int * width, int * height)
    {
-      driver.TextExtent(display, this, text, len, width, height);
+      int advance = 0;
+      driver.TextExtent(display, this, text, len, width, height, 0, null, &advance);
+      if(width)
+         *width += advance;
+   }
+
+   void TextExtent2(const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * overHang)
+   {
+      driver.TextExtent(display, this, text, len, width, height, prevGlyph, rPrevGlyph, overHang);
    }
 
    void WriteTextf(int x, int y, const char * format, ...)
@@ -298,7 +312,8 @@ public:
          va_start(args, format);
          vsnprintf(text, sizeof(text), format, args);
          text[sizeof(text)-1] = 0;
-         driver.WriteText(display, this, x,y, text, strlen(text));
+         if(driver)
+            driver.WriteText(display, this, x,y, text, strlen(text), 0, null);
          va_end(args);
       }
    }
@@ -310,14 +325,15 @@ public:
          char text[MAX_F_STRING];
          va_list args;
          int len;
-         int w, h;
+         int w, h, oh;
          va_start(args, format);
          vsnprintf(text, sizeof(text), format, args);
          text[sizeof(text)-1] = 0;
          len = strlen(text);
 
-         driver.TextExtent(display, this, text, len, &w, &h);
-         driver.WriteText(display, this, x - w/2, y, text, len);
+         driver.TextExtent(display, this, text, len, &w, &h, 0, null, &oh);
+         w += oh;
+         driver.WriteText(display, this, x - w/2, y, text, len, 0, null);
          va_end(args);
       }
    }
index 7edf428..0e640d0 100644 (file)
@@ -982,13 +982,13 @@ class CocoaOpenGLDisplayDriver : DisplayDriver
       return font;
    }
 
-   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height)
+   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
       printf("CocoaOpenGLDisplayDriver:FontExtent() %s:%i\n", __FILE__, __LINE__);
-      LFBDisplayDriver::FontExtent(displaySystem, font, text, len, width, height);
+      LFBDisplayDriver::FontExtent(displaySystem, font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
    }
 
-   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len)
+   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
    {
       SurfaceData surfaceData = surface.driverData;
       SystemData systemData = display.displaySystem.driverData;
@@ -1000,7 +1000,7 @@ class CocoaOpenGLDisplayDriver : DisplayDriver
       if(surface.textOpacity)
       {
          int w, h;
-         FontExtent(display.displaySystem, surface.font, text, len, &w, &h);
+         FontExtent(display.displaySystem, surface.font, text, len, &w, &h, prevGlyph, rPrevGlyph);
          Area(display, surface,x,y,x+w-1,y+h-1);
       }
 
@@ -1011,7 +1011,7 @@ class CocoaOpenGLDisplayDriver : DisplayDriver
       glColor4fv(surfaceData.foreground);
       CocoaGlAssert();
 
-      LFBDisplayDriver::WriteText(display, surface, x, y, text, len);
+      LFBDisplayDriver::WriteText(display, surface, x, y, text, len, prevGlyph, rPrevGlyph);
       surfaceData.writingText = false;
       systemData.loadingFont = false;
 
@@ -1032,12 +1032,12 @@ class CocoaOpenGLDisplayDriver : DisplayDriver
       printf("CocoaOpenGLDisplayDriver:TextOpacity(%i) %s:%i\n", opaque, __FILE__, __LINE__);
    }
 
-   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height)
+   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
       SurfaceData surfaceData = surface.driverData;
       SystemData systemData = display.displaySystem.driverData;
       systemData.loadingFont = true;
-      FontExtent(display.displaySystem, surfaceData.font, text, len, width, height);
+      FontExtent(display.displaySystem, surfaceData.font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
       systemData.loadingFont = false;
 
       printf("CocoaOpenGLDisplayDriver:TextExtent STUB! %s:%i\n", __FILE__, __LINE__);
index 0683b5e..96e4989 100644 (file)
@@ -998,12 +998,12 @@ class Direct3D8DisplayDriver : DisplayDriver
       d3dSurface.opaqueText = opaque;
    }
 
-   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height)
+   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
    }
 
-   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len)
+   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
    {
       DisplaySystem displaySystem = display.displaySystem;
       D3D8System d3dSystem = displaySystem.driverData;
@@ -1011,8 +1011,9 @@ class Direct3D8DisplayDriver : DisplayDriver
 
       if(surface.textOpacity)
       {
-         int w, h;
-         FontExtent(display.displaySystem, surface.font, text, len, &w, &h);
+         int w, h, adv;
+         FontExtent(display.displaySystem, surface.font, text, len, &w, &h, prevGlyph, rPrevGlyph, &adv);
+         w += adv;
 
          {
             int x1 = x, y1 = y, x2 = x+w-1, y2 = y+h-1;
@@ -1034,7 +1035,7 @@ class Direct3D8DisplayDriver : DisplayDriver
       IDirect3DDevice8_SetTextureStageState(d3dSystem.d3dDevice, 0, D3DTSS_MIPFILTER, D3DTEXF_NONE);
       d3dSurface.writingText = true;
 
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len, prevGlyph, rPrevGlyph);
 
       d3dSurface.writingText = false;
       IDirect3DDevice8_SetTextureStageState(d3dSystem.d3dDevice, 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
@@ -1042,9 +1043,9 @@ class Direct3D8DisplayDriver : DisplayDriver
       IDirect3DDevice8_SetTextureStageState(d3dSystem.d3dDevice, 0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR); //NONE);
    }
 
-   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height)
+   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, width, height);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, width, height, prevGlyph, rPrevGlyph, adv);
    }
 
    void DrawingChar(Display display, Surface surface, byte character)
index 38eeeb8..0be479f 100644 (file)
@@ -1014,12 +1014,12 @@ class Direct3D9DisplayDriver : DisplayDriver
       d3dSurface.opaqueText = opaque;
    }
 
-   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height)
+   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
    }
 
-   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len)
+   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
    {
       DisplaySystem displaySystem = display.displaySystem;
       D3DSystem d3dSystem = displaySystem.driverData;
@@ -1027,8 +1027,9 @@ class Direct3D9DisplayDriver : DisplayDriver
 
       if(surface.textOpacity)
       {
-         int w, h;
-         FontExtent(display.displaySystem, surface.font, text, len, &w, &h);
+         int w, h, adv;
+         FontExtent(display.displaySystem, surface.font, text, len, &w, &h, prevGlyph, rPrevGlyph, &adv);
+         w += adv;
          {
             int x1 = x, y1 = y, x2 = x+w-1, y2 = y+h-1;
             Vertex vertex[4] =
@@ -1050,7 +1051,7 @@ class Direct3D9DisplayDriver : DisplayDriver
       IDirect3DDevice9_SetSamplerState(d3dSystem.d3dDevice, 0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
       d3dSurface.writingText = true;
 
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len, prevGlyph, rPrevGlyph);
 
       d3dSurface.writingText = false;
       IDirect3DDevice9_SetSamplerState(d3dSystem.d3dDevice, 0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
@@ -1058,9 +1059,9 @@ class Direct3D9DisplayDriver : DisplayDriver
       IDirect3DDevice9_SetSamplerState(d3dSystem.d3dDevice, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
    }
 
-   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height)
+   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, width, height);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, width, height, prevGlyph, rPrevGlyph, adv);
    }
 
    void DrawingChar(Display display, Surface surface, char character)
index 5d30cf0..4ab7750 100644 (file)
@@ -633,7 +633,7 @@ class DirectDrawDisplayDriver : DisplayDriver
    #endif
    }
 
-   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len)
+   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
    {
    #ifdef USE_GDI_FONT
       DDrawDisplay ddrawDisplay = display.driverData;
@@ -662,8 +662,9 @@ class DirectDrawDisplayDriver : DisplayDriver
          TextOut(ddrawDisplay.hdc, x + surface.offset.x, y + surface.offset.y, u16text, wordCount);
          if(display.alphaBlend)
          {
-            int w, h;
-            FontExtent(display.displaySystem, surface.font, text, len, &w, &h);
+            int w, h, oh;
+            FontExtent(display.displaySystem, surface.font, text, len, &w, &h, prevGlyph, rPrevGlyph, &oh);
+            w += oh;
             surface.writeColor = false;
             SetBackground(display, surface, surface.foreground);
             Area(display, surface,x-2,y-2,x+w+1,y+h+1);
@@ -678,19 +679,20 @@ class DirectDrawDisplayDriver : DisplayDriver
    #else
       if(surface.textOpacity)
       {
-         int w, h;
-         ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(display.displaySystem, surface.font, text, len, &w, &h);
+         int w, h, adv;
+         ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(display.displaySystem, surface.font, text, len, &w, &h, prevGlyph, rPrevGlyph, &adv);
+         w += adv;
          Area(display, surface, x, y, x+w-1, y+h-1);
       }
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x,y, text, len);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x,y, text, len, prevGlyph, rPrevGlyph);
    #endif
    }
 
-   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height)
+   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
    #ifdef USE_GDI_FONT
       if(false) //display.alphaBlend)
-        ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height);
+        ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
       else
       {
          if(tmpDC)
@@ -702,6 +704,7 @@ class DirectDrawDisplayDriver : DisplayDriver
          {
             if(width) *width = 0;
             if(height) *height = 0;
+            if(adv) *adv = 0;
          }
       }
       /*
@@ -724,15 +727,15 @@ class DirectDrawDisplayDriver : DisplayDriver
       }
       */
    #else
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
    #endif
    }
 
-   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height)
+   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
    #ifdef USE_GDI_FONT
       /*if(display && display.alphaBlend)
-         ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, width, height);
+         ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, prevGlyph, rPrevGlyph, width, height, adv);
       else*/
 
       {
@@ -750,6 +753,7 @@ class DirectDrawDisplayDriver : DisplayDriver
 
          // UNICODE FIX: proper space computation
          if(width) *width = size.cx + (wordCount - realLen) * space.cx;
+         if(adv) *adv = 0;
          if(height)
          {
             if(realLen)
@@ -777,7 +781,7 @@ class DirectDrawDisplayDriver : DisplayDriver
       }
       */
    #else
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, width, height);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, width, height, prevGlyph, rPrevGlyph, adv);
    #endif
    }
 
index 77cbdc3..5b9998f 100644 (file)
@@ -69,11 +69,13 @@ class GDIBitmap : struct
    HDC memDC;
 };
 
-static class GDIFont
+static class GDIFont : struct
 {
    char faceName[512];
    FontFlags flags;
    float size;
+   int ascent, descent;
+   float scale;
 
    void * gdiFont;
    Font font;
@@ -855,9 +857,11 @@ class GDIDisplayDriver : DisplayDriver
       {
          GDIFont font { };
          HDC hdc = GetDC(null);
+         TEXTMETRIC tm;
          int pixels = GetDeviceCaps(hdc, LOGPIXELSY);
          strcpy(font.faceName, faceName);
          font.size = size;
+         font.scale = 1;
          font.flags = flags;
          font.gdiFont = CreateFontA(-(int)((float)size * pixels / 72 + 0.5),
             0,0,0, flags.bold ? FW_BOLD : FW_NORMAL, flags.italic ? TRUE : FALSE,
@@ -865,6 +869,10 @@ class GDIDisplayDriver : DisplayDriver
                            OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
                            DEFAULT_PITCH|FF_DONTCARE, faceName);
 
+         SelectObject(hdc, font.gdiFont);
+         GetTextMetrics(hdc, &tm);
+         font.ascent = tm.tmAscent;
+         font.descent = tm.tmDescent;
          ReleaseDC(null, hdc);
          return (Font)font;
       }
@@ -914,7 +922,7 @@ class GDIDisplayDriver : DisplayDriver
       }
    }
 
-   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len)
+   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
    {
       if(display.alphaBlend && display.pixelFormat == pixelFormat888)
       {
@@ -926,11 +934,12 @@ class GDIDisplayDriver : DisplayDriver
          }
          if(surface.textOpacity)
          {
-            int w, h;
-            ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(display.displaySystem, gdiFont.font, text, len, &w, &h);
+            int w, h, adv;
+            ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(display.displaySystem, gdiFont.font, text, len, &w, &h, prevGlyph, rPrevGlyph, &adv);
+            w += adv;
             Area(display, surface, x, y, x+w-1, y+h-1);
          }
-         ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len);
+         ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len, prevGlyph, rPrevGlyph);
       }
       else
       {
@@ -941,8 +950,9 @@ class GDIDisplayDriver : DisplayDriver
          TextOut(gdiSurface.hdc, x + surface.offset.x, y + surface.offset.y, u16text, wordCount);
          if(display.alphaBlend && display.pixelFormat == pixelFormat888)
          {
-            int w, h;
-            FontExtent(display.displaySystem, surface.font, text, len, &w, &h);
+            int w, h, adv;
+            FontExtent(display.displaySystem, surface.font, text, len, &w, &h, prevGlyph, rPrevGlyph, &adv);
+            w += adv;
             surface.writeColor = false;
             SetBackground(display, surface, surface.foreground);
             Area(display, surface,x-2,y-2,x+w+1,y+h+1);
@@ -953,10 +963,10 @@ class GDIDisplayDriver : DisplayDriver
       }
    }
 
-   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height)
+   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
       if(display && display.alphaBlend && display.pixelFormat == pixelFormat888)
-         ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, width, height);
+         ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, width, height, prevGlyph, rPrevGlyph, adv);
       else
       {
          GDISurface gdiSurface = surface.driverData;
@@ -965,9 +975,21 @@ class GDIDisplayDriver : DisplayDriver
          int wordCount;
          uint16 * u16text = UTF8toUTF16Len(text, len, &wordCount);
 
-         for(realLen = 0; realLen<wordCount && u16text[realLen]; realLen++);
+         for(realLen = 0; realLen < wordCount && u16text[realLen]; realLen++);
          GetTextExtentPoint32A(gdiSurface.hdc, " ", 1, &space);
          GetTextExtentPoint32(gdiSurface.hdc, u16text, realLen, &size);
+
+         if(adv) *adv = 0;
+         if(adv && realLen > 0)
+         {
+            ABC abc;
+            if(GetCharABCWidths(gdiSurface.hdc, u16text[realLen - 1], u16text[realLen - 1], &abc))
+            {
+               if(abc.abcC < 0)
+                  *adv = -abc.abcC;
+            }
+         }
+
          delete u16text;
 
          // UNICODE FIX: proper space computation
@@ -982,10 +1004,10 @@ class GDIDisplayDriver : DisplayDriver
       }
    }
 
-   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height)
+   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
       if(false) //display.alphaBlend)
-        ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height);
+        ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
       else
       {
          GDISystem gdiSystem = displaySystem.driverData;
@@ -999,7 +1021,7 @@ class GDIDisplayDriver : DisplayDriver
             gdiSurface.hdc = gdiSystem.tmpDC;
 
             SelectObject(gdiSurface.hdc, gdiFont ? gdiFont.gdiFont : null);
-            TextExtent(null, surface, text, len, width, height);
+            TextExtent(null, surface, text, len, width, height, prevGlyph, rPrevGlyph, adv);
 
             delete surface;
             delete gdiSurface;
@@ -1008,6 +1030,7 @@ class GDIDisplayDriver : DisplayDriver
          {
             if(width) *width = 0;
             if(height) *height = 0;
+            if(adv) *adv = 0;
          }
       }
    }
index ed31646..397ee7a 100644 (file)
@@ -1,37 +1,5 @@
 namespace gfx::drivers;
 
-#if (defined(ECERE_VANILLA) || defined(ECERE_ONEDRIVER)) && defined(__WIN32__)
-#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 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>
-static FcConfig * fcConfig;
-#undef set
-#endif
-
-#endif
-#undef uint
-#undef strlen
-
 #ifdef __MSC__
 #pragma warning(disable:4244)
 #pragma warning(disable:4018)
@@ -51,676 +19,30 @@ static bool rgbLookupSet = true;
 /*static */bool rgbLookupSet = false;
 //#endif
 
+#if defined(ECERE_VANILLA)
+   #define ECERE_NOTRUETYPE
+#endif
+
+#if !defined(ECERE_NOTRUETYPE)
+import "fontManagement"
+import "fontRendering"
+#else
+public class Font : struct { }
+#endif
+
 import "lfbBlit"
 import "lfbConvert"
 
 #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA) && defined(__WIN32__)
 import "OpenGLDisplayDriver"
 
-#if !defined(_GLES) || !defined(ECERE_STATIC)
+#if !defined(_GLES) && !defined(ECERE_STATIC)
 import "Direct3D8DisplayDriver"
 import "Direct3D9DisplayDriver"
 #endif
 
 #endif
 
-#if !defined(ECERE_NOTRUETYPE)
-
-#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]))
-   {
-      ch = HB_SurrogateToUcs4(string[0], string[1]);
-      *nw = 2;
-   }
-   else
-   {
-      ch = *string;
-      *nw = 1;
-   }
-   return ch;
-}
-
-static HB_Bool hb_stringToGlyphs(HB_Font font, const uint16 * string, uint length, HB_Glyph *glyphs, uint *numGlyphs, HB_Bool rightToLeft)
-{
-   FT_Face face = ((FontEntry)font->userData).face;
-   int glyph_pos = 0;
-   int c, nw;
-
-   if (length > *numGlyphs)
-      return 0;
-
-   for (c = 0; c < length; c += nw)
-   {
-      unichar ch = UTF16GetChar(string + c, &nw);
-      glyphs[glyph_pos++] = FT_Get_Char_Index(face, ch);
-   }
-   *numGlyphs = glyph_pos;
-   return 1;
-}
-
-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++)
-   {
-      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, const uint16 * string, uint length)
-{
-   FT_Face face = ((FontEntry)font->userData).face;
-   int c, nw;
-
-   for (c = 0; c < length; c += nw)
-   {
-      unichar ch = UTF16GetChar(string + c, &nw);
-      if(!FT_Get_Char_Index(face, ch))
-         return 0;
-   }
-   return 1;
-}
-
-static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
-{
-    FT_Face face = (FT_Face)font;
-    FT_ULong ftlen = *length;
-    FT_Error error = 0;
-
-    if (!FT_IS_SFNT(face))
-        return HB_Err_Invalid_Argument;
-
-    error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
-    *length = (uint)ftlen;
-    return (HB_Error)error;
-}
-
-static HB_Error hb_getPointInOutline(HB_Font font, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
-{
-    HB_Error error = HB_Err_Ok;
-    FT_Face face = (FT_Face)font->userData;
-
-    int load_flags = (flags & HB_ShaperFlag_UseDesignMetrics) ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT;
-
-    if ((error = (HB_Error)FT_Load_Glyph(face, glyph, load_flags)))
-        return error;
-
-    if (face->glyph->format != ft_glyph_format_outline)
-        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_SubTable;
-
-    *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 theGlyph, HB_GlyphMetrics *metrics)
-{
-   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)
-{
-   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 =
-{
-   hb_stringToGlyphs, hb_getAdvances, hb_canRender,
-   hb_getPointInOutline, hb_getGlyphMetrics, hb_getFontMetric
-};
-
-static uint FT_stream_load(FT_Stream stream, long offset, byte * buffer, long count)
-{
-    File f = stream->descriptor.pointer;
-    f.Seek((int)offset, start);
-    return count ? f.Read(buffer, 1, (uint)count) : 0;
-}
-
-static void FT_stream_close(FT_Stream stream)
-{
-   File f = stream->descriptor.pointer;
-   delete f;
-   delete stream;
-}
-
-static FT_Library ftLibrary;
-static int numFonts;
-#undef CompareString
-static BinaryTree loadedFonts
-{
-   CompareKey = (void *)BinaryTree::CompareString
-};
-
-class FontEntry : BTNode
-{
-   FT_Face face;
-   HB_FontRec hbFont;
-   HB_Face hbFace;
-
-   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()
-   {
-      delete (char *)key;
-      delete buffer;
-      if(hbFace)
-         HB_FreeFace(hbFace);
-      if(face)
-      {
-         FT_Done_Face(face);
-         numFonts--;
-         if(!numFonts)
-         {
-            FT_Done_FreeType(ftLibrary);
-            ftLibrary = null;
-         }
-      }
-   }
-}
-
-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
-{
-   int ax, ay;
-   int x, y;
-   int w, h;
-   int left, top;
-   int bx, by;
-   int glyphNo;
-   float scale;
-};
-
-class GlyphPack : BTNode
-{
-   GlyphInfo glyphs[256];
-   Bitmap bitmap { };
-
-   void Render(Font font, int startFontEntry, DisplaySystem displaySystem)
-   {
-#if !defined(ECERE_NOTRUETYPE)
-      unichar c;
-      int maxWidth, maxHeight;
-      int cellWidth, cellHeight;
-      int width, height;
-      FontEntry fontEntry = null;
-      FT_Face faces[128];
-      float scales[128];
-      bool isGlyph = ((uint)key & 0x80000000) != 0;
-      //int curScript = ((uint)key & 0x7F000000) >> 24;
-      unichar testChar = 0;
-      /*
-      if(isGlyph)
-      {
-         switch(curScript)
-         {
-            case HB_Script_Arabic:
-               testChar = 0x621;
-               // printf("\nRendering arabic in %s (%d)\n", font.faceName, key & 0xFFFFFF);
-               break;
-            case HB_Script_Devanagari:
-               testChar = 0x905;
-               break;
-            case 60: testChar = 'あ'; break;
-            case 61: testChar = 0x3400; break;
-         }
-      }
-      */
-      /*
-      FT_GlyphSlot slot;
-      FT_Matrix matrix;
-      FT_Vector pen = { 0, 0 };
-      if(font.fakeItalic)
-      {
-         matrix.xx = (FT_Fixed)( 1.0 * 0x10000L );
-         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)(font.size * 64), (int)(font.size * 64), 96, 96);
-      */
-
-      maxWidth = 0;
-      maxHeight = 0;
-
-      for(c = 0; c < MAX_FONT_LINK_ENTRIES; c++)
-      {
-         fontEntry = font.fontEntries[c];
-         if(fontEntry)
-         {
-            FT_Matrix matrix;
-            FT_Vector pen = { 0, 0 };
-
-            if(font.fakeItalic)
-            {
-               matrix.xx = (FT_Fixed)( 1.0 * 0x10000L );
-               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)(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 = (int)fontEntry.face->size->metrics.x_scale;
-            fontEntry.hbFont.y_scale = (int)fontEntry.face->size->metrics.y_scale;
-         }
-      }
-
-      fontEntry = null;
-      for(c = 0; c < 128; c++)
-      {
-         int entry = 0;
-         if(isGlyph)
-         {
-            uint glyph = ((uint)key | c) & 0xFFFFFF;
-            for(entry = startFontEntry; entry < MAX_FONT_LINK_ENTRIES; entry++)
-            {
-               fontEntry = font.fontEntries[entry];
-               if(fontEntry && (FT_Get_Char_Index(fontEntry.face, testChar) || !testChar || 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])
-                  {
-                     //printf("%s: Accepted entry %d ", font.faceName, entry);
-                     break;
-                  }
-               }
-            }
-         }
-         else
-         {
-            for(entry = startFontEntry; ; entry++)
-            {
-               uint glyph;
-               fontEntry = font.fontEntries[entry];
-               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));
-         //maxHeight = Max(maxHeight, ((faces[c]->glyph->metrics.height) >> 6));
-      }
-      cellWidth = maxWidth;
-      cellHeight = maxHeight;
-
-      width = pow2i(maxWidth * 16);
-      height = pow2i(maxHeight * 8);
-
-      if(bitmap.Allocate(null, width, height, 0, pixelFormatAlpha, false /*true*/))
-      {
-         Bitmap bitmap = this.bitmap;
-
-         bitmap.transparent = true;
-
-         for(c = 0; c < 128; c++)
-         {
-            FT_Int i, j, p, q;
-            FT_Int xMax, yMax;
-            int sx = (c % 16) * cellWidth;
-            int sy = (c / 16) * cellHeight;
-            int x, y;
-            byte * picture = (byte *)bitmap.picture;
-            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 = em_size ? (faces[c]->size->metrics.y_ppem / em_size) : 1;
-            double ascender = faces[c]->ascender * y_scale;
-            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);
-            //glyph->top = (int)(ascender - slot->bitmap_top) + 2 * ((((faces[c]->size->metrics.height + 64 + (64 - faces[c]->size->metrics.height & 0x3F)) >> 6)) - font.height);
-            //glyph->top = (int)(ascender - slot->bitmap_top) + (font.height - (faces[c]->size->metrics.height >> 6));
-
-            //glyph->top = (int)(ascender + (font.height *64 - /*faces[0]->size->metrics.height - */faces[c]->size->metrics.height) / 64.0  + 0.5) - slot->bitmap_top;
-            //glyph->top = (int)(ascender + (font.height *64 - /*faces[0]->size->metrics.height - */faces[c]->size->metrics.height) / 64.0  + 0.5) - slot->bitmap_top;
-
-            //glyph->top = (int)((ascender - slot->bitmap_top) + (font.height * 64 - maxHeight * 64 + faces[c]->glyph->metrics.height - faces[c]->glyph->metrics.height) / 64);
-
-            //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) + (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;
-            yMax = y + slot->bitmap.rows;
-
-            {
-               int total = 0;
-               int numPixels = 0;
-               //int max;
-               if(slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
-               {
-                  for(j = y, q = 0; j<yMax; j++)
-                  {
-                     for(p = 0, i = x; i<xMax; i++)
-                     {
-                        byte value = ((byte *)slot->bitmap.buffer)[q + p++];
-                        if(value > 32)
-                        {
-                           total += value;
-                           numPixels++;
-                        }
-                     }
-                     q += slot->bitmap.pitch;
-                  }
-               }
-               //max = numPixels ? (total / numPixels) : 1;
-
-               for(j = y, q = 0; j<yMax; j++)
-               {
-                  int bit = 0x80;
-                  for(p = 0, i = x; i<xMax; i++)
-                  {
-                     if(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
-                     {
-                        picture[j * bitmap.stride + i] = (slot->bitmap.buffer[q + p] & bit) ? 255 : 0;
-                        bit >>= 1;
-                        if(!bit) { bit = 0x80; p++; }
-                     }
-                     else
-                     {
-                        byte value = ((byte *)slot->bitmap.buffer)[q + p++];
-                        picture[j * bitmap.stride + i] = /*(max < 192) ? Min(255, value * 192/max) :*/ value;
-                     }
-                  }
-                  q += slot->bitmap.pitch;
-               }
-            }
-            glyph->x = sx;
-            glyph->y = sy;
-            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 = (int)slot->advance.x;
-            glyph->ay = (int)(slot->advance.y + (64 - slot->advance.y % 64));
-         }
-         #if 0
-         {
-            int c;
-            char fileName[256];
-            static int fid = 0;
-            for(c = 0; c<256; c++)
-               bitmap.palette[c] = ColorAlpha { 255, { (byte)c,(byte)c,(byte)c } };
-            bitmap.pixelFormat = pixelFormat8;
-
-            /*
-            //strcpy(fileName, faceName);
-            if(flags)
-               strcat(fileName, "Bold");
-            */
-            sprintf(fileName, "font%d", fid++);
-            ChangeExtension(fileName, "pcx", fileName);
-
-            bitmap.Save(fileName, null, 0);
-            bitmap.pixelFormat = pixelFormatAlpha;
-         }
-         #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)
-
-#if !defined(_GLES) || !defined(ECERE_STATIC)
-            || displaySystem.driver == class(Direct3D8DisplayDriver)
-            || displaySystem.driver == class(Direct3D9DisplayDriver)
-#endif
-            )
-#endif
-               bitmap.MakeDD(displaySystem);
-            displaySystem.Unlock();
-         }
-      }
-#endif
-   }
-}
-
-#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)
-{
-   static uint maxGlyphs = 0;
-   HB_Glyph * glyphs = shaper_item.glyphs;
-
-   shaper_item.kerning_applied = 0;
-   shaper_item.string = string;
-   shaper_item.stringLength = len;
-   shaper_item.item.script = script;
-   shaper_item.item.pos = 0;
-   shaper_item.item.length = shaper_item.stringLength;
-   if(script == HB_Script_Arabic || script == HB_Script_Hebrew || script == HB_Script_Thaana || script == HB_Script_Syriac)
-      shaper_item.item.bidiLevel = 1;
-   else
-      shaper_item.item.bidiLevel = 0;
-   shaper_item.shaperFlags = 0;
-   shaper_item.font = &entry.hbFont;
-   shaper_item.face = entry.hbFace;
-   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;
-
-   while(!HB_ShapeItem(&shaper_item))
-   {
-      if(shaper_item.num_glyphs > maxGlyphs)
-      {
-         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];
-         shaper_item.offsets      = renew0 shaper_item.offsets HB_FixedPoint[maxGlyphs];
-         shaper_item.log_clusters = renew0 shaper_item.log_clusters unsigned short[maxGlyphs];
-      }
-      else
-      {
-         shaper_item.glyphs = glyphs;
-         shaper_item.num_glyphs = maxGlyphs;
-      }
-  }
-
-   *numGlyphs = shaper_item.num_glyphs;
-   *rightToLeft = (bool)(shaper_item.item.bidiLevel % 2);
-   return shaper_item.glyphs;
-}
-
-/*
-   delete shaper_item.glyphs;
-   delete shaper_item.attributes;
-   delete shaper_item.advances;
-   delete shaper_item.offsets;
-   delete shaper_item.log_clusters;
-*/
-#endif
-
-public class Font : struct
-{
-   BinaryTree glyphPacks { };
-   GlyphPack asciiPack { };
-#if !defined(ECERE_NOTRUETYPE)
-   FontEntry fontEntries[MAX_FONT_LINK_ENTRIES];
-#endif
-   float size;
-   bool fakeItalic;
-   int height;
-   FontFlags flags;
-   char faceName[512];
-   DisplaySystem displaySystem;
-   int ascent;
-   float scale;
-
-   ~Font()
-   {
-#if !defined(ECERE_NOTRUETYPE)
-      GlyphPack pack;
-      while((pack = (GlyphPack)glyphPacks.root))
-      {
-         glyphPacks.Remove(pack);
-         delete pack;
-      }
-#endif
-   }
-   public property int ascent
-   {
-      get { return (int)(this ? ascent * scale : 0); }
-   }
-};
-
 public class LFBDisplay : struct
 {
 public:
@@ -814,83 +136,10 @@ static int CompareHit(GLHitRecord * recordA, GLHitRecord * recordB, const void *
       return 1;
    else if(recordA < recordB)
       return -1;
-   else
-      return  0;
-}
-*/
-
-#if defined(__WIN32__) && !defined(ECERE_NOTRUETYPE)
-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)
-   {
-      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((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];
-               DWORD type;
-               DWORD size = 1024;
-               DWORD sizeFileName = 1024;
-               char * occurrence;
-               if(RegEnumValue(key, value++, entryName, &size, null, (PDWORD)&type, (LPBYTE)fontFileName, &sizeFileName) != ERROR_SUCCESS)
-                  break;
-               if((occurrence = SearchString(entryName, 0, (const char *)font->elfFullName, false, false)))
-               {
-                  int c;
-                  for(c = (int)(occurrence - entryName) - 1; c >= 0; c--)
-                  {
-                     char ch = entryName[c];
-                     if(ch == '&') { c = -1; break; }
-                     else if(ch != ' ') break;
-                  }
-                  if(c >= 0) continue;
-                  for(c = (int)(occurrence - 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;
+   else
+      return  0;
 }
-#endif
-
-#if !defined(ECERE_NOTRUETYPE)
-static int utf16BufferSize = 0;
-static uint16 * utf16 = null;
-#endif
+*/
 
 public class LFBDisplayDriver : DisplayDriver
 {
@@ -2762,806 +2011,19 @@ public class LFBDisplayDriver : DisplayDriver
 
    void UnloadFont(DisplaySystem displaySystem, Font font)
    {
-      if(font)
-      {
-#if !defined(ECERE_NOTRUETYPE)
-         int entry;
-         for(entry = 0; entry<MAX_FONT_LINK_ENTRIES; entry++)
-         {
-            FontEntry fontEntry = font.fontEntries[entry];
-            if(fontEntry)
-            {
-               fontEntry.used--;
-               if(!fontEntry.used)
-               {
-                  loadedFonts.Remove(fontEntry);
-                  delete fontEntry;
-               }
-            }
-         }
-#endif
-         delete font;
-      }
+      delete font;
    }
 
    Font LoadFont(DisplaySystem displaySystem, const char * faceName, float size, FontFlags flags)
    {
-      void * result = null;
-
-#if !defined(ECERE_NOTRUETYPE)
-      Font font = Font { };
-      if(font)
-      {
-         char fileName[MAX_LOCATION];
-         bool fakeItalic = flags.italic;
-         int fontID = 0;
-#if !defined(__WIN32__)
-         File linkCfg;
-#endif
-         const char * ecereFonts = getenv("ECERE_FONTS");
-         if(!ecereFonts) ecereFonts = "<:ecere>";
-#if !defined(__WIN32__)
-         {
-            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))
-         {
-            strcpy(fileName, ecereFonts);
-            PathCat(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, ecereFonts);
-               PathCat(fileName, faceName);
-               if(flags.bold) strcat(fileName, "bd");
-               strcat(fileName, ".ttf");
-               strlwr(fileName);
-               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, (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, (LPARAM)&fontData, 0);
-                  fakeItalic = true;
-               }
-
-               if(fontData.fileName[0])
-               {
-                  GetWindowsDirectory(fileName, MAX_LOCATION);
-                  PathCat(fileName, "fonts");
-                  PathCat(fileName, fontData.fileName);
-               }
-               ReleaseDC(0, hdc);
-            }
-   #elif !defined(ECERE_NOFONTCONFIG)
-            {
-               char * fileName2;
-               FcResult result = 0;
-               FcPattern * pattern;
-               FcPattern * matched;
-               char * family;
-               unichar testChar = 0;
-               FcCharSet * charSet;
-               if(!fcConfig)
-                  fcConfig = FcInitLoadConfigAndFonts();
-
-               charSet = FcCharSetCreate();
-
-               if(!strcmpi(faceName, "Mangal"))
-               {
-                  testChar = 0x905;
-               }
-
-               if(testChar)
-                  FcCharSetAddChar(charSet, testChar);
-
-               pattern = FcPatternBuild(null,
-                               //FC_SOURCE, FcTypeString, "freetype",
-                               FC_FAMILY, FcTypeString, faceName,
-                               //FC_SCALABLE, FcTypeBool, 1,
-                               FC_SIZE, FcTypeDouble, (double)size,
-                               FC_WEIGHT, FcTypeInteger, flags.bold ? FC_WEIGHT_BOLD : FC_WEIGHT_MEDIUM /*FC_WEIGHT_LIGHT*/,
-                               FC_SLANT, FcTypeInteger, flags.italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN,
-                               testChar ? FC_CHARSET : 0,FcTypeCharSet, charSet,
-                               null);
-               FcDefaultSubstitute(pattern);
-               FcConfigSubstitute(fcConfig, pattern, FcMatchPattern); //FcMatchFont);
-
-               matched = FcFontMatch (0, pattern, &result);
-               // printf("Locating %s\n", faceName);
-               if(matched)
-               {
-                  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, (FcChar8 **)&fileName2);
-                  FcPatternGetInteger(matched, FC_INDEX, 0, &fontID);
-                  FcPatternGetDouble(matched, FC_SIZE, 0, &fontSize);
-                  strcpy(fileName, fileName2);
-                  // size = (float)fontSize;
-
-                  //printf("Matched to %s, %f\n", fileName, size);
-               }
-               else
-               {
-                  //printf("Could not find a match for %s, %f, %s %s (%d)\n", faceName, size, flags.bold ? "bold" : "", flags.italic ? "italic" : "", (int)result);
-               }
-               if(pattern) FcPatternDestroy(pattern);
-               if(matched) FcPatternDestroy(matched);
-               if(charSet) FcCharSetDestroy(charSet);
-            }
-   #endif
-         }
-
-         if(!FileExists(fileName))
-            ChangeExtension(fileName, "otf", fileName);
-         if(!FileExists(fileName))
-            ChangeExtension(fileName, "ttc", fileName);
-
-         //if(FileExists(fileName))
-         {
-            int entry = 0;
-            char links[1024] = "";
-            int linksPos = 0;
-#if defined(__WIN32__)
-            HKEY key;
-            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;
-               DWORD type;
-               DWORD size = 1024;
-               RegQueryValueEx(key, faceName, null, &type, (LPBYTE)links, &size);
-               memset(links + size, 0, 1024 - size);
-               RegCloseKey(key);
-            }
+#ifndef ECERE_NOTRUETYPE
+      return Font::Load(displaySystem, faceName, size, flags);
 #else
-            links[0] = 0;
-            if(linkCfg)
-            {
-               char line[512];
-               while(linkCfg.GetLine(line, sizeof(line)))
-               {
-                  int len = strlen(faceName);
-                  if(line[0] == '[' && !strncasecmp(line + 1, faceName, len) && line[len + 1] == ']')
-                  {
-                     while(linkCfg.GetLine(line, sizeof(line)))
-                     {
-                        TrimLSpaces(line, line);
-                        if(!line[0] || line[0] == '[')
-                           break;
-                        len = strlen(line);
-                        memcpy(links + linksPos, line, len);
-                        linksPos += len;
-                        links[linksPos] = 0;
-                        linksPos++;
-                     }
-                  }
-               }
-               linksPos = 0;
-            }
-#endif
-            while(entry < MAX_FONT_LINK_ENTRIES)
-            {
-               FontEntry fontEntry = (FontEntry)loadedFonts.FindString(fileName);
-               if(!fontEntry)
-               {
-                  File file = FileOpen/*Buffered*/(fileName, read);
-                  if(file)
-                  {
-                     FileSize fileSize = file.GetSize();
-                     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 = (uintptr)CopyString(fileName) };
-                     fontEntry.stream = stream;
-
-                     /*
-                     fontEntry.buffer = new byte[fileSize];
-                     file.Read(fontEntry.buffer, 1, fileSize);
-                     */
-
-                     //args.num_params = 1;
-                     args.params = &param;
-
-                     stream->size = fileSize;
-                     stream->descriptor.pointer = file;
-                     stream->read = FT_stream_load;
-                     stream->close = FT_stream_close;
-
-                     args.flags = /*FT_OPEN_PATHNAME|*//*FT_OPEN_MEMORY|*/FT_OPEN_STREAM/*|FT_OPEN_PARAMS*/;
-                     args.stream = stream;
-                     //args.pathname = fileName;
-                     //args.memory_base = fontEntry.buffer;
-                     //args.memory_size = fileSize;
-
-                     // printf("Opening: %s\n", fileName);
-                     FT_Open_Face( ftLibrary, &args, fontID, &fontEntry.face );
-
-                     // delete file;
-                     if(fontEntry.face)
-                     {
-                        fontEntry.hbFace = HB_NewFace(fontEntry.face, hb_getSFntTable);
-                        fontEntry.hbFont.klass = &hb_fontClass;
-                        fontEntry.hbFont.userData = fontEntry; //.face;
-
-                        numFonts++;
-                        loadedFonts.Add(fontEntry);
-                     }
-                     else
-                     {
-                        delete fontEntry;
-                        // printf("Error opening font %s\n", fileName);
-                     }
-                  }
-               }
-               if(fontEntry)
-               {
-                  if(!entry)
-                  {
-                     FT_Matrix matrix;
-                     FT_Vector pen = { 0, 0 };
-                     if(fakeItalic)
-                     {
-                        matrix.xx = (FT_Fixed)( 1.0 * 0x10000L );
-                        matrix.xy = (FT_Fixed)( 0.3 * 0x10000L );
-                        matrix.yx = (FT_Fixed)( 0.0 * 0x10000L );
-                        matrix.yy = (FT_Fixed)( 1.0 * 0x10000L );
-                     }
-                     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;
-                     result = font;
-                  }
-                  font.fontEntries[entry++] = fontEntry;
-                  fontEntry.used++;
-               }
-
-               {
-                  int c;
-                  char ch;
-                  char fontName[1024];
-                  if(!links[linksPos]) break;
-                  for(c = 0; (ch = links[linksPos + c]); c++)
-                  {
-                     fontName[c] = ch;
-                     if(ch == ',') break;
-                  }
-                  fontName[c] = 0;
-                  if(fontName[0] || ch == ',')
-                  {
-#if defined(__WIN32__)
-                     GetWindowsDirectory(fileName, MAX_LOCATION);
-                     PathCat(fileName, "fonts");
-                     PathCat(fileName, fontName);
-#elif !defined(ECERE_NOFONTCONFIG)
-                     if(getenv("ECERE_FONTS"))
-                     {
-                        strcpy(fileName, ecereFonts);
-                        PathCat(fileName, fontName);
-                     }
-                     else
-                     {
-                        {
-                           char * fileName2;
-                           FcResult result = 0;
-                           FcPattern * pattern;
-                           FcPattern * matched;
-                           char * family;
-                            pattern = FcPatternBuild(null,
-                                           //FC_SOURCE, FcTypeString, "freetype",
-                                           //FC_SCALABLE, FcTypeBool, 1,
-                                           FC_FAMILY, FcTypeString, links + linksPos + c + 1,
-                                           FC_SIZE, FcTypeDouble, (double)size,
-                                           FC_WEIGHT, FcTypeInteger, flags.bold ? FC_WEIGHT_BOLD : FC_WEIGHT_MEDIUM /*FC_WEIGHT_LIGHT*/,
-                                           FC_SLANT, FcTypeInteger, flags.italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN,
-                                           null);
-                           FcDefaultSubstitute(pattern);
-                           FcConfigSubstitute(fcConfig, pattern, FcMatchPattern); //FcMatchFont);
-
-                           //printf("Locating %s\n", links + linksPos + c + 1);
-                           matched = FcFontMatch (0, pattern, &result);
-                           if(matched)
-                           {
-                              FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family);
-                              // printf("Fontconfig returned %s\n", family);
-                           }
-                           if(matched && (result == FcResultMatch /*|| result == FcResultNoId*/) &&
-                              FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family) == FcResultMatch /*&& !strcmpi(family, links + linksPos + c + 1)*/)
-                           {
-                              double fontSize;
-                              FcPatternGetString (matched, FC_FILE, 0, (FcChar8 **)&fileName2);
-                              FcPatternGetInteger(matched, FC_INDEX, 0, &fontID);
-                              FcPatternGetDouble(matched, FC_SIZE, 0, &fontSize);
-                              strcpy(fileName, fileName2);
-                              //size = (float)fontSize;
-                              // printf("Matched to %s, %f\n", fileName, size);
-                           }
-                           else
-                           {
-                              // printf("Could not find a match for %s, %f, %s %s (%d)\n", links + linksPos + c + 1, size, flags.bold ? "bold" : "", flags.italic ? "italic" : "", (int)result);
-                           }
-                           if(pattern) FcPatternDestroy(pattern);
-                           if(matched) FcPatternDestroy(matched);
-                        }
-                     }
-#endif
-
-                  }
-                  linksPos += c;
-                  while(links[linksPos] && links[linksPos] != ',') linksPos++;
-                  linksPos++;
-               }
-            }
-         }
-
-         if(!result)
-            UnloadFont(displaySystem, font);
-         else
-         {
-            font.asciiPack.Render(font, 0, displaySystem);
-         }
-#if !defined(__WIN32__)
-         delete linkCfg;
-#endif
-      }
-   #endif
-      return result;
-   }
-
-#if !defined(ECERE_NOTRUETYPE)
-   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])
-      {
-         int previousGlyph = 0;
-         FT_Face previousFace = 0;
-         int c, nb, glyphIndex = 0;
-         unichar lastPack = 0;
-         GlyphPack pack = font.asciiPack;
-         int wc = 0;
-         uint * glyphs = null;
-         int numGlyphs = 0;
-         bool rightToLeft = false;
-         int fontEntryNum = 0;
-         int glyphScript = 0;
-         FontEntry curFontEntry;
-
-         pack.bitmap.alphaBlend = true;
-
-         for(c = 0; c < len || (numGlyphs && (rightToLeft ? (glyphIndex >= 0) : (glyphIndex < numGlyphs)));)
-         {
-            uint glyphNo = 0;
-            uint packNo;
-            if(numGlyphs && (rightToLeft ? (glyphIndex >= 0) : (glyphIndex < numGlyphs)))
-            {
-               glyphNo = glyphs[glyphIndex] | 0x80000000 | (glyphScript << 24);
-               rightToLeft ? glyphIndex-- : glyphIndex++;
-            }
-            else
-            {
-               HB_Script curScript = HB_Script_Common;
-               const byte * scriptStart = text + c;
-               //unichar nonASCIIch = 0;
-               unichar ch;
-               unichar ahead = 0;
-               unichar testChar = 0;
-#if !defined(__WIN32__) && !defined(ECERE_NOFONTCONFIG)
-               const char * testLang = null;
-#endif
-
-               while(true)
-               {
-                  HB_Script script = HB_Script_Common;
-                  ch = UTF8GetChar((const char *)text + c, &nb);
-                  //if(ch > 127) nonASCIIch = ch;
-                  if(!nb) break;
-                  if(ch == 32 && curScript)
-                  {
-                     if(ahead)
-                        script = curScript;
-                     else
-                     {
-                        int a;
-                        for(a = c + 1; a < c + len; a++)
-                        {
-                           if(text[a] != 32)
-                              break;
-                        }
-                        if(a < c + len)
-                        {
-                           int nb;
-                           unichar ahead = UTF8GetChar((const char *)text + a, &nb);
-                           if((ahead >= 0x590 && ahead <= 0x7C0) || (ahead >= 0xFB1D && ahead <= 0xFB4F) || (ahead >= 0xFB50 && ahead <= 0xFDFF))
-                              script = curScript;
-                        }
-                        else
-                           script = curScript;
-                     }
-                  }
-                  else if(ch < 0x370)
-                     script = HB_Script_Common;
-                  else if(ch <= 0x11FF)
-                  {
-                     switch(ch & 0xFF00)
-                     {
-                        case 0x300: script = HB_Script_Greek; break;
-                        case 0x400: script = HB_Script_Cyrillic; break;
-                        case 0x500: script = (ch < 0x530) ? HB_Script_Cyrillic : ((ch < 0x590) ? HB_Script_Armenian : HB_Script_Hebrew); break;
-                        case 0x600: script = HB_Script_Arabic; break;
-                        case 0x700: script = (ch < 0x750) ? HB_Script_Syriac : ((ch < 0x780) ? HB_Script_Arabic : ((ch < 0x7C0) ? HB_Script_Thaana : HB_Script_Common)); break;
-                        case 0x800: script = HB_Script_Common; break;   // NO CHARACTERS ASSIGNED BETWEEN 0x7C0 and 0x8FF?
-                        case 0x900: script = (ch < 0x980) ? HB_Script_Devanagari : HB_Script_Bengali; break;
-                        case 0xA00: script = (ch < 0xA80) ? HB_Script_Gurmukhi : HB_Script_Gujarati; break;
-                        case 0xB00: script = (ch < 0xB80) ? HB_Script_Oriya : HB_Script_Tamil; break;
-                        case 0xC00: script = (ch < 0xC80) ? HB_Script_Telugu : HB_Script_Kannada; break;
-                        case 0xD00: script = (ch < 0xD80) ? HB_Script_Malayalam : HB_Script_Sinhala; break;
-                        case 0xE00: script = (ch < 0xE80) ? HB_Script_Thai : HB_Script_Lao; break;
-                        case 0xF00: script = HB_Script_Tibetan; break;
-                        case 0x1000: script = (ch < 0x10A0) ? HB_Script_Myanmar : HB_Script_Georgian; break;
-                        case 0x1100: script = HB_Script_Hangul; break;
-                     }
-                  }
-                  else if(ch >= 0x1F00 && ch <= 0x1FFF) script = HB_Script_Greek;
-                  else if((ch >= 0x2D00 && ch <= 0x2D2F) || (ch >= 0x3130 && ch <= 0x318F) || (ch >= 0xAC00 && ch <= 0xD7AF) || (ch >= 0xFFA0 && ch <= 0xFFDC))
-                     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 >= 0x3040 && ch <= 0x309F) script = 60;
-                  else if(ch >= 0x3400 && ch <= 0x9FBF) script = 61;
-                  //else if(ch >= 0x4E00 && ch <= 0x9FBF) script = 61;
-                  else if(ch >= 0xFB13 && ch <= 0xFB17) script = HB_Script_Armenian;
-                  else if(ch >= 0xFB1D && ch <= 0xFB4F) script = HB_Script_Hebrew;
-                  else if(ch >= 0xFB50 && ch <= 0xFDFF) script = HB_Script_Arabic;
-                  if(curScript)
-                  {
-                     if(!script || (script != curScript))
-                        break;
-                     c += nb;
-                     if(c >= len)
-                        break;
-                  }
-                  else
-                  {
-                     if(!script || script > HB_ScriptCount) { c += nb; if(script > HB_ScriptCount) curScript = script; break; }
-                     if(!script) { c += nb; break; }
-                     curScript = script;
-                  }
-               }
-               if(!nb) break;
-               fontEntryNum = 0;
-
-               if(curScript == HB_Script_Common || curScript > HB_ScriptCount)
-               {
-                  rightToLeft = false;
-                  glyphNo = ch;
-                  theCurrentScript = 0;
-               }
-               else
-               {
-                  int len = c - (int)(scriptStart - text);
-                  int max = len * 2 + 1;
-                  if(max > utf16BufferSize)
-                  {
-                     utf16 = renew utf16 uint16[max];
-                     utf16BufferSize = max;
-                  }
-                  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;
-#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 == '\t') ? ' ' : ch;
-                  /*
-                  case 60: testChar = 'あ'; break;
-                  case 61: testChar = 0x3400; break; //'愛'; break;
-                  */
-               }
-
-               if(testChar)
-               {
-                  // printf("Testing for char %x\n", testChar);
-                  for(fontEntryNum = 0; fontEntryNum<MAX_FONT_LINK_ENTRIES; fontEntryNum++)
-                  {
-                     if(font.fontEntries[fontEntryNum] && FT_Get_Char_Index(font.fontEntries[fontEntryNum].face, testChar))
-                        break;
-                     /*if(font.fontEntries[fontEntryNum])
-                        printf("Not found in %s\n", (char *)font.fontEntries[fontEntryNum].key);*/
-                  }
-               }
-
-               if(fontEntryNum == MAX_FONT_LINK_ENTRIES)
-               {
-#if !defined(__WIN32__) && !defined(ECERE_NOFONTCONFIG)
-                  int fontID = 0;
-                  double fontSize = font.size;
-                  FcResult result = 0;
-                  FcPattern * pattern;
-                  FcPattern * matched;
-                  FcCharSet * charSet;
-                  char * family;
-                  FontEntry fontEntry;
-                  char * fileName = null;
-                  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__) && !defined(ECERE_NOFONTCONFIG)
-                  {
-                     charSet = FcCharSetCreate();
-                     FcCharSetAddChar(charSet, testChar);
-                     //printf("Loading with char %x\n", testChar);
-
-                     pattern = FcPatternBuild(null,
-                                     //FC_SOURCE, FcTypeString, "freetype",
-                                     //FC_SCALABLE, FcTypeBool, 1,
-                                     FC_FAMILY, FcTypeString, font.faceName,
-                                     FC_SIZE, FcTypeDouble, (double)font.size,
-                                     FC_WEIGHT, FcTypeInteger, font.flags.bold ? FC_WEIGHT_BOLD : FC_WEIGHT_MEDIUM,
-                                     FC_SLANT, FcTypeInteger, font.flags.italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN,
-                                     FC_CHARSET,FcTypeCharSet, charSet,
-                                     testLang ? FC_LANG : 0, FcTypeString,testLang,
-                                     null);
-                     FcDefaultSubstitute(pattern);
-                     FcConfigSubstitute(fcConfig, pattern, FcMatchPattern); //FcMatchFont);
-
-                     //printf("Locating %s for script %d\n", font.faceName, curScript);
-                     matched = FcFontMatch (0, pattern, &result);
-                     if(matched)
-                     {
-                        FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family);
-                        //printf("Fontconfig returned %s\n", family);
-                     }
-                     if(matched && (result == FcResultMatch) && FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family) == FcResultMatch)
-                     {
-                        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);
-                     }
-                     else
-                     {
-                        //printf("Could not find a match for %s, %f, %s %s (%d)\n", font.faceName, font.size, font.flags.bold ? "bold" : "", font.flags.italic ? "italic" : "", (int)result);
-                     }
-                  }
-                  if(fileName)
-                  {
-                     fontEntry = (FontEntry)loadedFonts.FindString(fileName);
-                     if(!fontEntry)
-                     {
-                        File file = FileOpen(fileName, read);
-                        if(file)
-                        {
-                           FileSize fileSize = file.GetSize();
-                           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 = (uintptr)CopyString(fileName) };
-                           fontEntry.stream = stream;
-
-                           //args.num_params = 1;
-                           args.params = &param;
-
-                           stream->size = fileSize;
-                           stream->descriptor.pointer = file;
-                           stream->read = FT_stream_load;
-                           stream->close = FT_stream_close;
-
-                           args.flags = FT_OPEN_STREAM;
-                           args.stream = stream;
-                           //args.pathname = fileName;
-                           //args.memory_base = fontEntry.buffer;
-                           //args.memory_size = fileSize;
-
-                           // printf("Opening: %s\n", fileName);
-                           FT_Open_Face( ftLibrary, &args, fontID, &fontEntry.face );
-
-                           // delete file;
-                           if(fontEntry.face)
-                           {
-                              fontEntry.hbFace = HB_NewFace(fontEntry.face, hb_getSFntTable);
-                              fontEntry.hbFont.klass = &hb_fontClass;
-                              fontEntry.hbFont.userData = fontEntry; //.face;
-
-                              numFonts++;
-                              loadedFonts.Add(fontEntry);
-                           }
-                           else
-                           {
-                              delete fontEntry;
-                              // printf("Error opening font %s\n", fileName);
-                           }
-                        }
-                     }
-                     if(fontEntry)
-                     {
-                        FaceSetCharSize(fontEntry.face, font.size);
-
-                        font.fontEntries[fontEntryNum] = fontEntry;
-                        fontEntry.used++;
-                     }
-                  }
-                  if(pattern) FcPatternDestroy(pattern);
-                  if(matched) FcPatternDestroy(matched);
-                  if(charSet) FcCharSetDestroy(charSet);
+      return { };
 #endif
-               }
-               if(curScript > HB_ScriptCount) curScript = HB_Script_Common;
-               if(curScript != HB_Script_Common && curScript < HB_ScriptCount)
-               {
-                  font.fontEntries[fontEntryNum].font = font;
-                  glyphs = shaping(font.fontEntries[fontEntryNum], utf16, wc, curScript, &numGlyphs, &rightToLeft);
-                  if(!numGlyphs)
-                     continue;
-
-                  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)
-                  pack = font.asciiPack;
-               else
-               {
-                  pack = (GlyphPack)font.glyphPacks.Find((uintptr)packNo);
-                  if(!pack)
-                  {
-                     pack = GlyphPack { key = (uintptr)packNo };
-                     font.glyphPacks.Add(pack);
-                     pack.Render(font, fontEntryNum, displaySystem);
-                  }
-               }
-               pack.bitmap.alphaBlend = true;
-               lastPack = packNo;
-            }
-            if(pack)
-            {
-               int index = rightToLeft ? (glyphIndex + 1) : (glyphIndex-1);
-               GlyphInfo * glyph = &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;
-
-               ax += offset;
-
-               if(previousGlyph && curFontEntry.face == previousFace)
-               {
-                  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;
-               }
-               else
-                  FaceSetCharSize(curFontEntry.face, font.size);
-
-               previousGlyph = glyph->glyphNo;
-               previousFace = curFontEntry.face;
-
-               if(callback)
-                  callback(surface, display, ((*x) >> 6), y + (oy >> 6), glyph, pack.bitmap);
-               *x += ax;
-            }
-            if(numGlyphs && (rightToLeft ? (glyphIndex < 0) : (glyphIndex == numGlyphs)))
-               numGlyphs = 0;
-         }
-      }
-      if(surface)
-      {
-         LFBSurface lfbSurface = surface.driverData;
-         lfbSurface.xOffset = 0;
-      }
    }
 
-#endif
-   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height)
+   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
       if(displaySystem && displaySystem.flags.text && len)
       {
@@ -3572,20 +2034,21 @@ public class LFBDisplayDriver : DisplayDriver
          }
          if(height) *height = textCellH;
       }
+#if !defined(ECERE_NOTRUETYPE)
       else if(font && len)
       {
          if(width)
          {
-            int w = 0;
-#if !defined(ECERE_NOTRUETYPE)
-            ProcessString(font, displaySystem, (const byte *)text, len, null, null, null, &w, 0);
-#endif
+            int w = 0, advance = 0;
+            font.ProcessString(displaySystem, (const byte *)text, len, null, null, null, &w, 0, prevGlyph, rPrevGlyph, &advance);
+            if(adv) *adv = advance >> 6;
             //*width = (w + 64 - w % 64) >> 6;
             *width = w >> 6;
          }
          if(height)
             *height = font.height;
       }
+#endif
       else
       {
          if(width) *width = 0;
@@ -3594,13 +2057,13 @@ public class LFBDisplayDriver : DisplayDriver
    }
 
 #if !defined(ECERE_NOTRUETYPE)
-   void ::OutputGlyph(Surface surface, Display display, int x, int y, GlyphInfo * glyph, Bitmap bitmap)
+   void ::OutputGlyph(Surface surface, Display display, int x, int y, Glyph glyph, Bitmap bitmap)
    {
-      surface.driver.Blit(display, surface, bitmap, x + glyph->left, y + glyph->top, glyph->x, glyph->y, glyph->w, glyph->h);
+      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, const char * text, int len)
+   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
    {
       LFBSurface lfbSurface = surface.driverData;
       if(display && display.displaySystem.flags.text)
@@ -3626,10 +2089,12 @@ public class LFBDisplayDriver : DisplayDriver
       }
       else
       {
+         int adv = 0;
          lfbSurface.writingText = true;
 #if !defined(ECERE_NOTRUETYPE)
          x <<= 6;
-         ProcessString(lfbSurface.font, surface.displaySystem, (const byte *)text, len, OutputGlyph, surface, display, &x, y);
+         lfbSurface.font.ProcessString(surface.displaySystem, (const byte *)text, len, OutputGlyph, surface, display, &x, y, prevGlyph, rPrevGlyph, &adv);
+         x += adv;
 #endif
          lfbSurface.writingText = false;
       }
@@ -3646,10 +2111,10 @@ public class LFBDisplayDriver : DisplayDriver
 
    }
 
-   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height)
+   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * advance)
    {
       LFBSurface lfbSurface = surface.driverData;
-      FontExtent(surface.displaySystem, lfbSurface.font, text, len, width, height);
+      FontExtent(surface.displaySystem, lfbSurface.font, text, len, width, height, prevGlyph, rPrevGlyph, advance);
    }
 
    void DrawingChar(Display display, Surface surface, byte character)
index 2e7cd19..99a0302 100644 (file)
@@ -358,13 +358,13 @@ class NCursesDisplayDriver : DisplayDriver
       ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextOpacity(display, surface, opaque);
    }
 
-   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len)
+   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
    {
       LFBSurface lfbSurface = surface.driverData;
       int c;
       uint16 * lfbPtr;
 
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len, prevGlyph, rPrevGlyph);
 
       x /= textCellW;
       y /= textCellH;
@@ -383,14 +383,14 @@ class NCursesDisplayDriver : DisplayDriver
       }
    }
 
-   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height)
+   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
    }
 
-   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height)
+   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
-      FontExtent(display.displaySystem, null, text, len, width, height);
+      FontExtent(display.displaySystem, null, text, len, width, height, prevGlyph, rPrevGlyph, adv);
    }
 
    void DrawingChar(Display display, Surface surface, char character)
index 0c3a9cd..14e99db 100644 (file)
@@ -3452,12 +3452,12 @@ class OpenGLDisplayDriver : DisplayDriver
       return font;
    }
 
-   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height)
+   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
    }
 
-   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len)
+   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
    {
       OGLSurface oglSurface = surface.driverData;
       OGLSystem oglSystem = display.displaySystem.driverData;
@@ -3469,8 +3469,9 @@ class OpenGLDisplayDriver : DisplayDriver
 
       if(surface.textOpacity)
       {
-         int w, h;
-         FontExtent(display.displaySystem, surface.font, text, len, &w, &h);
+         int w, h, adv;
+         FontExtent(display.displaySystem, surface.font, text, len, &w, &h, 0, null, &adv);
+         w += adv;
          display.displaySystem.driver.Area(display, surface,x,y,x+w-1,y+h-1);
       }
 
@@ -3479,7 +3480,7 @@ class OpenGLDisplayDriver : DisplayDriver
       glEnable(GL_TEXTURE_2D);
       glColor4fv(oglSurface.foreground);
 
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len, prevGlyph, rPrevGlyph);
       oglSurface.writingText = false;
       oglSystem.loadingFont = false;
 
@@ -3499,12 +3500,12 @@ class OpenGLDisplayDriver : DisplayDriver
       oglSurface.opaqueText = opaque;
    }
 
-   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height)
+   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
       OGLSurface oglSurface = surface.driverData;
       OGLSystem oglSystem = display.displaySystem.driverData;
       oglSystem.loadingFont = true;
-      FontExtent(display.displaySystem, oglSurface.font, text, len, width, height);
+      FontExtent(display.displaySystem, oglSurface.font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
       oglSystem.loadingFont = false;
    }
 
index b9b1b22..6d3e37a 100644 (file)
@@ -825,7 +825,7 @@ class Win32BitmapPrinterDisplayDriver : DisplayDriver
       SetBkMode(gdiSurface.hdc, opaque ? OPAQUE : TRANSPARENT);
    }
 
-   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len)
+   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
    {
       Win32BitmapPrinterSurface gdiSurface = surface.driverData;
       int wordCount;
@@ -834,7 +834,7 @@ class Win32BitmapPrinterDisplayDriver : DisplayDriver
       delete u16text;
    }
 
-   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height)
+   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
       Win32BitmapPrinterSurface gdiSurface = surface.driverData;
       SIZE space, size;
@@ -849,6 +849,7 @@ class Win32BitmapPrinterDisplayDriver : DisplayDriver
 
       // UNICODE FIX: proper space computation
       if(width) *width = size.cx + (wordCount - realLen) * space.cx;
+      if(adv) *adv = 0;
       if(height)
       {
          if(realLen)
@@ -858,7 +859,7 @@ class Win32BitmapPrinterDisplayDriver : DisplayDriver
       }
    }
 
-   void FontExtent(DisplaySystem displaySystem, void * font, const char * text, int len, int * width, int * height)
+   void FontExtent(DisplaySystem displaySystem, void * font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
       Win32BitmapPrinterSystem gdiSystem = displaySystem.driverData;
       if(gdiSystem.tmpDC)
@@ -870,13 +871,14 @@ class Win32BitmapPrinterDisplayDriver : DisplayDriver
          gdiSurface.hdc = gdiSystem.tmpDC;
 
          SelectObject(gdiSurface.hdc, font);
-         TextExtent(null, surface, text, len, width, height);
+         TextExtent(null, surface, text, len, width, height, prevGlyph, rPrevGlyph, adv);
 
          delete surface;
          delete gdiSurface;
       }
       else
       {
+         if(adv) *adv = 0;
          if(width) *width = 0;
          if(height) *height = 0;
       }
index cab5676..c3be3a9 100644 (file)
@@ -356,7 +356,7 @@ class Win32ConsoleDisplayDriver : DisplayDriver
       ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextOpacity(display, surface, opaque);
    }
 
-   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len)
+   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
    {
       CONDisplay conDisplay = display.driverData;
       LFBSurface conSurface = surface.driverData;
@@ -385,14 +385,14 @@ class Win32ConsoleDisplayDriver : DisplayDriver
       }
    }
 
-   void FontExtent(DisplaySystem displaySystem, void * font, const char * text, int len, int * width, int * height)
+   void FontExtent(DisplaySystem displaySystem, void * font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
    }
 
-   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height)
+   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
-      FontExtent(display.displaySystem, null, text, len, width, height);
+      FontExtent(display.displaySystem, null, text, len, width, height, prevGlyph, rPrevGlyph, adv);
    }
 
    void DrawingChar(Display display, Surface surface, char character)
index 33fb78e..8034060 100644 (file)
@@ -879,7 +879,7 @@ class Win32PrinterDisplayDriver : DisplayDriver
       SetBkMode(gdiSurface.hdc, opaque ? OPAQUE : TRANSPARENT);
    }
 
-   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len)
+   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
    {
       Win32PrinterSurface gdiSurface = surface.driverData;
       Win32PrinterDisplay gdiDisplay = display ? display.driverData : null;
@@ -899,7 +899,7 @@ class Win32PrinterDisplayDriver : DisplayDriver
       delete u16text;
    }
 
-   void ::_TextExtent(HDC hdc, int resX, int resY, const char * text, int len, int * width, int * height)
+   void ::_TextExtent(HDC hdc, int resX, int resY, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
       SIZE space, size;
       uint realLen;
@@ -911,6 +911,7 @@ class Win32PrinterDisplayDriver : DisplayDriver
       GetTextExtentPoint32(hdc, u16text, realLen, &size);
       delete u16text;
 
+      if(adv) *adv = 0;
       if(width)
       {
           // UNICODE FIX: proper space computation
@@ -927,25 +928,26 @@ class Win32PrinterDisplayDriver : DisplayDriver
       }
    }
 
-   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height)
+   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
       Win32PrinterSystem gdiSystem = (display && display.displaySystem) ? display.displaySystem.driverData : null;
       Win32PrinterSurface gdiSurface = surface.driverData;
 
-      _TextExtent(gdiSurface.hdc, gdiSystem.resX, gdiSystem.resY, text, len, width, height);
+      _TextExtent(gdiSurface.hdc, gdiSystem.resX, gdiSystem.resY, text, len, width, height, prevGlyph, rPrevGlyph, adv);
    }
 
-   void FontExtent(DisplaySystem displaySystem, void * font, const char * text, int len, int * width, int * height)
+   void FontExtent(DisplaySystem displaySystem, void * font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
       Win32PrinterSystem gdiSystem = displaySystem.driverData;
       if(gdiSystem.hdc)
       {
          SelectObject(gdiSystem.hdc, font);
-         _TextExtent(gdiSystem.hdc, gdiSystem.resX, gdiSystem.resY, text, len, width, height);
+         _TextExtent(gdiSystem.hdc, gdiSystem.resX, gdiSystem.resY, text, len, width, height, prevGlyph, rPrevGlyph, adv);
       }
       else
       {
          if(width) *width = 0;
+         if(adv) *adv = 0;
          if(height) *height = 0;
       }
    }
index 490815d..93bb6cc 100644 (file)
@@ -21,6 +21,7 @@ default:
 #define Time      X11Time
 #define KeyCode   X11KeyCode
 #define Picture   X11Picture
+#define Glyph     X11Glyph
 
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
@@ -37,6 +38,7 @@ default:
 #undef Time
 #undef KeyCode
 #undef Picture
+#undef Glyph
 
 #undef uint
 #undef new
@@ -1683,13 +1685,14 @@ class XDisplayDriver : DisplayDriver
    #define CHAR_WIDTH   6
    #define CHAR_HEIGHT  14
 
-   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len)
+   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
    {
       XSurface xSurface = surface.driverData;
       //XDisplay xDisplay = display.driverData;
-      int tw, th;
+      int tw, th, adv;
 
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, &tw, &th);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, &tw, &th, prevGlyph, rPrevGlyph, &adv);
+      tw += adv;
       if(xSurface.opaque)
       {
 #if 0
@@ -1718,10 +1721,10 @@ class XDisplayDriver : DisplayDriver
          x + surface.offset.x, y + surface.offset.y + 12, text, len);
       */
 
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len, prevGlyph, rPrevGlyph);
    }
 
-   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height)
+   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
       XSurface xSurface = surface.driverData;
       /*
@@ -1731,16 +1734,16 @@ class XDisplayDriver : DisplayDriver
       if(height) *height = CHAR_HEIGHT;
       */
 
-      FontExtent(display.displaySystem, xSurface.font, text, len, width, height);
+      FontExtent(display.displaySystem, xSurface.font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
    }
 
-   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height)
+   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
       /*
       if(width) *width = len * CHAR_WIDTH;
       if(height) *height = CHAR_HEIGHT;
       */
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
    }
 
    void DrawingChar(Display display, Surface surface, byte character)
diff --git a/ecere/src/gfx/fontManagement.ec b/ecere/src/gfx/fontManagement.ec
new file mode 100644 (file)
index 0000000..84c73e5
--- /dev/null
@@ -0,0 +1,458 @@
+import "File"
+
+namespace gfx;
+
+#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>
+   static FcConfig * fcConfig;
+   #undef set
+#endif
+
+#if defined(__WIN32__) && !defined(ECERE_NOTRUETYPE)
+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)
+   {
+      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((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];
+               DWORD type;
+               DWORD size = 1024;
+               DWORD sizeFileName = 1024;
+               char * occurrence;
+               if(RegEnumValue(key, value++, entryName, &size, null, (PDWORD)&type, (LPBYTE)fontFileName, &sizeFileName) != ERROR_SUCCESS)
+                  break;
+               if((occurrence = SearchString(entryName, 0, (const char *)font->elfFullName, false, false)))
+               {
+                  int c;
+                  for(c = (int)(occurrence - entryName) - 1; c >= 0; c--)
+                  {
+                     char ch = entryName[c];
+                     if(ch == '&') { c = -1; break; }
+                     else if(ch != ' ') break;
+                  }
+                  if(c >= 0) continue;
+                  for(c = (int)(occurrence - 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;
+}
+#endif
+
+public class FaceInfo : struct
+{
+   String fileName;
+   bool fakeItalic;
+   int fontID;
+
+   ~FaceInfo() { delete fileName; }
+}
+
+public Array<FaceInfo> ResolveFont(const String faceName, float size, FontFlags flags)
+{
+   Array<FaceInfo> fileNames { };
+#if !defined(ECERE_NOTRUETYPE)
+   char fileName[MAX_LOCATION];
+   bool fakeItalic = flags.italic;
+   int fontID = 0;
+#if !defined(__WIN32__)
+   File linkCfg;
+#endif
+   const char * ecereFonts = getenv("ECERE_FONTS");
+   if(!ecereFonts) ecereFonts = "<:ecere>";
+#if !defined(__WIN32__)
+   {
+      char linkCfgPath[MAX_LOCATION];
+
+      strcpy(linkCfgPath, ecereFonts);
+      PathCat(linkCfgPath, "linking.cfg");
+      linkCfg = FileOpen(linkCfgPath, read);
+   }
+#endif
+   strcpy(fileName, faceName);
+
+   if(!FileExists(fileName))
+   {
+      strcpy(fileName, ecereFonts);
+      PathCat(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, ecereFonts);
+         PathCat(fileName, faceName);
+         if(flags.bold) strcat(fileName, "bd");
+         strcat(fileName, ".ttf");
+         strlwr(fileName);
+         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, (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, (LPARAM)&fontData, 0);
+            fakeItalic = true;
+         }
+
+         if(fontData.fileName[0])
+         {
+            GetWindowsDirectory(fileName, MAX_LOCATION);
+            PathCat(fileName, "fonts");
+            PathCat(fileName, fontData.fileName);
+         }
+         ReleaseDC(0, hdc);
+      }
+#elif !defined(ECERE_NOFONTCONFIG)
+      {
+         char * fileName2;
+         FcResult result = 0;
+         FcPattern * pattern;
+         FcPattern * matched;
+         char * family;
+         unichar testChar = 0;
+         FcCharSet * charSet;
+         if(!fcConfig)
+            fcConfig = FcInitLoadConfigAndFonts();
+
+         charSet = FcCharSetCreate();
+
+         if(!strcmpi(faceName, "Mangal"))
+         {
+            testChar = 0x905;
+         }
+
+         if(testChar)
+            FcCharSetAddChar(charSet, testChar);
+
+         pattern = FcPatternBuild(null,
+                         //FC_SOURCE, FcTypeString, "freetype",
+                         FC_FAMILY, FcTypeString, faceName,
+                         //FC_SCALABLE, FcTypeBool, 1,
+                         FC_SIZE, FcTypeDouble, (double)size,
+                         FC_WEIGHT, FcTypeInteger, flags.bold ? FC_WEIGHT_BOLD : FC_WEIGHT_MEDIUM /*FC_WEIGHT_LIGHT*/,
+                         FC_SLANT, FcTypeInteger, flags.italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN,
+                         testChar ? FC_CHARSET : 0,FcTypeCharSet, charSet,
+                         null);
+         FcDefaultSubstitute(pattern);
+         FcConfigSubstitute(fcConfig, pattern, FcMatchPattern); //FcMatchFont);
+
+         matched = FcFontMatch (0, pattern, &result);
+         // printf("Locating %s\n", faceName);
+         if(matched)
+         {
+            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, (FcChar8 **)&fileName2);
+            FcPatternGetInteger(matched, FC_INDEX, 0, &fontID);
+            FcPatternGetDouble(matched, FC_SIZE, 0, &fontSize);
+            strcpy(fileName, fileName2);
+            // size = (float)fontSize;
+
+            //printf("Matched to %s, %f\n", fileName, size);
+         }
+         else
+         {
+            //printf("Could not find a match for %s, %f, %s %s (%d)\n", faceName, size, flags.bold ? "bold" : "", flags.italic ? "italic" : "", (int)result);
+         }
+         if(pattern) FcPatternDestroy(pattern);
+         if(matched) FcPatternDestroy(matched);
+         if(charSet) FcCharSetDestroy(charSet);
+      }
+#endif
+   }
+
+   if(!FileExists(fileName))
+      ChangeExtension(fileName, "otf", fileName);
+   if(!FileExists(fileName))
+      ChangeExtension(fileName, "ttc", fileName);
+
+   //if(FileExists(fileName))
+   {
+      char links[1024] = "";
+      int linksPos = 0;
+#if defined(__WIN32__)
+      HKEY key;
+      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;
+         DWORD type;
+         DWORD size = 1024;
+         RegQueryValueEx(key, faceName, null, &type, (LPBYTE)links, &size);
+         memset(links + size, 0, 1024 - size);
+         RegCloseKey(key);
+      }
+#else
+      links[0] = 0;
+      if(linkCfg)
+      {
+         char line[512];
+         while(linkCfg.GetLine(line, sizeof(line)))
+         {
+            int len = strlen(faceName);
+            if(line[0] == '[' && !strncasecmp(line + 1, faceName, len) && line[len + 1] == ']')
+            {
+               while(linkCfg.GetLine(line, sizeof(line)))
+               {
+                  TrimLSpaces(line, line);
+                  if(!line[0] || line[0] == '[')
+                     break;
+                  len = strlen(line);
+                  memcpy(links + linksPos, line, len);
+                  linksPos += len;
+                  links[linksPos] = 0;
+                  linksPos++;
+               }
+            }
+         }
+         linksPos = 0;
+      }
+#endif
+      while(true)
+      {
+         FaceInfo faceInfo
+         {
+            fileName = CopyString(fileName),
+            fakeItalic = fakeItalic,
+            fontID = fontID
+         };
+         fileNames.Add(faceInfo);
+         {
+            int c;
+            char ch;
+            char fontName[1024];
+            if(!links[linksPos]) break;
+            for(c = 0; (ch = links[linksPos + c]); c++)
+            {
+               fontName[c] = ch;
+               if(ch == ',') break;
+            }
+            fontName[c] = 0;
+            if(fontName[0] || ch == ',')
+            {
+#if defined(__WIN32__)
+               GetWindowsDirectory(fileName, MAX_LOCATION);
+               PathCat(fileName, "fonts");
+               PathCat(fileName, fontName);
+#elif !defined(ECERE_NOFONTCONFIG)
+               if(getenv("ECERE_FONTS"))
+               {
+                  strcpy(fileName, ecereFonts);
+                  PathCat(fileName, fontName);
+               }
+               else
+               {
+                  {
+                     char * fileName2;
+                     FcResult result = 0;
+                     FcPattern * pattern;
+                     FcPattern * matched;
+                     char * family;
+                      pattern = FcPatternBuild(null,
+                                     //FC_SOURCE, FcTypeString, "freetype",
+                                     //FC_SCALABLE, FcTypeBool, 1,
+                                     FC_FAMILY, FcTypeString, links + linksPos + c + 1,
+                                     FC_SIZE, FcTypeDouble, (double)size,
+                                     FC_WEIGHT, FcTypeInteger, flags.bold ? FC_WEIGHT_BOLD : FC_WEIGHT_MEDIUM /*FC_WEIGHT_LIGHT*/,
+                                     FC_SLANT, FcTypeInteger, flags.italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN,
+                                     null);
+                     FcDefaultSubstitute(pattern);
+                     FcConfigSubstitute(fcConfig, pattern, FcMatchPattern); //FcMatchFont);
+
+                     //printf("Locating %s\n", links + linksPos + c + 1);
+                     matched = FcFontMatch (0, pattern, &result);
+                     if(matched)
+                     {
+                        FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family);
+                        // printf("Fontconfig returned %s\n", family);
+                     }
+                     if(matched && (result == FcResultMatch /*|| result == FcResultNoId*/) &&
+                        FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family) == FcResultMatch /*&& !strcmpi(family, links + linksPos + c + 1)*/)
+                     {
+                        double fontSize;
+                        FcPatternGetString (matched, FC_FILE, 0, (FcChar8 **)&fileName2);
+                        FcPatternGetInteger(matched, FC_INDEX, 0, &fontID);
+                        FcPatternGetDouble(matched, FC_SIZE, 0, &fontSize);
+                        strcpy(fileName, fileName2);
+                        //size = (float)fontSize;
+                        // printf("Matched to %s, %f\n", fileName, size);
+                     }
+                     else
+                     {
+                        // printf("Could not find a match for %s, %f, %s %s (%d)\n", links + linksPos + c + 1, size, flags.bold ? "bold" : "", flags.italic ? "italic" : "", (int)result);
+                     }
+                     if(pattern) FcPatternDestroy(pattern);
+                     if(matched) FcPatternDestroy(matched);
+                  }
+               }
+#endif
+
+            }
+            linksPos += c;
+            while(links[linksPos] && links[linksPos] != ',') linksPos++;
+            linksPos++;
+         }
+      }
+   }
+
+#if !defined(__WIN32__)
+   delete linkCfg;
+#endif
+
+#endif
+   return fileNames;
+}
+
+public FaceInfo ResolveCharFont(const String faceName, float size, FontFlags flags, const String lang, unichar testChar)
+{
+   FaceInfo info = null;
+#if !defined(__WIN32__) && !defined(ECERE_NOFONTCONFIG)
+   int fontID = 0;
+   double fontSize = size;
+   FcResult result = 0;
+   FcPattern * pattern;
+   FcPattern * matched;
+   FcCharSet * charSet = FcCharSetCreate();
+   String family;
+   String fileName = null;
+
+   FcCharSetAddChar(charSet, testChar);
+   //printf("Loading with char %x\n", testChar);
+
+   pattern = FcPatternBuild(null,
+                   //FC_SOURCE, FcTypeString, "freetype",
+                   //FC_SCALABLE, FcTypeBool, 1,
+                   FC_FAMILY, FcTypeString, faceName,
+                   FC_SIZE, FcTypeDouble, (double)size,
+                   FC_WEIGHT, FcTypeInteger, flags.bold ? FC_WEIGHT_BOLD : FC_WEIGHT_MEDIUM,
+                   FC_SLANT, FcTypeInteger, flags.italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN,
+                   FC_CHARSET,FcTypeCharSet, charSet,
+                   lang ? FC_LANG : 0, FcTypeString, lang,
+                   null);
+   FcDefaultSubstitute(pattern);
+   FcConfigSubstitute(fcConfig, pattern, FcMatchPattern); //FcMatchFont);
+
+   //printf("Locating %s for script %d\n", faceName, curScript);
+   matched = FcFontMatch (0, pattern, &result);
+   if(matched)
+   {
+      FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family);
+      //printf("Fontconfig returned %s\n", family);
+   }
+   if(matched && (result == FcResultMatch) && FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family) == FcResultMatch)
+   {
+      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);
+
+      info =
+      {
+         fileName = CopyString(fileName);
+         fontID = fontID
+      };
+   }
+   else
+   {
+      //printf("Could not find a match for %s, %f, %s %s (%d)\n", faceName, size, flags.bold ? "bold" : "", flags.italic ? "italic" : "", (int)result);
+   }
+   if(pattern) FcPatternDestroy(pattern);
+   if(matched) FcPatternDestroy(matched);
+   if(charSet) FcCharSetDestroy(charSet);
+#endif
+   return info;
+}
diff --git a/ecere/src/gfx/fontRendering.ec b/ecere/src/gfx/fontRendering.ec
new file mode 100644 (file)
index 0000000..4d1667b
--- /dev/null
@@ -0,0 +1,1155 @@
+namespace gfx;
+
+import "fontManagement"
+
+#if (defined(ECERE_VANILLA) || defined(ECERE_ONEDRIVER)) && defined(__WIN32__)
+#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 FT_UNPATENTED_HINTING_H
+   #define property  _property
+   #include "harfbuzz.h"
+   #undef property
+#endif
+#undef uint
+#undef strlen
+
+#if !defined(ECERE_NOTRUETYPE)
+static int utf16BufferSize = 0;
+static uint16 * utf16 = null;
+#endif
+
+#if !defined(ECERE_NOTRUETYPE)
+
+#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]))
+   {
+      ch = HB_SurrogateToUcs4(string[0], string[1]);
+      *nw = 2;
+   }
+   else
+   {
+      ch = *string;
+      *nw = 1;
+   }
+   return ch;
+}
+
+static HB_Bool hb_stringToGlyphs(HB_Font font, const uint16 * string, uint length, HB_Glyph *glyphs, uint *numGlyphs, HB_Bool rightToLeft)
+{
+   FT_Face face = ((FontEntry)font->userData).face;
+   int glyph_pos = 0;
+   int c, nw;
+
+   if (length > *numGlyphs)
+      return 0;
+
+   for (c = 0; c < length; c += nw)
+   {
+      unichar ch = UTF16GetChar(string + c, &nw);
+      glyphs[glyph_pos++] = FT_Get_Char_Index(face, ch);
+   }
+   *numGlyphs = glyph_pos;
+   return 1;
+}
+
+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++)
+   {
+      Glyph * 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, const uint16 * string, uint length)
+{
+   FT_Face face = ((FontEntry)font->userData).face;
+   int c, nw;
+
+   for (c = 0; c < length; c += nw)
+   {
+      unichar ch = UTF16GetChar(string + c, &nw);
+      if(!FT_Get_Char_Index(face, ch))
+         return 0;
+   }
+   return 1;
+}
+
+static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
+{
+    FT_Face face = (FT_Face)font;
+    FT_ULong ftlen = *length;
+    FT_Error error = 0;
+
+    if (!FT_IS_SFNT(face))
+        return HB_Err_Invalid_Argument;
+
+    error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
+    *length = (uint)ftlen;
+    return (HB_Error)error;
+}
+
+static HB_Error hb_getPointInOutline(HB_Font font, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
+{
+    HB_Error error = HB_Err_Ok;
+    FT_Face face = (FT_Face)font->userData;
+
+    int load_flags = (flags & HB_ShaperFlag_UseDesignMetrics) ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT;
+
+    if ((error = (HB_Error)FT_Load_Glyph(face, glyph, load_flags)))
+        return error;
+
+    if (face->glyph->format != ft_glyph_format_outline)
+        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_SubTable;
+
+    *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 theGlyph, HB_GlyphMetrics *metrics)
+{
+   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;
+   }
+   {
+      Glyph * 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)
+{
+   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 =
+{
+   hb_stringToGlyphs, hb_getAdvances, hb_canRender,
+   hb_getPointInOutline, hb_getGlyphMetrics, hb_getFontMetric
+};
+
+static uint FT_stream_load(FT_Stream stream, long offset, byte * buffer, long count)
+{
+    File f = stream->descriptor.pointer;
+    f.Seek((int)offset, start);
+    return count ? f.Read(buffer, 1, (uint)count) : 0;
+}
+
+static void FT_stream_close(FT_Stream stream)
+{
+   File f = stream->descriptor.pointer;
+   delete f;
+   delete stream;
+}
+
+static FT_Library ftLibrary;
+static int numFonts;
+#undef CompareString
+static BinaryTree loadedFonts
+{
+   CompareKey = (void *)BinaryTree::CompareString
+};
+
+class FontEntry : BTNode
+{
+   FT_Face face;
+   HB_FontRec hbFont;
+   HB_Face hbFace;
+
+   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()
+   {
+      delete (char *)key;
+      delete buffer;
+      if(hbFace)
+         HB_FreeFace(hbFace);
+      if(face)
+      {
+         FT_Done_Face(face);
+         numFonts--;
+         if(!numFonts)
+         {
+            FT_Done_FreeType(ftLibrary);
+            ftLibrary = null;
+         }
+      }
+   }
+
+   FontEntry ::Load(FaceInfo info)
+   {
+      FontEntry fontEntry = (FontEntry)loadedFonts.FindString(info.fileName);
+      if(!fontEntry)
+      {
+         File file = FileOpen/*Buffered*/(info.fileName, read);
+         if(file)
+         {
+            FileSize fileSize = file.GetSize();
+            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 = (uintptr)CopyString(info.fileName) };
+            fontEntry.stream = stream;
+
+            /*
+            fontEntry.buffer = new byte[fileSize];
+            file.Read(fontEntry.buffer, 1, fileSize);
+            */
+
+            //args.num_params = 1;
+            args.params = &param;
+
+            stream->size = fileSize;
+            stream->descriptor.pointer = file;
+            stream->read = FT_stream_load;
+            stream->close = FT_stream_close;
+
+            args.flags = /*FT_OPEN_PATHNAME|*//*FT_OPEN_MEMORY|*/FT_OPEN_STREAM/*|FT_OPEN_PARAMS*/;
+            args.stream = stream;
+            //args.pathname = fileName;
+            //args.memory_base = fontEntry.buffer;
+            //args.memory_size = fileSize;
+
+            // printf("Opening: %s\n", fileName);
+            FT_Open_Face( ftLibrary, &args, info.fontID, &fontEntry.face );
+
+            // delete file;
+            if(fontEntry.face)
+            {
+               fontEntry.hbFace = HB_NewFace(fontEntry.face, hb_getSFntTable);
+               fontEntry.hbFont.klass = &hb_fontClass;
+               fontEntry.hbFont.userData = fontEntry; //.face;
+
+               numFonts++;
+               loadedFonts.Add(fontEntry);
+            }
+            else
+            {
+               delete fontEntry;
+               // printf("Error opening font %s\n", fileName);
+            }
+         }
+      }
+      return fontEntry;
+   }
+}
+
+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 Glyph
+{
+   int ax, ay;
+   int x, y;
+   int w, h;
+   int left, top;
+   int bx, by;
+   int glyphNo;
+   float scale;
+};
+
+class GlyphPack : BTNode
+{
+   Glyph glyphs[256];
+   Bitmap bitmap { };
+   int cellWidth, cellHeight;
+
+   void Render(Font font, int startFontEntry, DisplaySystem displaySystem)
+   {
+#if !defined(ECERE_NOTRUETYPE)
+      unichar c;
+      int maxWidth, maxHeight;
+      int cellWidth, cellHeight;
+      int width, height;
+      FontEntry fontEntry = null;
+      FT_Face faces[128];
+      float scales[128];
+      bool isGlyph = ((uint)key & 0x80000000) != 0;
+      //int curScript = ((uint)key & 0x7F000000) >> 24;
+      unichar testChar = 0;
+      /*
+      if(isGlyph)
+      {
+         switch(curScript)
+         {
+            case HB_Script_Arabic:
+               testChar = 0x621;
+               // printf("\nRendering arabic in %s (%d)\n", faceName, key & 0xFFFFFF);
+               break;
+            case HB_Script_Devanagari:
+               testChar = 0x905;
+               break;
+            case 60: testChar = 'あ'; break;
+            case 61: testChar = 0x3400; break;
+         }
+      }
+      */
+      /*
+      FT_GlyphSlot slot;
+      FT_Matrix matrix;
+      FT_Vector pen = { 0, 0 };
+      if(fakeItalic)
+      {
+         matrix.xx = (FT_Fixed)( 1.0 * 0x10000L );
+         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);
+      */
+
+      maxWidth = 0;
+      maxHeight = 0;
+
+      for(c = 0; c < MAX_FONT_LINK_ENTRIES; c++)
+      {
+         fontEntry = font.fontEntries[c];
+         if(fontEntry)
+         {
+            FT_Matrix matrix;
+            FT_Vector pen = { 0, 0 };
+
+            if(font.fakeItalic)
+            {
+               matrix.xx = (FT_Fixed)( 1.0 * 0x10000L );
+               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);
+            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);
+                  font.descent = (int)((double)fontEntry.face->descender);
+               }
+               else
+               {
+                  font.ascent = (int)((double)fontEntry.face->ascender * fontEntry.face->size->metrics.y_ppem / fontEntry.face->units_per_EM);
+                  font.descent = (int)((double)fontEntry.face->descender * 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 = (int)fontEntry.face->size->metrics.x_scale;
+            fontEntry.hbFont.y_scale = (int)fontEntry.face->size->metrics.y_scale;
+         }
+      }
+
+      fontEntry = null;
+      for(c = 0; c < 128; c++)
+      {
+         int entry = 0;
+         if(isGlyph)
+         {
+            uint glyph = ((uint)key | c) & 0xFFFFFF;
+            for(entry = startFontEntry; entry < MAX_FONT_LINK_ENTRIES; entry++)
+            {
+               fontEntry = font.fontEntries[entry];
+               if(fontEntry && (FT_Get_Char_Index(fontEntry.face, testChar) || !testChar || 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])
+                  {
+                     //printf("%s: Accepted entry %d ", faceName, entry);
+                     break;
+                  }
+               }
+            }
+         }
+         else
+         {
+            for(entry = startFontEntry; entry < MAX_FONT_LINK_ENTRIES; entry++)
+            {
+               uint glyph;
+               fontEntry = font.fontEntries[entry];
+               if(fontEntry && ((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 ? fontEntry.scale : 0;
+         faces[c] = fontEntry ? fontEntry.face : null;
+         if(fontEntry)
+         {
+            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));
+         }
+      }
+      this.cellWidth = cellWidth = maxWidth;
+      this.cellHeight = cellHeight = maxHeight;
+
+      width = maxWidth * 16;
+      height = maxHeight * 8;
+
+      if(true)
+      {
+         width = pow2i(width);
+         height = pow2i(height);
+      }
+
+      if(bitmap.Allocate(null, width, height, 0, pixelFormatAlpha, false /*true*/))
+      {
+         Bitmap bitmap = this.bitmap;
+
+         bitmap.transparent = true;
+
+         for(c = 0; c < 128; c++)
+         {
+            FT_Int i, j, p, q;
+            FT_Int xMax, yMax;
+            int sx = (c % 16) * cellWidth;
+            int sy = (c / 16) * cellHeight;
+            int x, y;
+            byte * picture = (byte *)bitmap.picture;
+            Glyph * glyph = &glyphs[c];
+            FT_GlyphSlot slot = null;
+            int glyphNo = isGlyph ? (((uint)key | c) & 0x00FFFFFF) : (faces[c] ? FT_Get_Char_Index(faces[c], (uint)key | c) : 0);
+            if(faces[c])
+            {
+               double em_size = 1.0 * faces[c]->units_per_EM;
+               //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;
+               slot = faces[c]->glyph;
+
+               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) + height - (faces[c]->size->metrics.height >> 6);
+               // glyph->top = (int)(ascender - slot->bitmap_top) + 2 * (height - maxHeight);
+               //glyph->top = (int)(ascender - slot->bitmap_top) + 2 * ((((faces[c]->size->metrics.height + 64 + (64 - faces[c]->size->metrics.height & 0x3F)) >> 6)) - height);
+               //glyph->top = (int)(ascender - slot->bitmap_top) + (height - (faces[c]->size->metrics.height >> 6));
+
+               //glyph->top = (int)(ascender + (height *64 - /*faces[0]->size->metrics.height - */faces[c]->size->metrics.height) / 64.0  + 0.5) - slot->bitmap_top;
+               //glyph->top = (int)(ascender + (height *64 - /*faces[0]->size->metrics.height - */faces[c]->size->metrics.height) / 64.0  + 0.5) - slot->bitmap_top;
+
+               //glyph->top = (int)((ascender - slot->bitmap_top) + (height * 64 - maxHeight * 64 + faces[c]->glyph->metrics.height - faces[c]->glyph->metrics.height) / 64);
+
+               //glyph->top = (int)(ascender - slot->bitmap_top); // + ((faces[c]->size->metrics.height >> 6) - (faces[0]->size->metrics.height >> 6)) + (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)) + (height - (faces[c]->size->metrics.height >> 6));
+
+               //glyph->top = (int)(ascender - slot->bitmap_top);// + (height - maxHeight);
+               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;
+               yMax = y + slot->bitmap.rows;
+
+               {
+                  int total = 0;
+                  int numPixels = 0;
+                  //int max;
+                  if(slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
+                  {
+                     for(j = y, q = 0; j<yMax; j++)
+                     {
+                        for(p = 0, i = x; i<xMax; i++)
+                        {
+                           byte value = ((byte *)slot->bitmap.buffer)[q + p++];
+                           if(value > 32)
+                           {
+                              total += value;
+                              numPixels++;
+                           }
+                        }
+                        q += slot->bitmap.pitch;
+                     }
+                  }
+                  //max = numPixels ? (total / numPixels) : 1;
+
+                  for(j = y, q = 0; j<yMax; j++)
+                  {
+                     int bit = 0x80;
+                     for(p = 0, i = x; i<xMax; i++)
+                     {
+                        if(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
+                        {
+                           picture[j * bitmap.stride + i] = (slot->bitmap.buffer[q + p] & bit) ? 255 : 0;
+                           bit >>= 1;
+                           if(!bit) { bit = 0x80; p++; }
+                        }
+                        else
+                        {
+                           byte value = ((byte *)slot->bitmap.buffer)[q + p++];
+                           picture[j * bitmap.stride + i] = /*(max < 192) ? Min(255, value * 192/max) :*/ value;
+                        }
+                     }
+                     q += slot->bitmap.pitch;
+                  }
+               }
+            }
+            glyph->x = sx;
+            glyph->y = sy;
+            if(slot)
+            {
+               glyph->w = slot->bitmap.width;
+               glyph->h = slot->bitmap.rows;
+               glyph->ax = (int)slot->advance.x;
+               glyph->ay = (int)(slot->advance.y + (64 - slot->advance.y % 64));
+            }
+            glyph->glyphNo = glyphNo;
+            if(faces[c])
+            {
+               glyph->bx = (int)faces[c]->glyph->metrics.horiBearingX;
+               glyph->by = (int)faces[c]->glyph->metrics.horiBearingY;
+            }
+            glyph->scale = scales[c];
+         }
+         #if 0
+         {
+            int c;
+            char fileName[256];
+            static int fid = 0;
+            for(c = 0; c<256; c++)
+               bitmap.palette[c] = ColorAlpha { 255, { (byte)c,(byte)c,(byte)c } };
+            bitmap.pixelFormat = pixelFormat8;
+
+            /*
+            //strcpy(fileName, faceName);
+            if(flags)
+               strcat(fileName, "Bold");
+            */
+            sprintf(fileName, "font%d", fid++);
+            ChangeExtension(fileName, "pcx", fileName);
+
+            bitmap.Save(fileName, null, 0);
+            bitmap.pixelFormat = pixelFormatAlpha;
+         }
+         #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)
+
+#if !defined(_GLES) && !defined(ECERE_STATIC)
+            || displaySystem.driver == class(Direct3D8DisplayDriver)
+            || displaySystem.driver == class(Direct3D9DisplayDriver)
+#endif
+
+               )
+#endif
+               bitmap.MakeDD(displaySystem);
+            displaySystem.Unlock();
+         }
+      }
+#endif
+   }
+}
+
+#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)
+{
+   static uint maxGlyphs = 0;
+   HB_Glyph * glyphs = shaper_item.glyphs;
+
+   shaper_item.kerning_applied = 0;
+   shaper_item.string = string;
+   shaper_item.stringLength = len;
+   shaper_item.item.script = script;
+   shaper_item.item.pos = 0;
+   shaper_item.item.length = shaper_item.stringLength;
+   if(script == HB_Script_Arabic || script == HB_Script_Hebrew || script == HB_Script_Thaana || script == HB_Script_Syriac)
+      shaper_item.item.bidiLevel = 1;
+   else
+      shaper_item.item.bidiLevel = 0;
+   shaper_item.shaperFlags = 0;
+   shaper_item.font = &entry.hbFont;
+   shaper_item.face = entry.hbFace;
+   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;
+
+   while(!HB_ShapeItem(&shaper_item))
+   {
+      if(shaper_item.num_glyphs > maxGlyphs)
+      {
+         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];
+         shaper_item.offsets      = renew0 shaper_item.offsets HB_FixedPoint[maxGlyphs];
+         shaper_item.log_clusters = renew0 shaper_item.log_clusters unsigned short[maxGlyphs];
+      }
+      else
+      {
+         shaper_item.glyphs = glyphs;
+         shaper_item.num_glyphs = maxGlyphs;
+      }
+  }
+
+   *numGlyphs = shaper_item.num_glyphs;
+   *rightToLeft = (bool)(shaper_item.item.bidiLevel % 2);
+   return shaper_item.glyphs;
+}
+
+/*
+   delete shaper_item.glyphs;
+   delete shaper_item.attributes;
+   delete shaper_item.advances;
+   delete shaper_item.offsets;
+   delete shaper_item.log_clusters;
+*/
+#endif
+
+public class Font : struct
+{
+   char faceName[512];
+   FontFlags flags;
+   float size;
+   int ascent, descent;
+   float scale;
+
+   BinaryTree glyphPacks { };
+   GlyphPack asciiPack { };
+   bool fakeItalic;
+   int height;
+   DisplaySystem displaySystem;
+   int numEntries;
+#if !defined(ECERE_NOTRUETYPE)
+   FontEntry fontEntries[MAX_FONT_LINK_ENTRIES];
+#endif
+
+   ~Font()
+   {
+      int entry;
+
+#if !defined(ECERE_NOTRUETYPE)
+      GlyphPack pack;
+      while((pack = (GlyphPack)glyphPacks.root))
+      {
+         glyphPacks.Remove(pack);
+         delete pack;
+      }
+#endif
+
+#if !defined(ECERE_NOTRUETYPE)
+      for(entry = 0; entry<MAX_FONT_LINK_ENTRIES; entry++)
+      {
+         FontEntry fontEntry = fontEntries[entry];
+         if(fontEntry)
+         {
+            fontEntry.used--;
+            if(!fontEntry.used)
+            {
+               loadedFonts.Remove(fontEntry);
+               delete fontEntry;
+            }
+         }
+      }
+#endif
+   }
+   public property int ascent
+   {
+      get { return (int)(this ? ascent * scale : 0); }
+   }
+   public property int descent
+   {
+      get { return (int)(this ? descent * scale : 0); }
+   }
+
+   void Setup(DisplaySystem displaySystem, const String faceName, float size, FontFlags flags)
+   {
+      strcpy(this.faceName, faceName);
+      this.flags = flags;
+      this.displaySystem = displaySystem;
+      this.size = size;
+   }
+
+   bool LoadEntry(FaceInfo info)
+   {
+      bool result = false;
+      if(numEntries < MAX_FONT_LINK_ENTRIES)
+      {
+         FontEntry fontEntry = FontEntry::Load(info);
+         if(fontEntry)
+         {
+            if(!numEntries)
+            {
+               FT_Matrix matrix;
+               FT_Vector pen = { 0, 0 };
+               if(fakeItalic)
+               {
+                  matrix.xx = (FT_Fixed)( 1.0 * 0x10000L );
+                  matrix.xy = (FT_Fixed)( 0.3 * 0x10000L );
+                  matrix.yx = (FT_Fixed)( 0.0 * 0x10000L );
+                  matrix.yy = (FT_Fixed)( 1.0 * 0x10000L );
+               }
+               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);
+               height = (int)((fontEntry.face->size->metrics.height) >> 6); //* y_scale;
+               // printf("Font height is %d\n", height);
+               this.fakeItalic = info.fakeItalic;
+            }
+            fontEntries[numEntries++] = fontEntry;
+            fontEntry.used++;
+
+            result = true;
+         }
+      }
+      return result;
+   }
+
+   Font ::Load(DisplaySystem displaySystem, const char * faceName, float size, FontFlags flags)
+   {
+      Font result = null;
+      Array<FaceInfo> infos = ResolveFont(faceName, size, flags);
+      if(infos)
+      {
+         Font font { };
+         bool success = false;
+         font.Setup(displaySystem, faceName, size, flags);
+         for(f : infos)
+            success |= font.LoadEntry(f);
+         if(success)
+         {
+            font.asciiPack.Render(font, 0, displaySystem);
+            result = font;
+         }
+         else
+            delete font;
+         infos.Free();
+         delete infos;
+      }
+      return result;
+   }
+
+   void ProcessString(DisplaySystem displaySystem, const byte * text, int len,
+                      void (* callback)(Surface surface, Display display, int x, int y, Glyph glyph, Bitmap bitmap),
+                      Surface surface, Display display, int * x, int y, int prevGlyph, int * rPrevGlyph, int * advance)
+   {
+#if !defined(ECERE_NOTRUETYPE)
+      if(this && fontEntries[0])
+      {
+         int previousGlyph = prevGlyph;
+         FT_Face previousFace = 0;
+         int c, nb, glyphIndex = 0;
+         unichar lastPack = 0;
+         GlyphPack pack = asciiPack;
+         int wc = 0;
+         uint * glyphs = null;
+         int numGlyphs = 0;
+         bool rightToLeft = false;
+         int fontEntryNum = 0;
+         int glyphScript = 0;
+         FontEntry curFontEntry;
+         Glyph * lastGlyph = null;
+         int lastAX = 0;
+
+         pack.bitmap.alphaBlend = true;
+
+         for(c = 0; c < len || (numGlyphs && (rightToLeft ? (glyphIndex >= 0) : (glyphIndex < numGlyphs)));)
+         {
+            uint glyphNo = 0;
+            uint packNo;
+            if(numGlyphs && (rightToLeft ? (glyphIndex >= 0) : (glyphIndex < numGlyphs)))
+            {
+               glyphNo = glyphs[glyphIndex] | 0x80000000 | (glyphScript << 24);
+               rightToLeft ? glyphIndex-- : glyphIndex++;
+            }
+            else
+            {
+               HB_Script curScript = HB_Script_Common;
+               const byte * scriptStart = text + c;
+               //unichar nonASCIIch = 0;
+               unichar ch;
+               unichar ahead = 0;
+               unichar testChar = 0;
+               const String testLang = null;
+
+               while(true)
+               {
+                  HB_Script script = HB_Script_Common;
+                  ch = UTF8GetChar((const char *)text + c, &nb);
+                  //if(ch > 127) nonASCIIch = ch;
+                  if(!nb) break;
+                  if(ch == 32 && curScript)
+                  {
+                     if(ahead)
+                        script = curScript;
+                     else
+                     {
+                        int a;
+                        for(a = c + 1; a < c + len; a++)
+                        {
+                           if(text[a] != 32)
+                              break;
+                        }
+                        if(a < c + len)
+                        {
+                           int nb;
+                           unichar ahead = UTF8GetChar((const char *)text + a, &nb);
+                           if((ahead >= 0x590 && ahead <= 0x7C0) || (ahead >= 0xFB1D && ahead <= 0xFB4F) || (ahead >= 0xFB50 && ahead <= 0xFDFF))
+                              script = curScript;
+                        }
+                        else
+                           script = curScript;
+                     }
+                  }
+                  else if(ch < 0x370)
+                     script = HB_Script_Common;
+                  else if(ch <= 0x11FF)
+                  {
+                     switch(ch & 0xFF00)
+                     {
+                        case 0x300: script = HB_Script_Greek; break;
+                        case 0x400: script = HB_Script_Cyrillic; break;
+                        case 0x500: script = (ch < 0x530) ? HB_Script_Cyrillic : ((ch < 0x590) ? HB_Script_Armenian : HB_Script_Hebrew); break;
+                        case 0x600: script = HB_Script_Arabic; break;
+                        case 0x700: script = (ch < 0x750) ? HB_Script_Syriac : ((ch < 0x780) ? HB_Script_Arabic : ((ch < 0x7C0) ? HB_Script_Thaana : HB_Script_Common)); break;
+                        case 0x800: script = HB_Script_Common; break;   // NO CHARACTERS ASSIGNED BETWEEN 0x7C0 and 0x8FF?
+                        case 0x900: script = (ch < 0x980) ? HB_Script_Devanagari : HB_Script_Bengali; break;
+                        case 0xA00: script = (ch < 0xA80) ? HB_Script_Gurmukhi : HB_Script_Gujarati; break;
+                        case 0xB00: script = (ch < 0xB80) ? HB_Script_Oriya : HB_Script_Tamil; break;
+                        case 0xC00: script = (ch < 0xC80) ? HB_Script_Telugu : HB_Script_Kannada; break;
+                        case 0xD00: script = (ch < 0xD80) ? HB_Script_Malayalam : HB_Script_Sinhala; break;
+                        case 0xE00: script = (ch < 0xE80) ? HB_Script_Thai : HB_Script_Lao; break;
+                        case 0xF00: script = HB_Script_Tibetan; break;
+                        case 0x1000: script = (ch < 0x10A0) ? HB_Script_Myanmar : HB_Script_Georgian; break;
+                        case 0x1100: script = HB_Script_Hangul; break;
+                     }
+                  }
+                  else if(ch >= 0x1F00 && ch <= 0x1FFF) script = HB_Script_Greek;
+                  else if((ch >= 0x2D00 && ch <= 0x2D2F) || (ch >= 0x3130 && ch <= 0x318F) || (ch >= 0xAC00 && ch <= 0xD7AF) || (ch >= 0xFFA0 && ch <= 0xFFDC))
+                     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 >= 0x3040 && ch <= 0x309F) script = 60;
+                  else if(ch >= 0x3400 && ch <= 0x9FBF) script = 61;
+                  //else if(ch >= 0x4E00 && ch <= 0x9FBF) script = 61;
+                  else if(ch >= 0xFB13 && ch <= 0xFB17) script = HB_Script_Armenian;
+                  else if(ch >= 0xFB1D && ch <= 0xFB4F) script = HB_Script_Hebrew;
+                  else if(ch >= 0xFB50 && ch <= 0xFDFF) script = HB_Script_Arabic;
+                  if(curScript)
+                  {
+                     if(!script || (script != curScript))
+                        break;
+                     c += nb;
+                     if(c >= len)
+                        break;
+                  }
+                  else
+                  {
+                     if(!script || script > HB_ScriptCount) { c += nb; if(script > HB_ScriptCount) curScript = script; break; }
+                     if(!script) { c += nb; break; }
+                     curScript = script;
+                  }
+               }
+               if(!nb) break;
+               fontEntryNum = 0;
+
+               if(curScript == HB_Script_Common || curScript > HB_ScriptCount)
+               {
+                  rightToLeft = false;
+                  glyphNo = ch;
+                  theCurrentScript = 0;
+               }
+               else
+               {
+                  int len = c - (int)(scriptStart - text);
+                  int max = len * 2 + 1;
+                  if(max > utf16BufferSize)
+                  {
+                     utf16 = renew utf16 uint16[max];
+                     utf16BufferSize = max;
+                  }
+                  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";
+                     //printf("Devanagari ");
+                     break;
+                  case HB_Script_Hebrew:        testChar = 0x05EA /*'ת'*/; /*testLang = "he"; */
+                     //printf("Hebrew ");
+                     break;
+                  default:
+                     testChar = (ch == '\t') ? ' ' : ch;
+                  /*
+                  case 60: testChar = 'あ'; break;
+                  case 61: testChar = 0x3400; break; //'愛'; break;
+                  */
+               }
+
+               if(testChar)
+               {
+                  // printf("Testing for char %x\n", testChar);
+                  for(fontEntryNum = 0; fontEntryNum<MAX_FONT_LINK_ENTRIES; fontEntryNum++)
+                  {
+                     if(fontEntries[fontEntryNum] && FT_Get_Char_Index(fontEntries[fontEntryNum].face, testChar))
+                        break;
+                     /*if(fontEntries[fontEntryNum])
+                        printf("Not found in %s\n", (char *)fontEntries[fontEntryNum].key);*/
+                  }
+               }
+
+               if(fontEntryNum == MAX_FONT_LINK_ENTRIES)
+               {
+                  FaceInfo info;
+                  // Do we still have room to add an entry?
+                  for(fontEntryNum = 0; fontEntryNum<MAX_FONT_LINK_ENTRIES; fontEntryNum++)
+                     if(!fontEntries[fontEntryNum])
+                        break;
+                  if(fontEntryNum == MAX_FONT_LINK_ENTRIES)
+                     continue;
+
+                  if((info = ResolveCharFont(faceName, size, flags, testLang, testChar)))
+                  {
+                     FontEntry fontEntry = FontEntry::Load(info);
+                     if(fontEntry)
+                     {
+                        FaceSetCharSize(fontEntry.face, size);
+                        fontEntries[fontEntryNum] = fontEntry;
+                        fontEntry.used++;
+                     }
+                     delete info;
+                  }
+
+                  if(!fontEntries[fontEntryNum])
+                     continue;
+               }
+               if(curScript > HB_ScriptCount) curScript = HB_Script_Common;
+               if(curScript != HB_Script_Common && curScript < HB_ScriptCount)
+               {
+                  fontEntries[fontEntryNum].font = this;
+                  glyphs = shaping(fontEntries[fontEntryNum], utf16, wc, curScript, &numGlyphs, &rightToLeft);
+                  if(!numGlyphs)
+                     continue;
+
+                  glyphIndex = rightToLeft ? (numGlyphs - 1) : 0;
+                  glyphNo = glyphs[glyphIndex] | 0x80000000 | (glyphScript << 24);
+                  rightToLeft ? glyphIndex-- : glyphIndex++;
+               }
+            }
+
+            curFontEntry = fontEntries[fontEntryNum];
+
+            packNo = glyphNo & 0xFFFFFF80;
+
+            if(packNo != lastPack)
+            {
+               if(glyphNo < 128)
+                  pack = asciiPack;
+               else
+               {
+                  pack = (GlyphPack)glyphPacks.Find((uintptr)packNo);
+                  if(!pack)
+                  {
+                     pack = GlyphPack { key = (uintptr)packNo };
+                     glyphPacks.Add(pack);
+                     pack.Render(this, fontEntryNum, displaySystem);
+                  }
+               }
+               pack.bitmap.alphaBlend = true;
+               lastPack = packNo;
+            }
+            if(pack)
+            {
+               int index = rightToLeft ? (glyphIndex + 1) : (glyphIndex-1);
+               Glyph * glyph = &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;
+
+               ax += offset;
+
+               if(previousGlyph && curFontEntry && (curFontEntry.face == previousFace || !previousFace)) // TO IMPROVE: Assuming same face for now for multiple calls...
+               {
+                  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;
+               }
+               else if(curFontEntry)
+                  FaceSetCharSize(curFontEntry.face, size);
+
+               previousGlyph = glyph->glyphNo;
+               previousFace = curFontEntry ? curFontEntry.face : null;
+
+               if(callback)
+                  callback(surface, display, ((*x) >> 6), y + (oy >> 6), glyph, pack.bitmap);
+               *x += ax;
+
+               lastGlyph = glyph;
+               lastAX = ax;
+            }
+            if(numGlyphs && (rightToLeft ? (glyphIndex < 0) : (glyphIndex == numGlyphs)))
+               numGlyphs = 0;
+         }
+         if(lastGlyph)
+         {
+            int w = (lastGlyph->w + lastGlyph->left) * (1 << 6);
+            // Fix for advance != width + left (e.g. italic fonts)
+            if(w > lastAX)
+               *advance = w - lastAX;
+         }
+         if(rPrevGlyph) *rPrevGlyph = previousGlyph;
+      }
+      if(surface)
+      {
+         LFBSurface lfbSurface = surface.driverData;
+         lfbSurface.xOffset = 0;
+      }
+#endif
+   }
+};
index b9cebd1..b31dfc0 100644 (file)
@@ -978,7 +978,7 @@ private:
 
    bool modified;
 
-   void (* FontExtent)(Display display, Font font, const char * text, int len, int * width, int * height);
+   void (* FontExtent)(Display display, Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * overHang);
 
    Color backColor;
    bool rightButtonDown;
@@ -1211,7 +1211,7 @@ private:
          colorScheme.keywordColors = [ blue, blue ];
       }
 
-      FontExtent = Display::FontExtent;
+      FontExtent = Display::FontExtent2;
       font = fontObject;
       lines.offset = (uint)(uintptr)&((EditLine)0).prev;
 
@@ -1267,7 +1267,7 @@ private:
       lines.Free(EditLine::Free);
    }
 
-   void FlushBuffer(Surface surface, EditLine line, int wc, int * renderStart, int * x, int y, int numSpaces, bool drawSpaces, Box box)
+   void FlushBuffer(Surface surface, EditLine line, int wc, int * renderStart, int * x, int y, int * previousGlyph, int * oh, int numSpaces, bool drawSpaces, Box box)
    {
       int count = wc - *renderStart;
       if(count)
@@ -1278,18 +1278,24 @@ private:
 
             if(!numSpaces)
             {
+               int coh;
                //FontExtent(display, font, line.buffer + *renderStart, count, &w, null);
                surface.TextFont(font);
-               surface.TextExtent(line.buffer + *renderStart, count, &w, null);
-               if(*x + w + XOFFSET > 0)
-                  surface.WriteText(XOFFSET + *x,y, line.buffer + *renderStart, count);
+               surface.TextExtent2(line.buffer + *renderStart, count, &w, null, *previousGlyph, null, &coh);
+
+               if(*x + w + coh + XOFFSET > 0)
+               {
+                  surface.WriteText2(XOFFSET + *x,y, line.buffer + *renderStart, count, *previousGlyph, previousGlyph);
+                  *oh = coh;
+                  //surface.WriteText(XOFFSET + *x,y, line.buffer + *renderStart, count);
+               }
                *x += w;
             }
             else
             {
                w = numSpaces; // * space.w;
-               if(*x + w + XOFFSET > 0 && (drawSpaces || surface.GetTextOpacity()))
-                  surface.Area(XOFFSET + *x - 1, y, XOFFSET + *x + w, y + space.h-1);
+               if(*x + w + XOFFSET > 0 && (drawSpaces))
+                  surface.Area(XOFFSET + *x /*- 1*/ + *oh, y, XOFFSET + *x + w, y + space.h-1);
                   // WHATS UP WITH THIS...  surface.Area(XOFFSET + *x, y, XOFFSET + *x + w, y + space.h-1);
                *x += w;
             }
@@ -1478,6 +1484,25 @@ private:
       }
    }*/
 
+   static inline int countTabsExtraSpaces(char * buffer, int tabSize, int start, int end)
+   {
+      // TODO: Handle tabs position properly with UTF-8 (and everywhere else)
+      int p = 0, i, extra = 0;
+      for(i = 0; i < end; i++)
+      {
+         if(buffer[i] == '\t')
+         {
+            int t = tabSize - (p % tabSize);
+            p += t;
+            if(i >= start)
+               extra += t-1;
+         }
+         else
+            p++;
+      }
+      return extra;
+   }
+
    void OnRedraw(Surface surface)
    {
       EditLine line;
@@ -1512,6 +1537,13 @@ private:
       bool wasInMultiLine = style.wasInMultiLine;
       // ****** ************* ******
 
+      // For drawing selection background
+      EditLine selStartLine = this.y < this.selY ? this.line : this.selLine;
+      EditLine selEndLine   = this.y < this.selY ? this.selLine : this.line;
+      int selStartX = this.y < this.selY || (this.y == this.selY && this.x < this.selX) ? this.x : this.selX;
+      int selEndX   = this.y > this.selY || (this.y == this.selY && this.x > this.selX) ? this.x : this.selX;
+      ///////////////////////////////////
+
       if(!isEnabled)
          defaultTextColor = Color { 85, 85, 85 };
       textColor = defaultTextColor;
@@ -1562,7 +1594,7 @@ private:
    */
       surface.SetForeground(foreground);
       surface.SetBackground(background);
-      surface.TextOpacity(opacity);
+      surface.TextOpacity(false);
 
       surface.GetBox(box);
 
@@ -1574,7 +1606,7 @@ private:
          int start = 0;
          Color newTextColor = textColor = defaultTextColor;
          bool lineComplete = false;
-
+         int overHang = 0;
 
          // ****** SYNTAX HIGHLIGHTING ******
          bool lastWasStar = false;
@@ -1601,6 +1633,61 @@ private:
          }
    */
 
+         // Draw Selection Background all at once here
+         if(selected || line == this.line || line == this.selLine)
+         {
+            int sx = XOFFSET + x, sy = y;
+            int tw, th;
+            int oh = 0;
+            char * buffer = line.buffer;
+            if(line != this.line && line != this.selLine)
+            {
+               if(style.freeCaret)
+               {
+                  tw = clientSize.w - sx;
+                  th = space.h;
+               }
+               else
+                  surface.TextExtent2(buffer, line.count, &tw, &th, 0, null, &oh);
+            }
+            else if(line == selStartLine)
+            {
+               int prevGlyph;
+               int start = Min(line.count, selStartX);
+               int end   = Min(line.count, selEndX);
+               surface.TextExtent2(buffer, start, &tw, &th, 0, &prevGlyph, null);
+               sx += tw;
+               sx += countTabsExtraSpaces(buffer, tabSize, 0, start) * space.w;
+               if(selStartX > start) sx += space.w * (selStartX - start);
+               if(style.freeCaret && line != selEndLine)
+               {
+                  tw = clientSize.w - sx;
+                  th = space.h;
+               }
+               else if(line != selEndLine)
+               {
+                  surface.TextExtent2(buffer + start, line.count - start, &tw, &th, prevGlyph, null, &oh);
+                  tw += countTabsExtraSpaces(buffer, tabSize, start, line.count) * space.w;
+               }
+               else
+               {
+                  surface.TextExtent2(buffer + start, end - start, &tw, &th, prevGlyph, null, &oh);
+                  tw += countTabsExtraSpaces(buffer, tabSize, start, end) * space.w;
+                  end = Max(end, selStartX);
+                  if(selEndX > end) { tw += space.w * (selEndX - end); th = space.h; }
+               }
+            }
+            else if(line == selEndLine)
+            {
+               int end = Min(line.count, selEndX);
+               surface.TextExtent2(buffer, end, &tw, &th, 0, null, &oh);
+               tw += countTabsExtraSpaces(buffer, tabSize, 0, end) * space.w;
+               if(selEndX - end) { tw += space.w * (selEndX - end); th = space.h; }
+            }
+            tw += oh;
+            surface.Area(sx, sy, sx + tw-1, sy + th-1);
+         }
+
          if(line == this.selLine && line == this.line)
          {
             end = Max(line.count, this.x);
@@ -1937,7 +2024,8 @@ private:
                      //if(!numSpaces)
                      {
                         int tw;
-                        FontExtent(display, font, line.buffer + start, bufferLen + wordLen, &tw, null);
+                        int oh;
+                        FontExtent(display, font, line.buffer + start, bufferLen + wordLen, &tw, null, 0, null, &oh);
                         w = tw;
                      }
                      /*else
@@ -1966,6 +2054,7 @@ private:
                bool flagTrailingSpace = false;
                int numSpaces = 0;
                int wc;
+               int previousGlyph = 0;
 
                // Render checking if we need to split because of selection or to find where to draw insert caret
                for(wc = start; wc < start + bufferLen; wc++)
@@ -1982,7 +2071,8 @@ private:
                   {
                      flagTrailingSpace = numSpaces && trailingSpace && style.syntax && start + bufferLen == line.count && line != this.line;
                      if(flagTrailingSpace) surface.SetBackground(red);
-                     FlushBuffer(surface, line, wc, &renderStart, &x, y, numSpaces, flagTrailingSpace, box);
+                     FlushBuffer(surface, line, wc, &renderStart, &x, y, &previousGlyph, &overHang, numSpaces, flagTrailingSpace, box);
+                     if(flagTrailingSpace) surface.SetBackground(background);
                      if(overWrite == 1)
                      {
                         overWriteX = x;
@@ -1991,8 +2081,6 @@ private:
                      }
                      numSpaces = 0;
 
-                     surface.TextOpacity(opacity);
-                     surface.SetBackground(background);
                      surface.SetForeground(foreground);
 
                      flush = false;
@@ -2012,7 +2100,8 @@ private:
                }
                flagTrailingSpace = numSpaces && trailingSpace && style.syntax && start + bufferLen == line.count && line != this.line;
                if(flagTrailingSpace) surface.SetBackground(red);
-               FlushBuffer(surface, line, wc, &renderStart, &x, y, numSpaces, flagTrailingSpace, box);
+               FlushBuffer(surface, line, wc, &renderStart, &x, y, &previousGlyph, &overHang, numSpaces, flagTrailingSpace, box);
+               if(flagTrailingSpace) surface.SetBackground(background);
                start += bufferLen;
             }
          }
@@ -2027,26 +2116,10 @@ private:
                overWriteCh = ' ';
                overWrite = 2;
             }
-            surface.TextOpacity(opacity);
             surface.SetBackground(background);
             surface.SetForeground(foreground);
          }
 
-         if(style.freeCaret && selected)
-         {
-            surface.SetBackground(selectionBackground);
-            surface.Area(x + XOFFSET - 1,y,clientSize.w-1,y+this.space.h-1);
-            // TEST: surface.Area(x + XOFFSET,y,clientSize.w-1,y+this.space.h-1);
-         }
-
-
-         /*
-         if(style.freeCaret && selected)
-         {
-            surface.SetBackground(selectionBackground);
-            surface.Area(x + XOFFSET - 1,y,clientSize.w-1,y+this.space.h-1);
-         }
-         */
          if(line.count && line.text[line.count - 1] == '\\')
          {
             continuedSingleLineComment = inSingleLineComment;
@@ -2137,7 +2210,10 @@ private:
                len = 1;
             }
             else
-               FontExtent(display, font, line.buffer + start, len, &w, null);
+            {
+               int oh;
+               FontExtent(display, font, line.buffer + start, len, &w, null, 0, null, &oh);
+            }
          }
          else
          {
@@ -2526,8 +2602,9 @@ private:
             }
             else
             {
+               int oh;
                numBytes = UTF8_NUM_BYTES(*string);
-               FontExtent(display, this.font, string, numBytes, &w, null);
+               FontExtent(display, this.font, string, numBytes, &w, null, 0, null, &oh);
             }
             x += w;
 
@@ -2900,7 +2977,10 @@ private:
                         len = 1;
                      }
                      else
-                        FontExtent(display, this.font, line.buffer + start, len, &w, null);
+                     {
+                        int oh;
+                        FontExtent(display, this.font, line.buffer + start, len, &w, null, 0, null, &oh);
+                     }
                   }
                   else
                   {
@@ -3005,7 +3085,10 @@ private:
                len = 1;
             }
             else
-               FontExtent(display, font, line.buffer + start, len, &w, null);
+            {
+               int oh;
+               FontExtent(display, font, line.buffer + start, len, &w, null, 0, null, &oh);
+            }
          }
          else
          {
@@ -3030,7 +3113,10 @@ private:
                else
                   a--;
                if(a > start)
-                  FontExtent(display, font, line.buffer + start, a - start, &w, null);
+               {
+                  int oh;
+                  FontExtent(display, font, line.buffer + start, a - start, &w, null, 0, null, &oh);
+               }
                else
                   w = 0;
                if(position > x + (half ? ((w + lastW) / 2) : lastW)) break;
@@ -3550,8 +3636,9 @@ private:
    {
       if(FontExtent)
       {
-         FontExtent(display, font, " ", 1, (int *)&space.w, (int *)&space.h);
-         FontExtent(display, font, "W", 1, (int *)&large.w, (int *)&large.h);
+         int oh;
+         FontExtent(display, font, " ", 1, (int *)&space.w, (int *)&space.h, 0, null, &oh);
+         FontExtent(display, font, "W", 1, (int *)&large.w, (int *)&large.h, 0, null, &oh);
 
          space.w = Max(space.w, 1);
          large.w = Max(large.w, 1);
@@ -3576,7 +3663,7 @@ private:
 
    bool OnLoadGraphics()
    {
-      FontExtent = Display::FontExtent;
+      FontExtent = Display::FontExtent2;
       font = fontObject;
       ComputeFont();
       // UpdateCaretPosition(true);