PageRenderTime 57ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/rxvt-unicode-9.15/rxvt-unicode-9.15-256color-ml/src/rxvtfont.C

#
C++ | 1799 lines | 1338 code | 382 blank | 79 comment | 339 complexity | bcd9680e693655aa6b47619cd8ece770 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*----------------------------------------------------------------------*
  2. * File: rxvtfont.C
  3. *----------------------------------------------------------------------*
  4. * Copyright (c) 2003-2008 Marc Lehmann <schmorp@schmorp.de>
  5. * - original version.
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *---------------------------------------------------------------------*/
  21. #include "../config.h"
  22. #include "rxvt.h"
  23. #include "rxvtutil.h"
  24. #include "rxvtfont.h"
  25. #include <stdlib.h>
  26. #include <inttypes.h>
  27. #if XFT
  28. # include <fontconfig/fontconfig.h>
  29. #endif
  30. #define MAX_OVERLAP_ROMAN (8 + 2) // max. character width in 8ths of the base width
  31. #define MAX_OVERLAP_ITALIC (8 + 3) // max. overlap for italic fonts
  32. #define OVERLAP_OK(w,wcw,prop) ((w) <= ( \
  33. (prop)->slant >= rxvt_fontprop::italic \
  34. ? ((prop)->width * (wcw) * MAX_OVERLAP_ITALIC + 7) >> 3 \
  35. : ((prop)->width * (wcw) * MAX_OVERLAP_ROMAN + 7) >> 3 \
  36. ))
  37. static const struct rxvt_fallback_font {
  38. codeset cs;
  39. const char *name;
  40. } fallback_fonts[] = {
  41. { CS_ISO8859_1, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-1" },
  42. { CS_ISO8859_15, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-15" },
  43. { CS_ISO8859_15, "-*-*-*-r-*--*-*-*-*-c-*-fcd8859-15" },
  44. #if ENCODING_EU
  45. // cyrillic
  46. { CS_KOI8_R, "-*-*-*-r-*--*-*-*-*-c-*-koi8-r" },
  47. { CS_KOI8_U, "-*-*-*-r-*--*-*-*-*-c-*-koi8-u" },
  48. { CS_ISO8859_2, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-2" },
  49. { CS_ISO8859_3, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-3" },
  50. { CS_ISO8859_4, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-4" },
  51. { CS_ISO8859_5, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-5" },
  52. { CS_ISO8859_6, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-6" },
  53. { CS_ISO8859_7, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-7" },
  54. { CS_ISO8859_8, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-8" },
  55. { CS_ISO8859_9, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-9" },
  56. { CS_ISO8859_10, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-10" },
  57. { CS_ISO8859_11, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-11" },
  58. { CS_ISO8859_13, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-13" },
  59. { CS_ISO8859_14, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-14" },
  60. { CS_ISO8859_16, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-16" },
  61. # if XFT
  62. { CS_KOI8_U, "xft::lang=ru" },
  63. { CS_ISO8859_5, "xft::lang=ru" },
  64. { CS_ISO8859_6, "xft::lang=ar" },
  65. { CS_ISO8859_7, "xft::lang=el" },
  66. { CS_ISO8859_8, "xft::lang=he" },
  67. { CS_ISO8859_9, "xft::lang=tr" },
  68. { CS_ISO8859_10, "xft::lang=se" },
  69. { CS_ISO8859_11, "xft::lang=th" },
  70. # endif
  71. #endif
  72. // japanese
  73. #if ENCODING_JP || ENCODING_JP_EXT
  74. # if XFT
  75. // prefer xft for complex scripts
  76. { CS_JIS0208_1990_0, "xft:Sazanami Mincho:antialias=false" },
  77. { CS_JIS0208_1990_0, "xft:Kochi Gothic:antialias=false" },
  78. { CS_JIS0208_1990_0, "xft:Mincho:antialias=false" },
  79. { CS_JIS0208_1990_0, "xft::lang=ja:antialias=false" },
  80. # endif
  81. { CS_JIS0201_1976_0, "-*-mincho-*-r-*--*-*-*-*-c-*-jisx0201*-0" },
  82. { CS_JIS0208_1990_0, "-*-mincho-*-r-*--*-*-*-*-c-*-jisx0208*-0" },
  83. { CS_JIS0212_1990_0, "-*-mincho-*-r-*--*-*-*-*-c-*-jisx0212*-0" },
  84. { CS_JIS0201_1976_0, "-*-*-*-r-*--*-*-*-*-c-*-jisx0201*-0" },
  85. { CS_JIS0208_1990_0, "-*-*-*-r-*--*-*-*-*-c-*-jisx0208*-0" },
  86. { CS_JIS0212_1990_0, "-*-*-*-r-*--*-*-*-*-c-*-jisx0212*-0" },
  87. #endif
  88. #if ENCODING_ZH || ENCODING_ZH_EXT
  89. # if XFT
  90. { CS_GBK_0, "xft:AR PL KaitiM GB" },
  91. { CS_GBK_0, "xft:AR PL SungtiL GB" },
  92. { CS_GBK_0, "xft::lang=zh" },
  93. { CS_BIG5_EXT, "xft:AR PL Mingti2L Big5" },
  94. { CS_BIG5_EXT, "xft:AR PL KaitiM Big5" },
  95. { CS_GB2312_1980_0, "xft:AR PL KaitiM GB" },
  96. { CS_GB2312_1980_0, "xft:AR PL SungtiL GB" },
  97. { CS_GB2312_1980_0, "xft::lang=zh" },
  98. # endif
  99. { CS_GBK_0, "-*-*-*-*-*-*-*-*-*-*-c-*-gbk*-0" },
  100. { CS_BIG5, "-*-*-*-*-*-*-*-*-*-*-c-*-big5-0" },
  101. { CS_BIG5_PLUS, "-*-*-*-*-*-*-*-*-*-*-c-*-big5p-0" },
  102. { CS_BIG5_EXT, "-*-*-*-*-*-*-*-*-*-*-c-*-big5.eten-0" },
  103. { CS_GB2312_1980_0, "-*-*-*-*-*-*-*-*-*-*-c-*-gb2312*-0" },
  104. { CS_CNS11643_1992_1, "-*-*-*-*-*-*-*-*-*-*-c-*-gb2312*-0" },
  105. { CS_CNS11643_1992_1, "-*-*-*-*-*-*-*-*-*-*-c-*-cns11643*-1" },
  106. { CS_CNS11643_1992_2, "-*-*-*-*-*-*-*-*-*-*-c-*-cns11643*-2" },
  107. { CS_CNS11643_1992_3, "-*-*-*-*-*-*-*-*-*-*-c-*-cns11643*-3" },
  108. { CS_CNS11643_1992_4, "-*-*-*-*-*-*-*-*-*-*-c-*-cns11643*-4" },
  109. { CS_CNS11643_1992_5, "-*-*-*-*-*-*-*-*-*-*-c-*-cns11643*-5" },
  110. { CS_CNS11643_1992_6, "-*-*-*-*-*-*-*-*-*-*-c-*-cns11643*-6" },
  111. { CS_CNS11643_1992_7, "-*-*-*-*-*-*-*-*-*-*-c-*-cns11643*-7" },
  112. { CS_CNS11643_1992_F, "-*-*-*-*-*-*-*-*-*-*-c-*-cns11643*-f" },
  113. #endif
  114. #if ENCODING_KR
  115. { CS_KSC5601_1987_0, "-baekmuk-gulim-*-*-*-*-*-*-*-*-c-*-ksc5601*" },
  116. { CS_KSC5601_1987_0, "-*-*-*-*-*-*-*-*-*-*-c-*-ksc5601*" },
  117. # if XFT
  118. { CS_KSC5601_1987_0, "xft:Baekmuk Gulim:antialias=false" },
  119. { CS_KSC5601_1987_0, "xft::lang=ko:antialias=false" },
  120. # endif
  121. #endif
  122. //{ CS_UNICODE, "-*-unifont-*-*-*-*-*-*-*-*-c-*-iso10646-1" }, // this gem of a font has actual dotted circles within the combining character glyphs.
  123. #if XFT
  124. { CS_UNICODE, "xft:Bitstream Vera Sans Mono:antialias=false:autohint=true" },
  125. { CS_UNICODE, "xft:Courier New:antialias=false:autohint=true" },
  126. { CS_UNICODE, "xft:Andale Mono:antialias=false:autohint=false" },
  127. { CS_UNICODE, "xft:Arial Unicode MS:antialias=false:autohint=false" },
  128. // FreeMono is usually uglier than x fonts, so try after the others
  129. { CS_UNICODE, "xft:FreeMono:autohint=true" },
  130. #endif
  131. // generic font fallback, put this last, as many iso10646 fonts have extents
  132. // specified for all glyphs in the range they cover, but most are simply empty
  133. //{ CS_UNICODE, "-*-*-*-r-*-*-*-*-*-*-c-*-iso10646-1" },
  134. //{ CS_UNICODE, "-*-*-*-r-*-*-*-*-*-*-m-*-iso10646-1" },
  135. { CS_UNKNOWN, 0 }
  136. };
  137. // these characters are used to guess the font height and width
  138. // pango uses a similar algorithm and doesn't trust the font either.
  139. static uint16_t extent_test_chars[] = {
  140. '0', '1', '8', 'a', 'd', 'x', 'm', 'y', 'g', 'W', 'X', '\'', '_',
  141. 0x00cd, 0x00d5, 0x0114, 0x0177, 0x0643, // 葉???
  142. 0x304c, 0x672c, // ??
  143. };
  144. #define dTermDisplay Display *disp = term->dpy
  145. #define dTermGC GC gc = term->gc
  146. /////////////////////////////////////////////////////////////////////////////
  147. static const char *
  148. enc_char (const text_t *text, uint32_t len, codeset cs, bool &zero)
  149. {
  150. uint8_t *buf = rxvt_temp_buf<uint8_t> (len);
  151. uint8_t *res = buf;
  152. while (len--)
  153. {
  154. uint32_t c = FROM_UNICODE (cs, *text++);
  155. if (c == NOCHAR)
  156. {
  157. c = 0;
  158. zero = true;
  159. }
  160. *buf++ = c;
  161. }
  162. return (const char *)res;
  163. }
  164. static const XChar2b *
  165. enc_xchar2b (const text_t *text, uint32_t len, codeset cs, bool &zero)
  166. {
  167. XChar2b *buf = rxvt_temp_buf<XChar2b> (len);
  168. XChar2b *res = buf;
  169. while (len--)
  170. {
  171. uint32_t c = FROM_UNICODE (cs, *text++);
  172. if (c == NOCHAR)
  173. {
  174. c = 0;
  175. zero = true;
  176. }
  177. buf->byte1 = c >> 8;
  178. buf->byte2 = c;
  179. buf++;
  180. }
  181. return res;
  182. }
  183. /////////////////////////////////////////////////////////////////////////////
  184. rxvt_font::rxvt_font ()
  185. : name(0), width(rxvt_fontprop::unset), height(rxvt_fontprop::unset)
  186. {
  187. }
  188. void
  189. rxvt_font::set_name (char *name_)
  190. {
  191. if (name == name_)
  192. return;
  193. if (name) free (name); // let the compiler optimize
  194. name = name_;
  195. }
  196. void
  197. rxvt_font::clear_rect (rxvt_drawable &d, int x, int y, int w, int h, int color) const
  198. {
  199. dTermDisplay;
  200. dTermGC;
  201. if (color == Color_bg || color == Color_transparent)
  202. XClearArea (disp, d, x, y, w, h, false);
  203. else if (color >= 0)
  204. {
  205. #if XFT
  206. Picture dst;
  207. # ifdef HAVE_BG_PIXMAP
  208. if (term->bg_pixmap
  209. && !term->pix_colors[color].is_opaque ()
  210. && ((dst = XftDrawPicture (d))))
  211. {
  212. XClearArea (disp, d, x, y, w, h, false);
  213. Picture solid_color_pict = XftDrawSrcPicture (d, &term->pix_colors[color].c);
  214. XRenderComposite (disp, PictOpOver, solid_color_pict, None, dst, 0, 0, 0, 0, x, y, w, h);
  215. }
  216. else
  217. # endif
  218. XftDrawRect (d, &term->pix_colors[color].c, x, y, w, h);
  219. #else
  220. XSetForeground (disp, gc, term->pix_colors[color]);
  221. XFillRectangle (disp, d, gc, x, y, w, h);
  222. #endif
  223. }
  224. }
  225. /////////////////////////////////////////////////////////////////////////////
  226. struct rxvt_font_default : rxvt_font {
  227. struct rxvt_fontset *fs;
  228. rxvt_font_default (rxvt_fontset *fs)
  229. : rxvt_font ()
  230. {
  231. this->fs = fs;
  232. }
  233. rxvt_fontprop properties ()
  234. {
  235. rxvt_fontprop p;
  236. p.width = p.height = 1;
  237. p.ascent = rxvt_fontprop::unset;
  238. p.weight = rxvt_fontprop::medium;
  239. p.slant = rxvt_fontprop::roman;
  240. return p;
  241. }
  242. bool load (const rxvt_fontprop &prop, bool force_prop)
  243. {
  244. width = 1; height = 1;
  245. ascent = 1; descent = 0;
  246. set_name (strdup ("built-in support font"));
  247. return true;
  248. }
  249. bool has_char (unicode_t unicode, const rxvt_fontprop *prop, bool &careful) const
  250. {
  251. careful = false;
  252. if (unicode <= 0x001f)
  253. return true;
  254. if (unicode <= 0x007f)
  255. return false;
  256. if (unicode <= 0x009f)
  257. return true;
  258. #ifdef BUILTIN_GLYPHS
  259. if (unicode >= 0x2500 && unicode <= 0x259f &&
  260. !term->option (Opt_skipBuiltinGlyphs))
  261. return true;
  262. #endif
  263. if (IS_COMPOSE (unicode))
  264. return true;
  265. switch (unicode)
  266. {
  267. case ZERO_WIDTH_CHAR:
  268. case NOCHAR:
  269. return true;
  270. }
  271. return false;
  272. }
  273. void draw (rxvt_drawable &d, int x, int y,
  274. const text_t *text, int len,
  275. int fg, int bg);
  276. };
  277. void
  278. rxvt_font_default::draw (rxvt_drawable &d, int x, int y,
  279. const text_t *text, int len,
  280. int fg, int bg)
  281. {
  282. dTermDisplay;
  283. dTermGC;
  284. clear_rect (d, x, y, term->fwidth * len, term->fheight, bg);
  285. XSetForeground (disp, gc, term->pix_colors[fg]);
  286. while (len)
  287. {
  288. #if ENABLE_COMBINING
  289. compose_char *cc;
  290. #endif
  291. const text_t *tp = text;
  292. text_t t = *tp;
  293. while (++text, --len && *text == NOCHAR)
  294. ;
  295. int width = text - tp;
  296. int fwidth = term->fwidth * width;
  297. #ifdef BUILTIN_GLYPHS
  298. if (0x2500 <= t && t <= 0x259f)
  299. {
  300. # include "table/linedraw.h"
  301. uint16_t offs = linedraw_offs[t - 0x2500];
  302. uint32_t *a = linedraw_command + (offs >> 4);
  303. uint32_t *b = a + (offs & 15);
  304. int W = fwidth;
  305. int H = term->fheight;
  306. int x_[16];
  307. int y_[16];
  308. for (int i = 0; i <= 8; i++)
  309. {
  310. x_[i] = x + ((W-1) * i + (i*7/8)) / 8;
  311. y_[i] = y + ((H-1) * i + (i*7/8)) / 8;
  312. }
  313. x_[10] = x + (W - 1) / 2; x_[9] = x_[10] - 1; x_[11] = x_[10] + 1;
  314. y_[10] = y + (H - 1) / 2; y_[9] = y_[10] - 1; y_[11] = y_[10] + 1;
  315. XGCValues gcv;
  316. gcv.cap_style = CapButt;
  317. gcv.line_width = 0;
  318. XChangeGC (disp, gc, GCLineWidth | GCCapStyle, &gcv);
  319. while (a < b)
  320. {
  321. uint32_t command = *a++;
  322. int op = (command >> 24) & 255;
  323. int a = (command >> 20) & 15;
  324. int b = (command >> 16) & 15;
  325. int x1 = x_[(command >> 12) & 15];
  326. int y1 = y_[(command >> 8) & 15];
  327. int x2 = x_[(command >> 4) & 15];
  328. int y2 = y_[(command >> 0) & 15];
  329. switch (op)
  330. {
  331. case 0: // line
  332. XDrawLine (disp, d, gc, x1, y1, x2, y2);
  333. break;
  334. case 1: // rectangle, possibly stippled
  335. if (a)
  336. {
  337. static char bm[] = { 0,0 , 3,1 , 1,2 , 1,0 };
  338. gcv.fill_style = FillStippled;
  339. gcv.stipple = XCreateBitmapFromData (disp, d, bm + a * 2, 2, 2);
  340. gcv.ts_x_origin = x;
  341. gcv.ts_y_origin = y;
  342. XChangeGC (disp, gc,
  343. GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin,
  344. &gcv);
  345. }
  346. XFillRectangle (disp, d, gc, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
  347. if (a)
  348. {
  349. XFreePixmap (disp, gcv.stipple);
  350. gcv.stipple = 0;
  351. gcv.fill_style = FillSolid;
  352. XChangeGC (disp, gc, GCFillStyle, &gcv);
  353. }
  354. break;
  355. case 2: // arc
  356. XDrawArc (disp, d, gc,
  357. x1 - W/2, y1 - H/2, W-1, H-1,
  358. (a - 1) * 90*64, (b - 1) * 90*64);
  359. break;
  360. }
  361. }
  362. }
  363. #else
  364. if (0)
  365. ;
  366. #endif
  367. #if ENABLE_COMBINING
  368. else if (IS_COMPOSE (t) && (cc = rxvt_composite[t]))
  369. {
  370. min_it (width, 2); // we only support wcwidth up to 2
  371. text_t chrs[2];
  372. chrs [1] = NOCHAR;
  373. *chrs = cc->c1;
  374. rxvt_font *f1 = (*fs)[fs->find_font_idx (cc->c1)];
  375. f1->draw (d, x, y, chrs, width, fg, bg);
  376. if (cc->c2 != NOCHAR)
  377. {
  378. bool careful;
  379. // prefer font of first character, for no good reasons
  380. *chrs = cc->c2;
  381. rxvt_font *f2 = (f1->has_char (cc->c2, 0, careful) && !careful)
  382. ? f1
  383. : (*fs)[fs->find_font_idx (cc->c2)];
  384. f2->draw (d, x, y, chrs, width, fg, Color_none);
  385. }
  386. }
  387. #endif
  388. else
  389. switch (t)
  390. {
  391. case '\t':
  392. case ZERO_WIDTH_CHAR:
  393. case NOCHAR:
  394. break;
  395. default:
  396. XDrawRectangle (disp, d, gc, x + 2, y + 2,
  397. fwidth - 4, term->fheight - 4);
  398. }
  399. x += fwidth;
  400. }
  401. }
  402. struct rxvt_font_overflow : rxvt_font {
  403. struct rxvt_fontset *fs;
  404. rxvt_font_overflow (rxvt_fontset *fs)
  405. : rxvt_font ()
  406. {
  407. this->fs = fs;
  408. }
  409. rxvt_fontprop properties ()
  410. {
  411. rxvt_fontprop p;
  412. p.width = p.height = 1;
  413. p.ascent = rxvt_fontprop::unset;
  414. p.weight = rxvt_fontprop::medium;
  415. p.slant = rxvt_fontprop::roman;
  416. return p;
  417. }
  418. bool load (const rxvt_fontprop &prop, bool force_prop)
  419. {
  420. width = 1; height = 1;
  421. ascent = 1; descent = 0;
  422. set_name (strdup ("built-in rendition overflow font"));
  423. return true;
  424. }
  425. bool has_char (unicode_t unicode, const rxvt_fontprop *prop, bool &careful) const
  426. {
  427. return false;
  428. }
  429. void draw (rxvt_drawable &d, int x, int y,
  430. const text_t *text, int len,
  431. int fg, int bg)
  432. {
  433. while (len)
  434. {
  435. int fid = fs->find_font_idx (*text);
  436. int w = 1;
  437. while (w < len && text[w] == NOCHAR)
  438. w++;
  439. (*fs)[fid]->draw (d, x, y, text, w, fg, bg);
  440. text += w;
  441. len -= w;
  442. x += term->fwidth * w;
  443. }
  444. }
  445. };
  446. /////////////////////////////////////////////////////////////////////////////
  447. struct rxvt_font_x11 : rxvt_font {
  448. rxvt_font_x11 () { f = 0; }
  449. void clear ();
  450. rxvt_fontprop properties ();
  451. bool load (const rxvt_fontprop &prop, bool force_prop);
  452. bool has_char (unicode_t unicode, const rxvt_fontprop *prop, bool &careful) const;
  453. void draw (rxvt_drawable &d, int x, int y,
  454. const text_t *text, int len,
  455. int fg, int bg);
  456. bool slow; // whether this is a proportional font or has other funny characteristics
  457. XFontStruct *f;
  458. bool enc2b, encm;
  459. char *get_property (XFontStruct *f, Atom property, const char *repl) const;
  460. bool set_properties (rxvt_fontprop &p, int height, const char *weight, const char *slant, int avgwidth);
  461. bool set_properties (rxvt_fontprop &p, XFontStruct *f);
  462. bool set_properties (rxvt_fontprop &p, const char *name);
  463. };
  464. char *
  465. rxvt_font_x11::get_property (XFontStruct *f, Atom property, const char *repl) const
  466. {
  467. unsigned long value;
  468. if (XGetFontProperty (f, property, &value))
  469. return XGetAtomName (term->dpy, value);
  470. else
  471. return repl ? strdup (repl) : 0;
  472. }
  473. rxvt_fontprop
  474. rxvt_font_x11::properties ()
  475. {
  476. rxvt_fontprop p;
  477. set_properties (p, f);
  478. return p;
  479. }
  480. bool
  481. rxvt_font_x11::set_properties (rxvt_fontprop &p, int height, const char *weight, const char *slant, int avgwidth)
  482. {
  483. p.width = width != rxvt_fontprop::unset ? width
  484. : avgwidth ? (avgwidth + 1) / 10
  485. : (height + 1) / 2;
  486. p.height = height;
  487. p.ascent = rxvt_fontprop::unset;
  488. p.weight = *weight == 'B' || *weight == 'b' ? rxvt_fontprop::bold : rxvt_fontprop::medium;
  489. p.slant = *slant == 'r' || *slant == 'R' ? rxvt_fontprop::roman : rxvt_fontprop::italic;
  490. return true;
  491. }
  492. bool
  493. rxvt_font_x11::set_properties (rxvt_fontprop &p, XFontStruct *f)
  494. {
  495. unsigned long height;
  496. #if 0
  497. if (!XGetFontProperty (f, XInternAtom (term->dpy, "PIXEL_SIZE", 0), &height))
  498. return false;
  499. #else
  500. height = f->ascent + f->descent;
  501. #endif
  502. unsigned long avgwidth;
  503. if (!XGetFontProperty (f, term->xa [XA_AVERAGE_WIDTH], &avgwidth))
  504. avgwidth = 0;
  505. char *weight = get_property (f, term->xa [XA_WEIGHT_NAME], "medium");
  506. char *slant = get_property (f, term->xa [XA_SLANT], "r");
  507. set_properties (p, height, weight, slant, avgwidth);
  508. free (weight);
  509. free (slant);
  510. p.ascent = f->ascent;
  511. return true;
  512. }
  513. bool
  514. rxvt_font_x11::set_properties (rxvt_fontprop &p, const char *name)
  515. {
  516. dTermDisplay;
  517. int slashes = 0;
  518. const char *comp[13];
  519. for (const char *c = name; *c; c++)
  520. if (*c == '-')
  521. {
  522. comp[slashes++] = c + 1;
  523. if (slashes >= 13)
  524. break;
  525. }
  526. /* can we short-circuit the costly XLoadQueryFont? */
  527. if (slashes >= 13
  528. && (*comp[ 6] >= '1' && *comp[ 6] <= '9')
  529. && (*comp[11] >= '0' && *comp[11] <= '9'))
  530. return set_properties (p, atoi (comp[6]), comp[2], comp[3], atoi (comp[11]));
  531. XFontStruct *f = XLoadQueryFont (disp, name);
  532. if (f)
  533. {
  534. // the font should really exist now. if not, we have a problem
  535. // (e.g. if the user did xset fp rehash just when we were searching fonts).
  536. // in that case, just return garbage.
  537. bool ret = set_properties (p, f);
  538. XFreeFont (disp, f);
  539. return ret;
  540. }
  541. else
  542. return false;
  543. }
  544. // fix the size of scalable fonts
  545. static bool
  546. replace_field (char **ptr, const char *name, int index, const char old, const char *replace)
  547. {
  548. int slashes = 0;
  549. const char *field, *end;
  550. for (const char *c = name; *c; c++)
  551. if (*c == '-')
  552. {
  553. if (slashes == index)
  554. field = c + 1;
  555. if (slashes == index + 1)
  556. end = c;
  557. if (++slashes >= 13)
  558. break;
  559. }
  560. if (slashes >= 13 && (!old || *field == old))
  561. {
  562. size_t len = field - name;
  563. *ptr = (char *)malloc (len + strlen (replace) + strlen (end) + 1);
  564. memcpy (*ptr, name, len);
  565. strcpy (*ptr + len, replace);
  566. strcat (*ptr, end);
  567. return true;
  568. }
  569. else
  570. {
  571. *ptr = strdup (name);
  572. return false;
  573. }
  574. }
  575. bool
  576. rxvt_font_x11::load (const rxvt_fontprop &prop, bool force_prop)
  577. {
  578. dTermDisplay;
  579. clear ();
  580. char field_str[64]; // enough for 128 bits
  581. // first morph the font if required
  582. if (force_prop)
  583. {
  584. char *fname;
  585. if (name[0] != '-')
  586. {
  587. f = XLoadQueryFont (disp, name);
  588. if (!f)
  589. return false;
  590. char *new_name = get_property (f, XA_FONT, 0);
  591. if (new_name)
  592. set_name (new_name);
  593. else
  594. rxvt_warn ("font '%s' has no FONT property, continuing without.\n", name);
  595. XFreeFont (disp, f);
  596. f = 0;
  597. }
  598. if (prop.weight != rxvt_fontprop::unset)
  599. {
  600. replace_field (&fname, name, 2, 0,
  601. prop.weight < rxvt_fontprop::bold
  602. ? "medium" : "bold");
  603. set_name (fname);
  604. }
  605. if (prop.slant != rxvt_fontprop::unset)
  606. {
  607. replace_field (&fname, name, 3, 0,
  608. prop.slant < rxvt_fontprop::italic
  609. ? "r" : "i"); // TODO: handle "o"blique, too
  610. set_name (fname);
  611. }
  612. }
  613. sprintf (field_str, "%d", prop.height == rxvt_fontprop::unset
  614. ? 0 : prop.height);
  615. struct font_weight {
  616. char *name;
  617. int diff;
  618. void clear ()
  619. {
  620. name = 0;
  621. diff = 0x7fffffff;
  622. }
  623. font_weight () { clear (); }
  624. ~font_weight () { free (name); }
  625. };
  626. char **list;
  627. int count;
  628. list = XListFonts (disp, name, 4000, &count);
  629. set_name (0);
  630. if (!list)
  631. return false;
  632. font_weight *fonts = new font_weight[count];
  633. for (int i = 0; i < count; i++)
  634. {
  635. rxvt_fontprop p;
  636. char *fname;
  637. int diff = 0;
  638. if (replace_field (&fname, list[i], 6, '0', field_str))
  639. diff += 10; // slightly penalize scalable fonts
  640. else
  641. {
  642. free (fname);
  643. if (replace_field (&fname, list[i], 11, '0', "0"))
  644. diff += 300; // more heavily penalize what looks like scaled bitmap fonts
  645. }
  646. if (!set_properties (p, fname)
  647. // also weed out too large fonts
  648. || (prop.height != rxvt_fontprop::unset
  649. && p.height > prop.height))
  650. {
  651. free (fname);
  652. continue;
  653. }
  654. if (prop.height != rxvt_fontprop::unset) diff += (prop.height - p.height) * 128;
  655. if (prop.weight != rxvt_fontprop::unset) diff += abs (prop.weight - p.weight);
  656. if (prop.slant != rxvt_fontprop::unset) diff += abs (prop.slant - p.slant);
  657. //if (prop.width != rxvt_fontprop::unset) diff += abs (prop.width - p.width);
  658. fonts[i].name = fname;
  659. fonts[i].diff = diff;
  660. }
  661. XFreeFontNames (list);
  662. // this loop only iterates when the guessed font-size is too small
  663. for (;;)
  664. {
  665. font_weight *best = fonts;
  666. for (font_weight *w = fonts + 1; w < fonts + count; w++)
  667. if (w->diff < best->diff)
  668. best = w;
  669. if (!best->name
  670. || !(f = XLoadQueryFont (disp, best->name)))
  671. break;
  672. set_name (best->name);
  673. best->clear ();
  674. ascent = f->ascent;
  675. descent = f->descent;
  676. height = ascent + descent;
  677. if (prop.height == rxvt_fontprop::unset
  678. || height <= prop.height)
  679. break; // font is ready for use
  680. // PIXEL_SIZE small enough, but real height too large
  681. clear ();
  682. }
  683. delete [] fonts;
  684. if (!f)
  685. return false;
  686. char *registry = get_property (f, term->xa [XA_CHARSET_REGISTRY], 0);
  687. char *encoding = get_property (f, term->xa [XA_CHARSET_ENCODING], 0);
  688. cs = CS_UNKNOWN;
  689. if (registry && encoding)
  690. {
  691. char charset[64];
  692. snprintf (charset, 64, "%s-%s", registry, encoding);
  693. cs = codeset_from_name (charset);
  694. if (cs == CS_UNKNOWN)
  695. rxvt_warn ("%s: cannot deduce encoding from registry/encoding properties \"%s\", ignoring font.\n", name, charset);
  696. }
  697. free (registry);
  698. free (encoding);
  699. if (cs == CS_UNKNOWN)
  700. {
  701. char *value = get_property (f, XA_FONT, 0);
  702. const char *charset = value;
  703. if (!charset)
  704. charset = name;
  705. int count = 13;
  706. while (*charset)
  707. if (*charset++ == '-' && !--count)
  708. break;
  709. cs = codeset_from_name (charset);
  710. if (cs == CS_UNKNOWN)
  711. rxvt_warn ("%s: cannot deduce encoding from font name property \"%s\", ignoring font.\n", name, charset);
  712. free (value);
  713. }
  714. if (cs == CS_UNKNOWN)
  715. {
  716. clear ();
  717. return false;
  718. }
  719. if (cs == CS_UNICODE)
  720. cs = CS_UNICODE_16; // X11 can have a max. of 65536 chars per font
  721. encm = f->min_byte1 != 0 || f->max_byte1 != 0;
  722. enc2b = encm || f->max_char_or_byte2 > 255;
  723. slow = false;
  724. #if 1 // only used for slow detection, TODO optimize
  725. if (f->min_bounds.width == f->max_bounds.width || !f->per_char)
  726. width = f->max_bounds.width;
  727. else
  728. {
  729. slow = true;
  730. int N = f->max_char_or_byte2 - f->min_char_or_byte2;
  731. if (encm)
  732. N += (f->max_byte1 - f->min_byte1)
  733. * (f->max_char_or_byte2 - f->min_char_or_byte2 + 1);
  734. while (N)
  735. {
  736. if (f->per_char[N].width > width)
  737. width = f->per_char[N].width;
  738. --N;
  739. }
  740. }
  741. #endif
  742. width = 1;
  743. for (uint16_t *t = extent_test_chars; t < extent_test_chars + ecb_array_length (extent_test_chars); t++)
  744. {
  745. if (FROM_UNICODE (cs, *t) == NOCHAR)
  746. continue;
  747. // ignore characters we wouldn't use anyways
  748. bool careful;
  749. if (!has_char (*t, &prop, careful))
  750. continue;
  751. XChar2b ch = { *t >> 8, *t };
  752. XCharStruct g;
  753. int dir_ret, asc_ret, des_ret;
  754. XTextExtents16 (f, &ch, 1, &dir_ret, &asc_ret, &des_ret, &g);
  755. int wcw = WCWIDTH (*t);
  756. if (wcw > 0) g.width = (g.width + wcw - 1) / wcw;
  757. if (width < g.width) width = g.width;
  758. }
  759. #if 0 // do it per-character
  760. if (prop && width > prop->width)
  761. {
  762. clear ();
  763. return false;
  764. }
  765. #endif
  766. return true;
  767. }
  768. void
  769. rxvt_font_x11::clear ()
  770. {
  771. if (f)
  772. {
  773. XFreeFont (term->dpy, f);
  774. f = 0;
  775. }
  776. }
  777. bool
  778. rxvt_font_x11::has_char (unicode_t unicode, const rxvt_fontprop *prop, bool &careful) const
  779. {
  780. careful = false;
  781. uint32_t ch = FROM_UNICODE (cs, unicode);
  782. if (ch == NOCHAR)
  783. return false;
  784. /* check whether the character exists in _this_ font. horrible. */
  785. XCharStruct *xcs;
  786. if (encm)
  787. {
  788. unsigned char byte1 = ch >> 8;
  789. unsigned char byte2 = ch & 255;
  790. if (byte1 < f->min_byte1 || byte1 > f->max_byte1
  791. || byte2 < f->min_char_or_byte2 || byte2 > f->max_char_or_byte2)
  792. return false;
  793. if (f->per_char)
  794. {
  795. int D = f->max_char_or_byte2 - f->min_char_or_byte2 + 1;
  796. int N = (byte1 - f->min_byte1) * D + byte2 - f->min_char_or_byte2;
  797. xcs = f->per_char + N;
  798. }
  799. else
  800. xcs = &f->max_bounds;
  801. }
  802. else
  803. {
  804. if (ch < f->min_char_or_byte2 || ch > f->max_char_or_byte2)
  805. return false;
  806. if (f->per_char)
  807. xcs = f->per_char + (ch - f->min_char_or_byte2);
  808. else
  809. xcs = &f->max_bounds;
  810. }
  811. if (xcs->lbearing == 0 && xcs->rbearing == 0 && xcs->width == 0
  812. && xcs->ascent == 0 && xcs->descent == 0)
  813. return false;
  814. if (!prop || prop->width == rxvt_fontprop::unset)
  815. return true;
  816. // check whether character overlaps previous/next character
  817. int w = xcs->rbearing - xcs->lbearing;
  818. int wcw = max (WCWIDTH (unicode), 1);
  819. careful = xcs->lbearing < 0 || xcs->rbearing > prop->width * wcw;
  820. if (careful && !OVERLAP_OK (w, wcw, prop))
  821. return false;
  822. return true;
  823. }
  824. void
  825. rxvt_font_x11::draw (rxvt_drawable &d, int x, int y,
  826. const text_t *text, int len,
  827. int fg, int bg)
  828. {
  829. // this looks like a mess /.
  830. // and it is a mess /.
  831. // yet we are trying to be perfect /.
  832. // but the result still isn't perfect /.
  833. dTermDisplay;
  834. dTermGC;
  835. bool slow = this->slow
  836. || width != term->fwidth
  837. || height != term->fheight;
  838. int base = ascent; // sorry, incorrect: term->fbase;
  839. XGCValues v;
  840. v.foreground = term->pix_colors[fg];
  841. v.font = f->fid;
  842. if (enc2b)
  843. {
  844. const XChar2b *xc = enc_xchar2b (text, len, cs, slow);
  845. if (bg == Color_bg && !slow)
  846. {
  847. v.background = term->pix_colors[bg];
  848. XChangeGC (disp, gc, GCForeground | GCBackground | GCFont, &v);
  849. XDrawImageString16 (disp, d, gc, x, y + base, xc, len);
  850. }
  851. else
  852. {
  853. clear_rect (d, x, y, term->fwidth * len, term->fheight, bg);
  854. XChangeGC (disp, gc, GCForeground | GCFont, &v);
  855. if (slow)
  856. {
  857. do
  858. {
  859. if (xc->byte1 || xc->byte2)
  860. XDrawString16 (disp, d, gc, x, y + base, xc, 1);
  861. x += term->fwidth;
  862. xc++; len--;
  863. }
  864. while (len);
  865. }
  866. else
  867. XDrawString16 (disp, d, gc, x, y + base, xc, len);
  868. }
  869. }
  870. else
  871. {
  872. const char *xc = enc_char (text, len, cs, slow);
  873. if (bg == Color_bg && !slow)
  874. {
  875. v.background = term->pix_colors[bg];
  876. XChangeGC (disp, gc, GCForeground | GCBackground | GCFont, &v);
  877. XDrawImageString (disp, d, gc, x, y + base, xc, len);
  878. }
  879. else
  880. {
  881. clear_rect (d, x, y, term->fwidth * len, term->fheight, bg);
  882. XChangeGC (disp, gc, GCForeground | GCFont, &v);
  883. if (slow)
  884. {
  885. do
  886. {
  887. if (*xc)
  888. XDrawString (disp, d, gc, x, y + base, xc, 1);
  889. x += term->fwidth;
  890. xc++; len--;
  891. }
  892. while (len);
  893. }
  894. else
  895. XDrawString (disp, d, gc, x, y + base, xc, len);
  896. }
  897. }
  898. }
  899. /////////////////////////////////////////////////////////////////////////////
  900. #if XFT
  901. struct rxvt_font_xft : rxvt_font {
  902. rxvt_font_xft () { f = 0; }
  903. void clear ();
  904. rxvt_fontprop properties ();
  905. bool load (const rxvt_fontprop &prop, bool force_prop);
  906. void draw (rxvt_drawable &d, int x, int y,
  907. const text_t *text, int len,
  908. int fg, int bg);
  909. bool has_char (unicode_t unicode, const rxvt_fontprop *prop, bool &careful) const;
  910. protected:
  911. XftFont *f;
  912. };
  913. void
  914. rxvt_font_xft::clear ()
  915. {
  916. if (f)
  917. {
  918. XftFontClose (term->dpy, f);
  919. f = 0;
  920. }
  921. }
  922. rxvt_fontprop
  923. rxvt_font_xft::properties ()
  924. {
  925. rxvt_fontprop p;
  926. FT_Face face = XftLockFace (f);
  927. p.width = width;
  928. p.height = height;
  929. p.ascent = ascent;
  930. p.weight = face->style_flags & FT_STYLE_FLAG_BOLD
  931. ? rxvt_fontprop::bold : rxvt_fontprop::medium;
  932. p.slant = face->style_flags & FT_STYLE_FLAG_ITALIC
  933. ? rxvt_fontprop::italic : rxvt_fontprop::roman;
  934. XftUnlockFace (f);
  935. return p;
  936. }
  937. bool
  938. rxvt_font_xft::load (const rxvt_fontprop &prop, bool force_prop)
  939. {
  940. dTermDisplay;
  941. clear ();
  942. FcPattern *p = FcNameParse ((FcChar8 *) name);
  943. if (!p)
  944. return false;
  945. FcValue v;
  946. if (prop.height != rxvt_fontprop::unset
  947. && (FcPatternGet (p, FC_PIXEL_SIZE, 0, &v) != FcResultMatch
  948. && FcPatternGet (p, FC_SIZE, 0, &v) != FcResultMatch))
  949. FcPatternAddInteger (p, FC_PIXEL_SIZE, prop.height);
  950. if (prop.weight != rxvt_fontprop::unset
  951. && (force_prop || FcPatternGet (p, FC_WEIGHT, 0, &v) != FcResultMatch))
  952. FcPatternAddInteger (p, FC_WEIGHT, prop.weight);
  953. if (prop.slant != rxvt_fontprop::unset
  954. && (force_prop || FcPatternGet (p, FC_SLANT, 0, &v) != FcResultMatch))
  955. FcPatternAddInteger (p, FC_SLANT, prop.slant);
  956. #if 0 // clipping unfortunately destroys our precious double-width-characters
  957. // clip width, we can't do better, or can we?
  958. if (FcPatternGet (p, FC_CHAR_WIDTH, 0, &v) != FcResultMatch)
  959. FcPatternAddInteger (p, FC_CHAR_WIDTH, prop.width);
  960. #endif
  961. if (FcPatternGet (p, FC_MINSPACE, 0, &v) != FcResultMatch)
  962. FcPatternAddBool (p, FC_MINSPACE, 1);
  963. // store generated name so iso14755 view gives better results
  964. set_name ((char *)FcNameUnparse (p));
  965. XftResult result;
  966. FcPattern *match = XftFontMatch (disp, term->display->screen, p, &result);
  967. FcPatternDestroy (p);
  968. if (!match)
  969. return false;
  970. int ftheight = 0;
  971. bool success = true;
  972. for (;;)
  973. {
  974. p = FcPatternDuplicate (match);
  975. f = XftFontOpenPattern (disp, p);
  976. if (!f)
  977. {
  978. FcPatternDestroy (p);
  979. success = false;
  980. break;
  981. }
  982. FT_Face face = XftLockFace (f);
  983. ascent = (face->size->metrics.ascender + 63) >> 6;
  984. descent = (-face->size->metrics.descender + 63) >> 6;
  985. height = max (ascent + descent, (face->size->metrics.height + 63) >> 6);
  986. width = 0;
  987. bool scalable = face->face_flags & FT_FACE_FLAG_SCALABLE;
  988. XftUnlockFace (f);
  989. int glheight = height;
  990. for (uint16_t *t = extent_test_chars; t < extent_test_chars + ecb_array_length (extent_test_chars); t++)
  991. {
  992. FcChar16 ch = *t;
  993. if (cs != CS_UNICODE
  994. && ch > 0x100
  995. && FROM_UNICODE (cs, ch) == NOCHAR)
  996. continue;
  997. // ignore characters we wouldn't use anyways
  998. bool careful;
  999. if (!has_char (*t, &prop, careful))
  1000. continue;
  1001. XGlyphInfo g;
  1002. XftTextExtents16 (disp, f, &ch, 1, &g);
  1003. g.width -= g.x;
  1004. int wcw = WCWIDTH (ch);
  1005. if (wcw > 0) g.width = (g.width + wcw - 1) / wcw;
  1006. if (width < g.width ) width = g.width;
  1007. if (height < g.height ) height = g.height;
  1008. if (glheight < g.height - g.y) glheight = g.height - g.y;
  1009. }
  1010. if (!width)
  1011. {
  1012. rxvt_warn ("unable to calculate font width for '%s', ignoring.\n", name);
  1013. XftFontClose (disp, f);
  1014. f = 0;
  1015. success = false;
  1016. break;
  1017. }
  1018. if (prop.height == rxvt_fontprop::unset
  1019. || (height <= prop.height && glheight <= prop.height)
  1020. || height <= 2
  1021. || !scalable)
  1022. break;
  1023. if (ftheight)
  1024. {
  1025. // take smaller steps near the end
  1026. if (height > prop.height + 1) ftheight++;
  1027. if (height > prop.height + 2) ftheight++;
  1028. if (height > prop.height + 3) ftheight++;
  1029. ftheight -= height - prop.height;
  1030. }
  1031. else
  1032. ftheight = prop.height - 1;
  1033. XftFontClose (disp, f);
  1034. FcPatternDel (match, FC_PIXEL_SIZE);
  1035. FcPatternAddInteger (match, FC_PIXEL_SIZE, ftheight);
  1036. }
  1037. FcPatternDestroy (match);
  1038. #if 0 // do it per-character
  1039. if (prop.width != rxvt_fontprop::unset && width > prop.width)
  1040. {
  1041. clear ();
  1042. success = false;
  1043. }
  1044. #endif
  1045. return success;
  1046. }
  1047. bool
  1048. rxvt_font_xft::has_char (unicode_t unicode, const rxvt_fontprop *prop, bool &careful) const
  1049. {
  1050. careful = false;
  1051. if (!XftCharExists (term->dpy, f, unicode))
  1052. return false;
  1053. if (!prop || prop->width == rxvt_fontprop::unset)
  1054. return true;
  1055. // check character against base font bounding box
  1056. FcChar32 ch = unicode;
  1057. XGlyphInfo g;
  1058. XftTextExtents32 (term->dpy, f, &ch, 1, &g);
  1059. int w = g.width - g.x;
  1060. int wcw = max (WCWIDTH (unicode), 1);
  1061. careful = g.x > 0 || w > prop->width * wcw;
  1062. if (careful && !OVERLAP_OK (w, wcw, prop))
  1063. return false;
  1064. // this weeds out _totally_ broken fonts, or glyphs
  1065. if (!OVERLAP_OK (g.xOff, wcw, prop))
  1066. return false;
  1067. return true;
  1068. }
  1069. void
  1070. rxvt_font_xft::draw (rxvt_drawable &d, int x, int y,
  1071. const text_t *text, int len,
  1072. int fg, int bg)
  1073. {
  1074. XGlyphInfo extents;
  1075. XftGlyphSpec *enc = rxvt_temp_buf<XftGlyphSpec> (len);
  1076. XftGlyphSpec *ep = enc;
  1077. dTermDisplay;
  1078. dTermGC;
  1079. int w = term->fwidth * len;
  1080. int h = term->fheight;
  1081. bool buffered = bg >= Color_transparent
  1082. && term->option (Opt_buffered);
  1083. // cut trailing spaces
  1084. while (len && text [len - 1] == ' ')
  1085. len--;
  1086. int x_ = buffered ? 0 : x;
  1087. int y_ = buffered ? 0 : y;
  1088. while (len)
  1089. {
  1090. int cwidth = term->fwidth;
  1091. FcChar32 fc = *text++; len--;
  1092. while (len && *text == NOCHAR)
  1093. text++, len--, cwidth += term->fwidth;
  1094. if (fc != ' ') // skip spaces
  1095. {
  1096. FT_UInt glyph = XftCharIndex (disp, f, fc);
  1097. XftGlyphExtents (disp, f, &glyph, 1, &extents);
  1098. ep->glyph = glyph;
  1099. ep->x = x_ + (cwidth - extents.xOff >> 1);
  1100. ep->y = y_ + ascent;
  1101. if (extents.xOff == 0)
  1102. ep->x = x_ + cwidth;
  1103. ep++;
  1104. }
  1105. x_ += cwidth;
  1106. }
  1107. if (buffered)
  1108. {
  1109. if (ep != enc)
  1110. {
  1111. rxvt_drawable &d2 = d.screen->scratch_drawable (w, h);
  1112. #ifdef HAVE_BG_PIXMAP
  1113. Picture dst = 0; // the only assignment is done conditionally in the following if condition
  1114. if (term->bg_pixmap
  1115. && (bg == Color_transparent || bg == Color_bg
  1116. || (bg >= 0 && !term->pix_colors[bg].is_opaque () && ((dst = XftDrawPicture (d2))))))
  1117. {
  1118. int src_x = x, src_y = y;
  1119. if (term->bg_flags & rxvt_term::BG_IS_TRANSPARENT)
  1120. {
  1121. src_x += term->window_vt_x;
  1122. src_y += term->window_vt_y;
  1123. }
  1124. if (term->bg_pmap_width >= src_x + w
  1125. && term->bg_pmap_height >= src_y + h)
  1126. {
  1127. XCopyArea (disp, term->bg_pixmap, d2, gc,
  1128. src_x, src_y, w, h, 0, 0);
  1129. }
  1130. else
  1131. {
  1132. XGCValues gcv;
  1133. gcv.fill_style = FillTiled;
  1134. gcv.tile = term->bg_pixmap;
  1135. gcv.ts_x_origin = -src_x;
  1136. gcv.ts_y_origin = -src_y;
  1137. XChangeGC (disp, gc,
  1138. GCTile | GCTileStipXOrigin | GCTileStipYOrigin | GCFillStyle,
  1139. &gcv);
  1140. XFillRectangle (disp, d2, gc, 0, 0, w, h);
  1141. gcv.fill_style = FillSolid;
  1142. XChangeGC (disp, gc, GCFillStyle, &gcv);
  1143. }
  1144. if (dst)
  1145. {
  1146. Picture solid_color_pict = XftDrawSrcPicture (d2, &term->pix_colors[bg].c);
  1147. // dst can only be set when bg >= 0
  1148. XRenderComposite (disp, PictOpOver, solid_color_pict, None, dst, 0, 0, 0, 0, 0, 0, w, h);
  1149. }
  1150. }
  1151. else
  1152. #endif
  1153. XftDrawRect (d2, &term->pix_colors[bg >= 0 ? bg : Color_bg].c, 0, 0, w, h);
  1154. XftDrawGlyphSpec (d2, &term->pix_colors[fg].c, f, enc, ep - enc);
  1155. XCopyArea (disp, d2, d, gc, 0, 0, w, h, x, y);
  1156. }
  1157. else
  1158. clear_rect (d, x, y, w, h, bg);
  1159. }
  1160. else
  1161. {
  1162. clear_rect (d, x, y, w, h, bg);
  1163. XftDrawGlyphSpec (d, &term->pix_colors[fg].c, f, enc, ep - enc);
  1164. }
  1165. }
  1166. #endif
  1167. /////////////////////////////////////////////////////////////////////////////
  1168. rxvt_fontset::rxvt_fontset (rxvt_term *term)
  1169. : fontdesc (0), term (term)
  1170. {
  1171. clear ();
  1172. }
  1173. rxvt_fontset::~rxvt_fontset ()
  1174. {
  1175. clear ();
  1176. }
  1177. void
  1178. rxvt_fontset::clear ()
  1179. {
  1180. prop.width = prop.height = prop.ascent = prop.weight = prop.slant
  1181. = rxvt_fontprop::unset;
  1182. force_prop = false;
  1183. for (rxvt_font **i = fonts.begin (); i != fonts.end (); i++)
  1184. (*i)->unref ();
  1185. for (pagemap **p = fmap.begin (); p != fmap.end (); p++)
  1186. delete *p;
  1187. free (fontdesc); fontdesc = 0;
  1188. fonts.clear ();
  1189. fallback = fallback_fonts;
  1190. }
  1191. void
  1192. rxvt_fontset::prepare_font (rxvt_font *font, codeset cs)
  1193. {
  1194. font->set_term (term);
  1195. font->cs = cs;
  1196. font->loaded = false;
  1197. }
  1198. rxvt_font *
  1199. rxvt_fontset::new_font (const char *name, codeset cs)
  1200. {
  1201. rxvt_font *f;
  1202. if (!name || !*name)
  1203. {
  1204. name = "";
  1205. f = new rxvt_font_default (this);
  1206. }
  1207. #if XFT
  1208. else if (!strncmp (name, "xft:", 4))
  1209. {
  1210. name += 4;
  1211. f = new rxvt_font_xft ();
  1212. }
  1213. #endif
  1214. else if (!strncmp (name, "x:", 2))
  1215. {
  1216. name += 2;
  1217. f = new rxvt_font_x11;
  1218. }
  1219. else
  1220. f = new rxvt_font_x11;
  1221. f->set_name (strdup (name));
  1222. prepare_font (f, cs);
  1223. return f;
  1224. }
  1225. /////////////////////////////////////////////////////////////////////////////
  1226. void
  1227. rxvt_fontset::push_font (rxvt_font *font)
  1228. {
  1229. // the fontCount index is reserved for the overflow font, it is only
  1230. // necessary when we get fontCount or more fonts, as they cannot be
  1231. // represented in the rendition.
  1232. if (fonts.size () == fontCount)
  1233. {
  1234. rxvt_font *f = new rxvt_font_overflow (this);
  1235. prepare_font (f, CS_UNICODE);
  1236. fonts.push_back (f);
  1237. }
  1238. fonts.push_back (font);
  1239. }
  1240. void
  1241. rxvt_fontset::add_fonts (const char *desc)
  1242. {
  1243. if (desc)
  1244. {
  1245. char buf[512];
  1246. const char *end;
  1247. do
  1248. {
  1249. while (*desc && *desc <= ' ')
  1250. desc++;
  1251. codeset cs = CS_UNICODE;
  1252. if (*desc == '[')
  1253. {
  1254. char spec[256];
  1255. const char *extra = ++desc; // not yet used
  1256. desc = strchr (desc, ']');
  1257. if (!desc)
  1258. {
  1259. rxvt_warn ("ERROR: opening '[' without closing ']' in font specification, trying to continue.\n");
  1260. break;
  1261. }
  1262. memcpy (spec, extra, min (desc - extra, 255));
  1263. spec[min (desc - extra, 255)] = 0;
  1264. if (!strncmp (extra, "codeset=", sizeof ("codeset=") - 1))
  1265. cs = codeset_from_name (spec + sizeof ("codeset=") - 1);
  1266. else
  1267. rxvt_warn ("unknown parameter '%s' in font specification, skipping.\n", spec);
  1268. desc++;
  1269. while (*desc <= ' ') desc++;
  1270. }
  1271. end = strchr (desc, ',');
  1272. if (!end)
  1273. end = desc + strlen (desc);
  1274. if (end - desc < 511)
  1275. {
  1276. memcpy (buf, desc, end - desc);
  1277. buf[end - desc] = 0;
  1278. push_font (new_font (buf, cs));
  1279. }
  1280. else
  1281. rxvt_warn ("fontset element too long (>511 bytes), ignored.\n");
  1282. desc = end + 1;
  1283. }
  1284. while (*end);
  1285. }
  1286. }
  1287. bool
  1288. rxvt_fontset::realize_font (int i)
  1289. {
  1290. if (i < 0 || i >= fonts.size ())
  1291. return false;
  1292. if (fonts[i]->loaded)
  1293. return true;
  1294. fonts[i]->loaded = true;
  1295. if (!fonts[i]->load (prop, force_prop))
  1296. {
  1297. fonts[i]->cs = CS_UNKNOWN;
  1298. return false;
  1299. }
  1300. return true;
  1301. }
  1302. bool
  1303. rxvt_fontset::populate (const char *desc)
  1304. {
  1305. clear ();
  1306. fontdesc = strdup (desc);
  1307. push_font (new_font (0, CS_UNICODE));
  1308. realize_font (0);
  1309. add_fonts (desc);
  1310. return true;
  1311. }
  1312. int
  1313. rxvt_fontset::find_font (const char *name) const
  1314. {
  1315. for (rxvt_font *const *f = fonts.begin (); f < fonts.end (); f++)
  1316. if ((*f)->name && !strcmp ((*f)->name, name))
  1317. return f - fonts.begin ();
  1318. return -1;
  1319. }
  1320. int
  1321. rxvt_fontset::find_font_idx (unicode_t unicode)
  1322. {
  1323. if (unicode >= 1<<20)
  1324. return 0;
  1325. unicode_t hi = unicode >> 8;
  1326. if (hi < fmap.size ()
  1327. && fmap[hi]
  1328. && (*fmap[hi])[unicode & 0xff] != 0xff)
  1329. return (*fmap[hi])[unicode & 0xff];
  1330. unsigned int i;
  1331. for (i = 0; i < fonts.size (); i++)
  1332. {
  1333. rxvt_font *f = fonts[i];
  1334. if (!f->loaded)
  1335. {
  1336. if (FROM_UNICODE (f->cs, unicode) == NOCHAR)
  1337. goto next_font;
  1338. if (!realize_font (i))
  1339. goto next_font;
  1340. if (prop.ascent != rxvt_fontprop::unset)
  1341. max_it (f->ascent, prop.ascent);
  1342. }
  1343. if (f->cs == CS_UNKNOWN)
  1344. goto next_font;
  1345. bool careful;
  1346. if (f->has_char (unicode, &prop, careful))
  1347. {
  1348. i = (i << 1) | careful;
  1349. goto found;
  1350. }
  1351. next_font:
  1352. if (i == fonts.size () - 1)
  1353. {
  1354. if (fallback->name)
  1355. {
  1356. // search through the fallback list
  1357. push_font (new_font (fallback->name, fallback->cs));
  1358. fallback++;
  1359. }
  1360. else
  1361. {
  1362. // try to find a new font.
  1363. // only xft currently supported, as there is no
  1364. // way to configure this and xft is easier to hack in,
  1365. // while x11 has more framework in place already.
  1366. // TODO: this is a real resource hog, xft takes ages(?)
  1367. #if XFT && USE_SLOW_LOOKUP
  1368. // grab the first xft font that seems suitable
  1369. FcPattern *p = FcPatternCreate ();
  1370. FcCharSet *s = FcCharSetCreate ();
  1371. FcCharSetAddChar (s, unicode);
  1372. FcPatternAddCharSet (p, FC_CHARSET, s);
  1373. // charsets don't help that much, as xft might return
  1374. // a non-matching font even if a better font is available :/
  1375. x x x x TODO prop might have unset contents
  1376. FcPatternAddInteger (p, FC_PIXEL_SIZE, prop.height);
  1377. FcPatternAddInteger (p, FC_WEIGHT, prop.weight);
  1378. FcPatternAddInteger (p, FC_SLANT, prop.slant);
  1379. FcPatternAddBool (p, FC_MINSPACE, 1);
  1380. //FcPatternAddBool (p, FC_ANTIALIAS, 1);
  1381. XftResult result;
  1382. FcPattern *match = XftFontMatch (term->dpy, term->display->screen, p, &result);
  1383. FcPatternDestroy (p);
  1384. if (match)
  1385. {
  1386. FcPatternDel (match, FC_CHARSET);
  1387. char *font = (char *)FcNameUnparse (match);
  1388. FcPatternDestroy (match);
  1389. if (find_font (font) < 0)
  1390. {
  1391. char fontname[4096];
  1392. snprintf (fontname, sizeof (fontname), "xft:%s", font);
  1393. push_font (new_font (fontname, CS_UNICODE));
  1394. }
  1395. free (font);
  1396. }
  1397. #endif
  1398. }
  1399. }
  1400. }
  1401. /* we must return SOME font */
  1402. i = 0;
  1403. found:
  1404. // found a font, cache it
  1405. if (i < 255)
  1406. {
  1407. while (hi >= fmap.size ())
  1408. fmap.push_back (0);
  1409. if (!fmap[hi])
  1410. {
  1411. fmap[hi] = (pagemap *)new pagemap;
  1412. memset (fmap[hi], 0xff, sizeof (pagemap));
  1413. }
  1414. (*fmap[hi])[unicode & 0xff] = i;
  1415. }
  1416. return i;
  1417. }