#include "SystemDraw.h" NAMESPACE_UPP #ifdef PLATFORM_X11 #define LTIMING(x) #define LLOG(x) int gtk_antialias = -1; int gtk_hinting; String gtk_hintstyle; String gtk_rgba; XftFont *CreateXftFont(Font font, int angle) { LTIMING("CreateXftFont"); XftFont *xftfont; double sina, cosa; Std(font); 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() ? 110 : 0); FcPatternAddInteger(p, FC_PIXEL_SIZE, hg); FcPatternAddInteger(p, FC_WEIGHT, font.IsBold() ? 200 : 100); 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(Font fnt, int angle) { static XftEntry cache[FONTCACHE]; ONCELOCK { for(int i = 0; i < FONTCACHE; i++) cache[i].font.Height(-30000); } 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; } CommonFontInfo XftGetFontInfoSys(Font font) { CommonFontInfo fi; String path; XftFont *xftfont = GetXftFont(font, 0); if(xftfont) { fi.ascent = (int16)xftfont->ascent; fi.descent = (int16)xftfont->descent; fi.height = fi.ascent + fi.descent; fi.lineheight = (int16)xftfont->height; 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; XftTextExtents16(Xdisplay, GetXftFont(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 { // extern FT_Face (*FTFaceXft)(Font fnt, String *rpath); extern CommonFontInfo (*GetFontInfoSysXft)(Font font); extern GlyphInfo (*GetGlyphInfoSysXft)(Font font, int chr); // FTFaceXft = XftFTFace; 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 __; LTIMING("DrawText"); 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()); XftFont *xftfont = GetXftFont(font, angle); Size offset = Point(0, 0); double sina, cosa; 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] : lastFont[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 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[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 += lastFont[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 END_UPP_NAMESPACE