X11Font.client.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "gfx/gFont.h"
  23. #include "gfx/bitmap/gBitmap.h"
  24. #include "math/mRect.h"
  25. #include "console/console.h"
  26. #include "core/strings/unicode.h"
  27. #include "core/stringTable.h"
  28. #include "platformPOSIX/platformPOSIX.h"
  29. #include "platformX11/X11Font.h"
  30. // Needed by createFont
  31. #include <X11/Xlib.h>
  32. #include <X11/Xutil.h>
  33. #include <X11/Xos.h>
  34. #include <X11/Xatom.h>
  35. #include <X11/Xft/Xft.h>
  36. //#include <X11/extensions/Xrender.h> // For XRenderColor
  37. // Needed for getenv in createFont
  38. #include <stdlib.h>
  39. XftFont *loadFont(const char *name, S32 size, Display *display)
  40. {
  41. XftFont *fontInfo = NULL;
  42. const char* fontname = name;
  43. if (dStrlen(fontname)==0)
  44. fontname = "arial";
  45. else if (stristr(name, "arial") != NULL)
  46. fontname = "arial";
  47. else if (stristr(name, "lucida console") != NULL)
  48. fontname = "lucida console";
  49. const char* weight = "medium";
  50. const char* slant = "roman"; // no slant
  51. if (stristr(name, "bold") != NULL)
  52. weight = "bold";
  53. if (stristr(name, "italic") != NULL)
  54. slant = "italic";
  55. int mSize = size - 2 - (int)((float)size * 0.1);
  56. char xfontName[512];
  57. // We specify a lower DPI to get 'correct' looking fonts, if we go with the
  58. // native DPI the fonts are to big and don't fit the widgets.
  59. dSprintf(xfontName, 512, "%s-%d:%s:slant=%s:dpi=76", fontname, mSize, weight, slant);
  60. // Lets see if Xft can get a font for us.
  61. char xftname[1024];
  62. fontInfo = XftFontOpenName(display, DefaultScreen(display), xfontName);
  63. // Cant find a suitabke font, default to a known font (6x10)
  64. if ( !fontInfo )
  65. {
  66. dSprintf(xfontName, 512, "6x10-%d:%s:slant=%s:dpi=76", mSize, weight, slant);
  67. fontInfo = XftFontOpenName(display, DefaultScreen(display), xfontName);
  68. }
  69. XftNameUnparse(fontInfo->pattern, xftname, 1024);
  70. #ifdef DEBUG
  71. Con::printf("Font '%s %d' mapped to '%s'\n", name, size, xftname);
  72. #endif
  73. return fontInfo;
  74. }
  75. //GOldFont* createFont(const char *name, dsize_t size, U32 charset)
  76. //{
  77. // Display *display = XOpenDisplay(getenv("DISPLAY"));
  78. // int screen;
  79. //
  80. // if (!display)
  81. // AssertFatal(false, "createFont: cannot connect to X server");
  82. // screen = DefaultScreen(display);
  83. //
  84. // XftFont *font = loadFont (name, size, display);
  85. // if (!font) // This should almost never trigger anymore.
  86. // AssertFatal(false, "createFont: cannot load font");
  87. //
  88. // // Create the pixmap to draw on.
  89. // Pixmap pixmap = XCreatePixmap(display,
  90. // DefaultRootWindow(display),
  91. // font->max_advance_width,
  92. // font->height,
  93. // DefaultDepth(display, screen));
  94. // // And the Xft wrapper around it.
  95. // XftDraw *draw = XftDrawCreate(display,
  96. // pixmap,
  97. // DefaultVisual(display, screen),
  98. // DefaultColormap(display, screen));
  99. // // Allocate some colors, we don't use XftColorAllocValue here as that
  100. // // Don't appear to function correctly (or I'm using it wrong) As we only do
  101. // // this twice per new un cached font it isn't that big of a penalty. (Each
  102. // // call to XftColorAllocName involves a round trip to the X Server)
  103. // XftColor black, white;
  104. // XftColorAllocName(display,
  105. // DefaultVisual(display, screen),
  106. // DefaultColormap(display, screen),
  107. // "black",
  108. // &black);
  109. // // White
  110. // XftColorAllocName(display,
  111. // DefaultVisual(display, screen),
  112. // DefaultColormap(display, screen),
  113. // "white",
  114. // &white);
  115. //
  116. // // The font.
  117. // GOldFont *retFont = new GOldFont;
  118. // static U8 scratchPad[65536];
  119. // int x, y;
  120. // // insert bitmaps into the font for each character
  121. // for(U16 i = 32; i < 256; i++)
  122. // {
  123. // XGlyphInfo extent;
  124. // FT_UInt glyph;
  125. // if (!XftCharExists(display, font, i))
  126. // {
  127. // retFont->insertBitmap(i, scratchPad, 0, 0, 0, 0, 0, font->max_advance_width);
  128. // continue;
  129. // }
  130. // // Get the glyph and its extents.
  131. // glyph = XftCharIndex(display, font, i);
  132. // XftGlyphExtents (display, font, &glyph, 1, &extent);
  133. // // Clear the bounding box and draw the glyph
  134. // XftDrawRect (draw, &black, 0, 0, font->max_advance_width, font->height);
  135. // XftDrawGlyphs (draw, &white, font, 0, font->ascent, &glyph, 1);
  136. // // Grab the rendered image ...
  137. // XImage *ximage = XGetImage(display, pixmap, 0, 0,
  138. // extent.xOff, font->height,
  139. // AllPlanes, XYPixmap);
  140. // if (ximage == NULL)
  141. // AssertFatal(false, "cannot get x image");
  142. // // And store each pixel in the scratchPad for insertion into the bitmap.
  143. // // We grab the full height of the pixmap.
  144. // for(y = 0; y < font->height; y++)
  145. // {
  146. // // and the width of the glyph and its padding.
  147. // for(x = 0; x < extent.xOff; x++)
  148. // scratchPad[y * extent.xOff + x] = static_cast<U8>(XGetPixel(ximage, x, y));
  149. // }
  150. // // Done with the image.
  151. // XDestroyImage(ximage);
  152. // // Add it to the bitmap.
  153. // retFont->insertBitmap(i, // index
  154. // scratchPad, // src
  155. // extent.xOff, // stride
  156. // extent.xOff, // width
  157. // font->height, // height
  158. // 0, // xOrigin
  159. // font->ascent, // yOrigin
  160. // extent.xOff); // xIncrement
  161. //
  162. // }
  163. // retFont->pack(font->height, font->ascent);
  164. // XftFontClose(display, font);
  165. //
  166. // XftColorFree(display, DefaultVisual(display, screen),
  167. // DefaultColormap(display, screen), &black);
  168. // XftColorFree(display, DefaultVisual(display, screen),
  169. // DefaultColormap(display, screen), &white);
  170. // XftDrawDestroy(draw);
  171. // XFreePixmap(display, pixmap);
  172. // XCloseDisplay(display);
  173. // return retFont;
  174. //}
  175. // XA: New class for the unix unicode font
  176. PlatformFont *createPlatformFont(const char *name, dsize_t size, U32 charset /* = TGE_ANSI_CHARSET */)
  177. {
  178. PlatformFont *retFont = new x86UNIXFont;
  179. if(retFont->create(name, size, charset))
  180. return retFont;
  181. delete retFont;
  182. return NULL;
  183. }
  184. x86UNIXFont::x86UNIXFont()
  185. {}
  186. x86UNIXFont::~x86UNIXFont()
  187. {}
  188. bool x86UNIXFont::create(const char *name, dsize_t size, U32 charset)
  189. {
  190. Display *display = XOpenDisplay(getenv("DISPLAY"));
  191. if (display == NULL)
  192. AssertFatal(false, "createFont: cannot connect to X server");
  193. XftFont *font = loadFont(name, size, display);
  194. if (!font)
  195. {
  196. Con::errorf("Error: Could not load font -%s-", name);
  197. return false;
  198. }
  199. char xfontname[1024];
  200. XftNameUnparse(font->pattern, xfontname, 1024);
  201. #ifdef DEBUG
  202. Con::printf("CreateFont: request for %s %d, using %s", name, size, xfontname);
  203. #endif
  204. // store some info about the font
  205. baseline = font->ascent;
  206. height = font->height;
  207. mFontName = StringTable->insert(xfontname);
  208. XftFontClose (display, font);
  209. // DISPLAY
  210. XCloseDisplay(display);
  211. return true;
  212. }
  213. bool x86UNIXFont::isValidChar(const UTF16 str) const
  214. {
  215. // 0x20 == 32
  216. // 0x100 == 256
  217. if( str < 0x20 || str > 0x100 )
  218. return false;
  219. return true;
  220. }
  221. bool x86UNIXFont::isValidChar(const UTF8 *str) const
  222. {
  223. return isValidChar(oneUTF32toUTF16(oneUTF8toUTF32(str,NULL)));
  224. }
  225. PlatformFont::CharInfo &x86UNIXFont::getCharInfo(const UTF16 ch) const
  226. {
  227. Display *display = XOpenDisplay(getenv("DISPLAY"));
  228. if (!display )
  229. AssertFatal(false, "createFont: cannot connect to X server");
  230. static PlatformFont::CharInfo c;
  231. dMemset(&c, 0, sizeof(c));
  232. c.bitmapIndex = 0;
  233. c.xOffset = 0;
  234. c.yOffset = 0;
  235. XftFont *fontInfo = XftFontOpenName(display, DefaultScreen(display), mFontName);
  236. if (!fontInfo)
  237. AssertFatal(false, "createFont: cannot load font");
  238. int screen = DefaultScreen(display);
  239. // Create the pixmap to draw on.
  240. Drawable pixmap = XCreatePixmap(display,
  241. DefaultRootWindow(display),
  242. fontInfo->max_advance_width,
  243. fontInfo->height,
  244. DefaultDepth(display, screen));
  245. // And the Xft wrapper around it.
  246. XftDraw *draw = XftDrawCreate(display,
  247. pixmap,
  248. DefaultVisual(display, screen),
  249. DefaultColormap(display, screen));
  250. // Allocate some colors, we don't use XftColorAllocValue here as that
  251. // Don't appear to function correctly (or I'm using it wrong) As we only do
  252. // this twice per new un cached font it isn't that big of a penalty. (Each
  253. // call to XftColorAllocName involves a round trip to the X Server)
  254. XftColor black, white;
  255. XftColorAllocName(display,
  256. DefaultVisual(display, screen),
  257. DefaultColormap(display, screen),
  258. "black",
  259. &black);
  260. // White
  261. XftColorAllocName(display,
  262. DefaultVisual(display, screen),
  263. DefaultColormap(display, screen),
  264. "white",
  265. &white);
  266. XGlyphInfo charinfo;
  267. XftTextExtents16(display, fontInfo, &ch, 1, &charinfo);
  268. c.height = fontInfo->height;
  269. c.xOrigin = 0;
  270. c.yOrigin = fontInfo->ascent;
  271. c.xIncrement = charinfo.xOff;
  272. c.width = charinfo.xOff;
  273. // kick out early if the character is undrawable
  274. if( c.width == 0 || c.height == 0)
  275. return c;
  276. // allocate a greyscale bitmap and clear it.
  277. int bitmapDataSize = c.width * c.height;
  278. c.bitmapData = new U8[bitmapDataSize];
  279. dMemset(c.bitmapData, 0, bitmapDataSize);
  280. XftDrawRect (draw, &black, 0, 0, fontInfo->max_advance_width, fontInfo->height);
  281. XftDrawString16 (draw, &white, fontInfo, 0, fontInfo->ascent, &ch, 1);
  282. // grab the pixmap image
  283. XImage *ximage = XGetImage(display, pixmap, 0, 0,
  284. charinfo.xOff, fontInfo->height,
  285. AllPlanes, XYPixmap);
  286. if (!ximage)
  287. AssertFatal(false, "cannot get x image");
  288. int x, y;
  289. // grab each pixel and store it in the scratchPad
  290. for(y = 0; y < fontInfo->height; y++)
  291. {
  292. for(x = 0; x < charinfo.xOff; x++)
  293. c.bitmapData[y * charinfo.xOff + x] = static_cast<U8>(XGetPixel(ximage, x, y));
  294. }
  295. XDestroyImage(ximage);
  296. XftColorFree(display, DefaultVisual(display, screen),
  297. DefaultColormap(display, screen), &black);
  298. XftColorFree(display, DefaultVisual(display, screen),
  299. DefaultColormap(display, screen), &white);
  300. XftDrawDestroy(draw);
  301. XFreePixmap(display, pixmap);
  302. XCloseDisplay(display);
  303. return c;
  304. }
  305. PlatformFont::CharInfo &x86UNIXFont::getCharInfo(const UTF8 *str) const
  306. {
  307. return getCharInfo(oneUTF32toUTF16(oneUTF8toUTF32(str,NULL)));
  308. }