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 \
$(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
$(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)
$(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
"DisplaySystem.ec",
"FontResource.ec",
"Resource.ec",
- "Surface.ec"
+ "Surface.ec",
+ "fontManagement.ec",
+ "fontRendering.ec"
],
"Configurations" : [
{
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)
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 &&
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)
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;
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, ...)
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);
}
}
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);
}
}
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;
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);
}
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;
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__);
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;
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;
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);
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)
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;
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] =
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);
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)
#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;
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);
#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)
{
if(width) *width = 0;
if(height) *height = 0;
+ if(adv) *adv = 0;
}
}
/*
}
*/
#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*/
{
// UNICODE FIX: proper space computation
if(width) *width = size.cx + (wordCount - realLen) * space.cx;
+ if(adv) *adv = 0;
if(height)
{
if(realLen)
}
*/
#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
}
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;
{
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,
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;
}
}
}
- 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)
{
}
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
{
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);
}
}
- 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;
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
}
}
- 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;
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;
{
if(width) *width = 0;
if(height) *height = 0;
+ if(adv) *adv = 0;
}
}
}
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)
/*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:
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
{
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 = ¶m;
-
- 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 = ¶m;
-
- 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)
{
}
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;
}
#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)
}
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;
}
}
- 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)
((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;
}
}
- 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)
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;
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);
}
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;
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;
}
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;
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;
// UNICODE FIX: proper space computation
if(width) *width = size.cx + (wordCount - realLen) * space.cx;
+ if(adv) *adv = 0;
if(height)
{
if(realLen)
}
}
- 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)
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;
}
((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;
}
}
- 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)
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;
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;
GetTextExtentPoint32(hdc, u16text, realLen, &size);
delete u16text;
+ if(adv) *adv = 0;
if(width)
{
// UNICODE FIX: proper space computation
}
}
- 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;
}
}
#define Time X11Time
#define KeyCode X11KeyCode
#define Picture X11Picture
+#define Glyph X11Glyph
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#undef Time
#undef KeyCode
#undef Picture
+#undef Glyph
#undef uint
#undef new
#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
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;
/*
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)
--- /dev/null
+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;
+}
--- /dev/null
+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 = ¶m;
+
+ 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
+ }
+};
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;
colorScheme.keywordColors = [ blue, blue ];
}
- FontExtent = Display::FontExtent;
+ FontExtent = Display::FontExtent2;
font = fontObject;
lines.offset = (uint)(uintptr)&((EditLine)0).prev;
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)
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;
}
}
}*/
+ 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;
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;
*/
surface.SetForeground(foreground);
surface.SetBackground(background);
- surface.TextOpacity(opacity);
+ surface.TextOpacity(false);
surface.GetBox(box);
int start = 0;
Color newTextColor = textColor = defaultTextColor;
bool lineComplete = false;
-
+ int overHang = 0;
// ****** SYNTAX HIGHLIGHTING ******
bool lastWasStar = false;
}
*/
+ // 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);
//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
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++)
{
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;
}
numSpaces = 0;
- surface.TextOpacity(opacity);
- surface.SetBackground(background);
surface.SetForeground(foreground);
flush = false;
}
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;
}
}
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;
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
{
}
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;
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
{
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
{
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;
{
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);
bool OnLoadGraphics()
{
- FontExtent = Display::FontExtent;
+ FontExtent = Display::FontExtent2;
font = fontObject;
ComputeFont();
// UpdateCaretPosition(true);