text.c 6.5 KB

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