mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
263 lines
6.8 KiB
C++
263 lines
6.8 KiB
C++
#include "CtrlCore.h"
|
|
|
|
#ifdef GUI_X11
|
|
|
|
namespace Upp {
|
|
|
|
#define LTIMING(x)
|
|
#define LLOG(x) // DLOG(x)
|
|
|
|
int gtk_antialias = -1;
|
|
int gtk_hinting = -1;
|
|
String gtk_hintstyle;
|
|
String gtk_rgba;
|
|
|
|
XftFont *CreateXftFont(Font font, int angle)
|
|
{
|
|
LTIMING("CreateXftFont");
|
|
XftFont *xftfont;
|
|
double sina, cosa;
|
|
int hg = abs(font.GetHeight());
|
|
if(hg == 0) hg = max(GetStdFontCy(), 10);
|
|
String face = font.GetFaceName();
|
|
FcPattern *p = FcPatternCreate();
|
|
FcPatternAddString(p, FC_FAMILY, (FcChar8*)~face);
|
|
FcPatternAddInteger(p, FC_SLANT, font.IsItalic() ? FC_SLANT_ITALIC : FC_SLANT_ROMAN);
|
|
FcPatternAddInteger(p, FC_PIXEL_SIZE, hg);
|
|
FcPatternAddInteger(p, FC_WEIGHT, font.IsBold() ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL);
|
|
FcPatternAddBool(p, FC_MINSPACE, 1);
|
|
if(angle) {
|
|
FcMatrix mx;
|
|
Draw::SinCos(angle, sina, cosa);
|
|
mx.xx = cosa;
|
|
mx.xy = -sina;
|
|
mx.yx = sina;
|
|
mx.yy = cosa;
|
|
FcPatternAddMatrix(p, FC_MATRIX, &mx);
|
|
}
|
|
FcResult result;
|
|
FcPattern *m = XftFontMatch(Xdisplay, Xscreenno, p, &result);
|
|
if(font.IsNonAntiAliased() || gtk_antialias >= 0) {
|
|
FcPatternDel(m, FC_ANTIALIAS);
|
|
FcPatternAddBool(m, FC_ANTIALIAS,
|
|
font.IsNonAntiAliased() ? FcFalse : gtk_antialias ? FcTrue : FcFalse);
|
|
}
|
|
if(gtk_hinting >= 0) {
|
|
FcPatternDel(m, FC_HINTING);
|
|
FcPatternAddBool(m, FC_HINTING, gtk_hinting);
|
|
}
|
|
const char *hs[] = { "hintnone", "hintslight", "hintmedium", "hintfull" };
|
|
for(int i = 0; i < 4; i++)
|
|
if(gtk_hintstyle == hs[i]) {
|
|
FcPatternDel(m, FC_HINT_STYLE);
|
|
FcPatternAddInteger(m, FC_HINT_STYLE, i);
|
|
}
|
|
const char *rgba[] = { "_", "rgb", "bgr", "vrgb", "vbgr" };
|
|
for(int i = 0; i < __countof(rgba); i++)
|
|
if(gtk_rgba == rgba[i]) {
|
|
FcPatternDel(m, FC_RGBA);
|
|
FcPatternAddInteger(m, FC_RGBA, i);
|
|
}
|
|
xftfont = XftFontOpenPattern(Xdisplay, m);
|
|
FcPatternDestroy(p);
|
|
return xftfont;
|
|
}
|
|
|
|
#define FONTCACHE 37
|
|
|
|
struct XftEntry {
|
|
Font font;
|
|
int angle;
|
|
XftFont *xftfont;
|
|
};
|
|
|
|
XftFont *GetXftFont(XftEntry *cache, Font fnt, int angle)
|
|
{
|
|
XftEntry be;
|
|
be = cache[0];
|
|
for(int i = 0; i < FONTCACHE; i++) {
|
|
XftEntry e = cache[i];
|
|
if(i)
|
|
cache[i] = be;
|
|
if(e.font == fnt && e.angle == angle) {
|
|
if(i)
|
|
cache[0] = e;
|
|
return e.xftfont;
|
|
}
|
|
be = e;
|
|
}
|
|
if(be.xftfont) {
|
|
XftFontClose(Xdisplay, be.xftfont);
|
|
}
|
|
be.font = fnt;
|
|
be.angle = angle;
|
|
be.xftfont = CreateXftFont(fnt, angle);
|
|
cache[0] = be;
|
|
return be.xftfont;
|
|
}
|
|
|
|
XftFont *GetXftMetricFont(Font fnt, int angle)
|
|
{ // Using different global cache for metrics to avoid MT locking issues
|
|
static XftEntry cache[FONTCACHE];
|
|
ONCELOCK {
|
|
for(int i = 0; i < FONTCACHE; i++)
|
|
cache[i].font.Height(-30000);
|
|
}
|
|
Std(fnt);
|
|
return GetXftFont(cache, fnt, angle);
|
|
}
|
|
|
|
CommonFontInfo XftGetFontInfoSys(Font font)
|
|
{
|
|
CommonFontInfo fi;
|
|
String path;
|
|
XftFont *xftfont = GetXftMetricFont(font, 0);
|
|
if(xftfont) {
|
|
fi.ascent = (int16)xftfont->ascent;
|
|
fi.descent = (int16)xftfont->descent;
|
|
fi.external = 0;
|
|
fi.internal = 0;
|
|
fi.overhang = 0;
|
|
fi.maxwidth = (int16)xftfont->max_advance_width;
|
|
fi.avewidth = fi.maxwidth;
|
|
fi.default_char = '?';
|
|
fi.fixedpitch = font.GetFaceInfo() & Font::FIXEDPITCH;
|
|
|
|
char *fn = NULL;
|
|
XftPatternGetString(xftfont->pattern, XFT_FILE, 0, &fn);
|
|
if(fn && strlen(fn) < 250)
|
|
strcpy(fi.path, fn);
|
|
}
|
|
return fi;
|
|
}
|
|
|
|
GlyphInfo XftGetGlyphInfoSys(Font font, int chr)
|
|
{
|
|
wchar h = chr;
|
|
XGlyphInfo info;
|
|
XftTextExtents32(Xdisplay, GetXftMetricFont(font, 0), &h, 1, &info);
|
|
GlyphInfo gi;
|
|
gi.width = info.xOff;
|
|
gi.lspc = -info.x;
|
|
gi.rspc = info.xOff - info.width + info.x;
|
|
return gi;
|
|
}
|
|
|
|
INITBLOCK {
|
|
// it is probably not quite required as Xft is based on FC, but to be sure to have
|
|
// consistent metrics hook Xft metrics into Draw/FontFc.cpp
|
|
|
|
extern CommonFontInfo (*GetFontInfoSysXft)(Font font);
|
|
extern GlyphInfo (*GetGlyphInfoSysXft)(Font font, int chr);
|
|
|
|
GetFontInfoSysXft = XftGetFontInfoSys;
|
|
GetGlyphInfoSysXft = XftGetGlyphInfoSys;
|
|
}
|
|
|
|
void SystemDraw::DrawTextOp(int x, int y, int angle, const wchar *text, Font font,
|
|
Color ink, int n, const int *dx) {
|
|
GuiLock __;
|
|
LLOG("DrawText " << ToUtf8(WString(text, n)) << " color:" << ink << " font:" << font);
|
|
//TODO - X11 seems to crash when displaying too long strings (?)
|
|
int ox = x + actual_offset.x;
|
|
int oy = y + actual_offset.y;
|
|
SetForeground(ink);
|
|
XftColor c;
|
|
c.color.red = ink.GetR() << 8;
|
|
c.color.green = ink.GetG() << 8;
|
|
c.color.blue = ink.GetB() << 8;
|
|
c.color.alpha = 0xffff;
|
|
c.pixel = GetXPixel(ink.GetR(), ink.GetG(), ink.GetB());
|
|
|
|
static XftEntry cache[FONTCACHE];
|
|
ONCELOCK {
|
|
for(int i = 0; i < FONTCACHE; i++)
|
|
cache[i].font.Height(-30000);
|
|
}
|
|
font.RealizeStd();
|
|
XftFont *xftfont = GetXftFont(cache, font, angle);
|
|
|
|
Size offset = Point(0, 0);
|
|
double sina = 0, cosa = 1;
|
|
int ascent = font.Info().GetAscent();
|
|
if(angle) {
|
|
SinCos(angle, sina, cosa);
|
|
offset.cx = fround(ascent * sina);
|
|
offset.cy = fround(ascent * cosa);
|
|
}
|
|
int hg = abs(font.GetHeight());
|
|
if(hg == 0) hg = 10;
|
|
int underline_thickness = max(hg / 20, 1);
|
|
int underline_position = max(hg / 15, int(font.Info().GetDescent() > 0));
|
|
if(angle) {
|
|
int xpos = 0;
|
|
for(int i = 0; i < n; i++) {
|
|
wchar h = text[i];
|
|
XftDrawString16(xftdraw, &c, xftfont,
|
|
int(ox + xpos * cosa + offset.cx),
|
|
int(oy - xpos * sina + offset.cy),
|
|
(FcChar16 *)&h, 1);
|
|
xpos += dx ? dx[i] : font[text[i]];
|
|
}
|
|
if(font.IsUnderline() || font.IsStrikeout()) {
|
|
x += offset.cx;
|
|
y += offset.cy;
|
|
if(font.IsUnderline())
|
|
DrawLine(
|
|
int(x + underline_position * sina),
|
|
int(y + underline_position * cosa),
|
|
int(x + xpos * cosa + underline_position * sina),
|
|
int(y - xpos * sina + underline_position * cosa),
|
|
underline_thickness,
|
|
ink
|
|
);
|
|
if(font.IsStrikeout()) {
|
|
int p = 2 * ascent / 3;
|
|
DrawLine(
|
|
int(x + p * sina),
|
|
int(y + p * cosa),
|
|
int(x + xpos * cosa + p * sina),
|
|
int(y - xpos * sina + p * cosa),
|
|
underline_thickness,
|
|
ink
|
|
);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// if(dx) {
|
|
int xpos = ox;
|
|
Buffer<XftCharSpec> ch(n);
|
|
for(int i = 0; i < n; i++) {
|
|
ch[i].ucs4 = text[i];
|
|
ch[i].x = xpos;
|
|
ch[i].y = oy + ascent;
|
|
xpos += dx ? dx[i] : font[text[i]];
|
|
}
|
|
XftDrawCharSpec(xftdraw, &c, xftfont, ch, n);
|
|
// }
|
|
// else
|
|
// XftDrawString16(xftdraw, &c, xftfont, ox, oy + ascent,
|
|
// (FcChar16 *)text, n);
|
|
LLOG("XftColor: r=" << c.color.red << ", g=" << c.color.green << ", b=" << c.color.blue
|
|
<< ", alpha=" << c.color.alpha << ", pixel=" << FormatIntHex(c.pixel));
|
|
if(font.IsUnderline() || font.IsStrikeout()) {
|
|
int cx;
|
|
if(dx && n > 0) {
|
|
cx = 0;
|
|
Sum(cx, dx, dx + n - 1);
|
|
cx += font[text[n - 1]];
|
|
}
|
|
else
|
|
cx = GetTextSize(text, font, n).cx;
|
|
if(font.IsUnderline())
|
|
DrawRect(x, y + ascent + underline_position, cx, underline_thickness, ink);
|
|
if(font.IsStrikeout())
|
|
DrawRect(x, y + 2 * ascent / 3, cx, underline_thickness, ink);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|