text.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. /*!
  2. \file lib/cairodriver/text.c
  3. \brief GRASS cairo display driver - text subroutines
  4. (C) 2007-2008 by Lars Ahlzen and the GRASS Development Team
  5. This program is free software under the GNU General Public License
  6. (>=v2). Read the file COPYING that comes with GRASS for details.
  7. \author Lars Ahlzen <lars ahlzen.com> (original contributor)
  8. \author Glynn Clements
  9. */
  10. #include <grass/glocale.h>
  11. #include "cairodriver.h"
  12. #if CAIRO_HAS_FT_FONT
  13. #include <cairo-ft.h>
  14. #if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1,10,0) || defined(CAIRO_HAS_FC_FONT)
  15. #define USE_FONTCONFIG 1
  16. #include <fontconfig/fontconfig.h>
  17. #else
  18. #define USE_FONTCONFIG 0
  19. #endif
  20. #endif /* CAIRO_HAS_FT_FONT */
  21. #ifdef HAVE_ICONV_H
  22. #include <iconv.h>
  23. #endif
  24. static char *convert(const char *in)
  25. {
  26. size_t ilen, olen;
  27. char *out;
  28. ilen = strlen(in);
  29. olen = 3 * ilen + 1;
  30. out = G_malloc(olen);
  31. #ifdef HAVE_ICONV_H
  32. {
  33. const char *encoding = font_get_encoding();
  34. char *p1 = (char *) in;
  35. char *p2 = out;
  36. size_t ret;
  37. iconv_t cd;
  38. if ((cd = iconv_open("UTF-8", encoding)) == (iconv_t) -1)
  39. G_fatal_error(_("Unable to convert from <%s> to UTF-8"),
  40. encoding);
  41. ret = iconv(cd, &p1, &ilen, &p2, &olen);
  42. iconv_close(cd);
  43. *p2++ = '\0';
  44. if (ret > 0)
  45. G_warning(_("Some characters could not be converted to UTF-8"));
  46. }
  47. #else
  48. {
  49. const unsigned char *p1 = (const unsigned char *) in;
  50. unsigned char *p2 = (unsigned char *) out;
  51. int i, j;
  52. for (i = j = 0; i < ilen; i++) {
  53. int c = p1[i];
  54. if (c < 0x80)
  55. p2[j++] = c;
  56. else {
  57. p2[j++] = 0xC0 + (c >> 6);
  58. p2[j++] = 0x80 + (c & 0x3F);
  59. }
  60. }
  61. p2[j++] = '\0';
  62. }
  63. #endif
  64. return out;
  65. }
  66. static void set_matrix(void)
  67. {
  68. static cairo_matrix_t mat;
  69. if (matrix_valid)
  70. return;
  71. cairo_matrix_init_identity(&mat);
  72. cairo_matrix_scale(&mat, text_size_x, text_size_y);
  73. cairo_matrix_rotate(&mat, -text_rotation * M_PI / 180);
  74. cairo_set_font_matrix(cairo, &mat);
  75. matrix_valid = 1;
  76. }
  77. /*!
  78. \brief Draw text
  79. \param str string to be drawn
  80. */
  81. void Cairo_Text(const char *str)
  82. {
  83. char *utf8 = convert(str);
  84. if (!utf8)
  85. return;
  86. set_matrix();
  87. cairo_move_to(cairo, cur_x, cur_y);
  88. cairo_show_text(cairo, utf8);
  89. G_free(utf8);
  90. ca.modified = 1;
  91. }
  92. /*
  93. \brief Get text bounding box
  94. \param str string
  95. \param[out] t,b,l,r top, bottom, left, right corner
  96. */
  97. void Cairo_text_box(const char *str, double *t, double *b, double *l, double *r)
  98. {
  99. char *utf8 = convert(str);
  100. cairo_text_extents_t ext;
  101. if (!utf8)
  102. return;
  103. set_matrix();
  104. cairo_text_extents(cairo, utf8, &ext);
  105. G_free(utf8);
  106. *l = cur_x + ext.x_bearing;
  107. *r = cur_x + ext.x_bearing + ext.width;
  108. *t = cur_y + ext.y_bearing;
  109. *b = cur_y + ext.y_bearing + ext.height;
  110. }
  111. static void set_font_toy(const char *name)
  112. {
  113. char *font = G_store(name);
  114. cairo_font_weight_t weight = CAIRO_FONT_WEIGHT_NORMAL;
  115. cairo_font_slant_t slant = CAIRO_FONT_SLANT_NORMAL;
  116. for (;;) {
  117. char *p = strrchr(font, '-');
  118. if (!p)
  119. break;
  120. if (G_strcasecmp(p, "-bold") == 0)
  121. weight = CAIRO_FONT_WEIGHT_BOLD;
  122. else if (strcasecmp(p, "-italic") == 0)
  123. slant = CAIRO_FONT_SLANT_ITALIC;
  124. else if (G_strcasecmp(p, "-oblique") == 0)
  125. slant = CAIRO_FONT_SLANT_OBLIQUE;
  126. else
  127. break;
  128. *p = '\0';
  129. }
  130. cairo_select_font_face(cairo, font, slant, weight);
  131. G_free(font);
  132. }
  133. #if USE_FONTCONFIG
  134. static void fc_init(void)
  135. {
  136. static int initialized;
  137. if (!initialized) {
  138. FcInit();
  139. initialized = 1;
  140. }
  141. }
  142. static void set_font_fc(const char *name)
  143. {
  144. static cairo_font_face_t *face;
  145. FcPattern *pattern;
  146. FcResult result;
  147. fc_init();
  148. if (face) {
  149. cairo_font_face_destroy(face);
  150. face = NULL;
  151. }
  152. pattern = FcNameParse((FcChar8 *)name);
  153. FcDefaultSubstitute(pattern);
  154. FcConfigSubstitute(FcConfigGetCurrent(), pattern, FcMatchPattern);
  155. pattern = FcFontMatch(FcConfigGetCurrent(), pattern, &result);
  156. face = cairo_ft_font_face_create_for_pattern(pattern);
  157. cairo_set_font_face(cairo, face);
  158. }
  159. static void font_list_fc(char ***list, int *count, int verbose)
  160. {
  161. FcPattern *pattern;
  162. FcObjectSet *objset;
  163. FcFontSet *fontset;
  164. char **fonts = *list;
  165. int num_fonts = *count;
  166. int i;
  167. fc_init();
  168. pattern = FcPatternCreate();
  169. objset = FcObjectSetBuild(FC_FAMILY, FC_STYLE, (char *) NULL);
  170. fontset = FcFontList(NULL, pattern, objset);
  171. fonts = G_realloc(fonts, (num_fonts + fontset->nfont) * sizeof(char *));
  172. for (i = 0; i < fontset->nfont; i++) {
  173. char buf[1024];
  174. FcPattern *pat = fontset->fonts[i];
  175. FcChar8 *family = (FcChar8 *)"", *style = (FcChar8 *)"";
  176. FcPatternGetString(pat, FC_FAMILY, 0, &family);
  177. FcPatternGetString(pat, FC_STYLE , 0, &style );
  178. if (verbose)
  179. sprintf(buf, "%s:%s|%s:%s|%d|%s|%d|%s|",
  180. family, style, family, style, GFONT_DRIVER, "", 0, "utf-8");
  181. else
  182. sprintf(buf, "%s:%s", family, style);
  183. fonts[num_fonts++] = G_store(buf);
  184. }
  185. FcObjectSetDestroy(objset);
  186. FcPatternDestroy(pattern);
  187. FcFontSetDestroy (fontset);
  188. *list = fonts;
  189. *count = num_fonts;
  190. }
  191. #endif
  192. static const char *toy_fonts[12] = {
  193. "sans",
  194. "sans-italic",
  195. "sans-bold",
  196. "sans-bold-italic",
  197. "serif",
  198. "serif-italic",
  199. "serif-bold",
  200. "serif-bold-italic",
  201. "mono",
  202. "mono-italic",
  203. "mono-bold",
  204. "mono-bold-italic",
  205. };
  206. static const int num_toy_fonts = 12;
  207. static int is_toy_font(const char *name)
  208. {
  209. int i;
  210. for (i = 0; i < num_toy_fonts; i++)
  211. if (G_strcasecmp(name, toy_fonts[i]) == 0)
  212. return 1;
  213. return 0;
  214. }
  215. /*!
  216. \brief Set font
  217. \param name font name
  218. */
  219. void Cairo_set_font(const char *name)
  220. {
  221. #if USE_FONTCONFIG
  222. if (is_toy_font(name))
  223. set_font_toy(name);
  224. else
  225. set_font_fc(name);
  226. #else
  227. set_font_toy(name);
  228. #endif
  229. }
  230. static void font_list_toy(char ***list, int *count, int verbose)
  231. {
  232. char **fonts = *list;
  233. int num_fonts = *count;
  234. int i;
  235. fonts = G_realloc(fonts, (num_fonts + num_toy_fonts) * sizeof(char *));
  236. for (i = 0; i < num_toy_fonts; i++) {
  237. char buf[256];
  238. if (verbose)
  239. sprintf(buf, "%s|%s|%d|%s|%d|%s|",
  240. toy_fonts[i], toy_fonts[i], GFONT_DRIVER, "", 0, "utf-8");
  241. else
  242. strcpy(buf, toy_fonts[i]);
  243. fonts[num_fonts++] = G_store(buf);
  244. }
  245. *list = fonts;
  246. *count = num_fonts;
  247. }
  248. /*!
  249. \brief Get list of fonts
  250. \param[out] list font list
  251. \param[out] count number of items in the list
  252. */
  253. void Cairo_font_list(char ***list, int *count)
  254. {
  255. font_list_toy(list, count, 0);
  256. #if USE_FONTCONFIG
  257. font_list_fc(list, count, 0);
  258. #endif
  259. }
  260. /*!
  261. \brief Get fonts into
  262. \param[out] list font list
  263. \param[out] count number of items in the list
  264. */
  265. void Cairo_font_info(char ***list, int *count)
  266. {
  267. font_list_toy(list, count, 1);
  268. #if USE_FONTCONFIG
  269. font_list_fc(list, count, 1);
  270. #endif
  271. }