Text.c 5.6 KB

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