x86UNIXFont.cc 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 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 "graphics/gFont.h"
  23. #include "graphics/gBitmap.h"
  24. #include "math/mRect.h"
  25. #include "console/console.h"
  26. #include "string/unicode.h"
  27. #include "platformX86UNIX/platformX86UNIX.h"
  28. #include "platformX86UNIX/x86UNIXFont.h"
  29. // Needed by createFont
  30. #include <X11/Xlib.h>
  31. #include <X11/Xutil.h>
  32. #include <X11/Xos.h>
  33. #include <X11/Xatom.h>
  34. #include <X11/Xft/Xft.h>
  35. #include <X11/extensions/Xrender.h> // For XRenderColor
  36. // Needed for getenv in createFont
  37. #include <stdlib.h>
  38. XftFont *loadFont(const char *name, S32 size, Display *display)
  39. {
  40. XftFont *fontInfo = NULL;
  41. char* fontname = const_cast<char*>(name);
  42. if (dStrlen(fontname)==0)
  43. fontname = "arial";
  44. else if (stristr(const_cast<char*>(name), "arial") != NULL)
  45. fontname = "arial";
  46. else if (stristr(const_cast<char*>(name), "lucida console") != NULL)
  47. fontname = "lucida console";
  48. char* weight = "medium";
  49. char* slant = "roman"; // no slant
  50. if (stristr(const_cast<char*>(name), "bold") != NULL)
  51. weight = "bold";
  52. if (stristr(const_cast<char*>(name), "italic") != NULL)
  53. slant = "italic";
  54. int mSize = size - 2 - (int)((float)size * 0.1);
  55. char xfontName[512];
  56. // We specify a lower DPI to get 'correct' looking fonts, if we go with the
  57. // native DPI the fonts are to big and don't fit the widgets.
  58. dSprintf(xfontName, 512, "%s-%d:%s:slant=%s:dpi=76", fontname, mSize, weight, slant);
  59. // Lets see if Xft can get a font for us.
  60. char xftname[1024];
  61. fontInfo = XftFontOpenName(display, DefaultScreen(display), xfontName);
  62. // Cant find a suitabke font, default to a known font (6x10)
  63. if ( !fontInfo )
  64. {
  65. dSprintf(xfontName, 512, "6x10-%d:%s:slant=%s:dpi=76", mSize, weight, slant);
  66. fontInfo = XftFontOpenName(display, DefaultScreen(display), xfontName);
  67. }
  68. XftNameUnparse(fontInfo->pattern, xftname, 1024);
  69. #ifdef DEBUG
  70. Con::printf("Font '%s %d' mapped to '%s'\n", name, size, xftname);
  71. #endif
  72. return fontInfo;
  73. }
  74. // XA: New class for the unix unicode font
  75. PlatformFont *createPlatformFont(const char *name, U32 size, U32 charset /* = TGE_ANSI_CHARSET */)
  76. {
  77. PlatformFont *retFont = new x86UNIXFont;
  78. if(retFont->create(name, size, charset))
  79. return retFont;
  80. delete retFont;
  81. return NULL;
  82. }
  83. x86UNIXFont::x86UNIXFont()
  84. {}
  85. x86UNIXFont::~x86UNIXFont()
  86. {}
  87. bool x86UNIXFont::create(const char *name, U32 size, U32 charset)
  88. {
  89. Display *display = XOpenDisplay(getenv("DISPLAY"));
  90. if (display == NULL)
  91. AssertFatal(false, "createFont: cannot connect to X server");
  92. XftFont *font = loadFont(name, size, display);
  93. if (!font)
  94. {
  95. Con::errorf("Error: Could not load font -%s-", name);
  96. return false;
  97. }
  98. char xfontname[1024];
  99. XftNameUnparse(font->pattern, xfontname, 1024);
  100. #ifdef DEBUG
  101. Con::printf("CreateFont: request for %s %d, using %s", name, size, xfontname);
  102. #endif
  103. // store some info about the font
  104. baseline = font->ascent;
  105. height = font->height;
  106. mFontName = StringTable->insert(xfontname);
  107. XftFontClose (display, font);
  108. // DISPLAY
  109. XCloseDisplay(display);
  110. return true;
  111. }
  112. bool x86UNIXFont::isValidChar(const UTF16 str) const
  113. {
  114. // 0x20 == 32
  115. // 0x100 == 256
  116. if( str < 0x20 || str > 0x100 )
  117. return false;
  118. return true;
  119. }
  120. bool x86UNIXFont::isValidChar(const UTF8 *str) const
  121. {
  122. return isValidChar(oneUTF32toUTF16(oneUTF8toUTF32(str,NULL)));
  123. }
  124. PlatformFont::CharInfo &x86UNIXFont::getCharInfo(const UTF16 ch) const
  125. {
  126. Display *display = XOpenDisplay(getenv("DISPLAY"));
  127. if (!display )
  128. AssertFatal(false, "createFont: cannot connect to X server");
  129. static PlatformFont::CharInfo c;
  130. dMemset(&c, 0, sizeof(c));
  131. c.bitmapIndex = 0;
  132. c.xOffset = 0;
  133. c.yOffset = 0;
  134. XftFont *fontInfo = XftFontOpenName(display, DefaultScreen(display), mFontName);
  135. if (!fontInfo)
  136. {
  137. //Try a fall back font before crashing..
  138. fontInfo = XftFontOpenName(display, DefaultScreen(display), "lucida console-10:dpi=76");
  139. if (!fontInfo)
  140. {
  141. AssertFatal(false, "createFont: cannot load font");
  142. }
  143. }
  144. int screen = DefaultScreen(display);
  145. // Create the pixmap to draw on.
  146. Drawable pixmap = XCreatePixmap(display,
  147. DefaultRootWindow(display),
  148. fontInfo->max_advance_width,
  149. fontInfo->height,
  150. DefaultDepth(display, screen));
  151. // And the Xft wrapper around it.
  152. XftDraw *draw = XftDrawCreate(display,
  153. pixmap,
  154. DefaultVisual(display, screen),
  155. DefaultColormap(display, screen));
  156. // Allocate some colors, we don't use XftColorAllocValue here as that
  157. // Don't appear to function correctly (or I'm using it wrong) As we only do
  158. // this twice per new un cached font it isn't that big of a penalty. (Each
  159. // call to XftColorAllocName involves a round trip to the X Server)
  160. XftColor black, white;
  161. XftColorAllocName(display,
  162. DefaultVisual(display, screen),
  163. DefaultColormap(display, screen),
  164. "black",
  165. &black);
  166. // White
  167. XftColorAllocName(display,
  168. DefaultVisual(display, screen),
  169. DefaultColormap(display, screen),
  170. "white",
  171. &white);
  172. XGlyphInfo charinfo;
  173. XftTextExtents16(display, fontInfo, &ch, 1, &charinfo);
  174. c.height = fontInfo->height;
  175. c.xOrigin = 0;
  176. c.yOrigin = fontInfo->ascent;
  177. c.xIncrement = charinfo.xOff;
  178. c.width = charinfo.xOff;
  179. // kick out early if the character is undrawable
  180. if( c.width == 0 || c.height == 0)
  181. return c;
  182. // allocate a greyscale bitmap and clear it.
  183. int bitmapDataSize = c.width * c.height;
  184. c.bitmapData = new U8[bitmapDataSize];
  185. dMemset(c.bitmapData, 0, bitmapDataSize);
  186. XftDrawRect (draw, &black, 0, 0, fontInfo->max_advance_width, fontInfo->height);
  187. XftDrawString16 (draw, &white, fontInfo, 0, fontInfo->ascent, &ch, 1);
  188. // grab the pixmap image
  189. XImage *ximage = XGetImage(display, pixmap, 0, 0,
  190. charinfo.xOff, fontInfo->height,
  191. AllPlanes, XYPixmap);
  192. if (!ximage)
  193. AssertFatal(false, "cannot get x image");
  194. int x, y;
  195. // grab each pixel and store it in the scratchPad
  196. for(y = 0; y < fontInfo->height; y++)
  197. {
  198. for(x = 0; x < charinfo.xOff; x++)
  199. c.bitmapData[y * charinfo.xOff + x] = static_cast<U8>(XGetPixel(ximage, x, y));
  200. }
  201. XDestroyImage(ximage);
  202. XftColorFree(display, DefaultVisual(display, screen),
  203. DefaultColormap(display, screen), &black);
  204. XftColorFree(display, DefaultVisual(display, screen),
  205. DefaultColormap(display, screen), &white);
  206. XftDrawDestroy(draw);
  207. XFreePixmap(display, pixmap);
  208. XCloseDisplay(display);
  209. return c;
  210. }
  211. PlatformFont::CharInfo &x86UNIXFont::getCharInfo(const UTF8 *str) const
  212. {
  213. return getCharInfo(oneUTF32toUTF16(oneUTF8toUTF32(str,NULL)));
  214. }