Text.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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_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. }
  88. /*
  89. \brief Get text bounding box
  90. \param str string
  91. \param[out] t,b,l,r top, bottom, left, right corner
  92. */
  93. void Cairo_text_box(const char *str, double *t, double *b, double *l, double *r)
  94. {
  95. char *utf8 = convert(str);
  96. cairo_text_extents_t ext;
  97. if (!utf8)
  98. return;
  99. set_matrix();
  100. cairo_text_extents(cairo, utf8, &ext);
  101. G_free(utf8);
  102. *l = cur_x + ext.x_bearing;
  103. *r = cur_x + ext.x_bearing + ext.width;
  104. *t = cur_y + ext.y_bearing;
  105. *b = cur_y + ext.y_bearing + ext.height;
  106. }
  107. static void set_font_toy(const char *name)
  108. {
  109. char *font = G_store(name);
  110. cairo_font_weight_t weight = CAIRO_FONT_WEIGHT_NORMAL;
  111. cairo_font_slant_t slant = CAIRO_FONT_SLANT_NORMAL;
  112. for (;;) {
  113. char *p = strrchr(font, '-');
  114. if (!p)
  115. break;
  116. if (G_strcasecmp(p, "-bold") == 0)
  117. weight = CAIRO_FONT_WEIGHT_BOLD;
  118. else if (strcasecmp(p, "-italic") == 0)
  119. slant = CAIRO_FONT_SLANT_ITALIC;
  120. else if (G_strcasecmp(p, "-oblique") == 0)
  121. slant = CAIRO_FONT_SLANT_OBLIQUE;
  122. else
  123. break;
  124. *p = '\0';
  125. }
  126. cairo_select_font_face(cairo, font, slant, weight);
  127. G_free(font);
  128. }
  129. #if CAIRO_HAS_FT_FONT
  130. static void set_font_fc(const char *name)
  131. {
  132. static cairo_font_face_t *face;
  133. static int initialized;
  134. FcPattern *pattern;
  135. FcResult result;
  136. if (!initialized) {
  137. FcInit();
  138. initialized = 1;
  139. }
  140. if (face) {
  141. cairo_font_face_destroy(face);
  142. face = NULL;
  143. }
  144. pattern = FcNameParse(name);
  145. FcDefaultSubstitute(pattern);
  146. FcConfigSubstitute(FcConfigGetCurrent(), pattern, FcMatchPattern);
  147. pattern = FcFontMatch(FcConfigGetCurrent(), pattern, &result);
  148. face = cairo_ft_font_face_create_for_pattern(pattern);
  149. cairo_set_font_face(cairo, face);
  150. }
  151. #endif
  152. static const char *toy_fonts[12] = {
  153. "sans",
  154. "sans-italic",
  155. "sans-bold",
  156. "sans-bold-italic",
  157. "serif",
  158. "serif-italic",
  159. "serif-bold",
  160. "serif-bold-italic",
  161. "mono",
  162. "mono-italic",
  163. "mono-bold",
  164. "mono-bold-italic",
  165. };
  166. static const int num_toy_fonts = 12;
  167. static int is_toy_font(const char *name)
  168. {
  169. int i;
  170. for (i = 0; i < num_toy_fonts; i++)
  171. if (G_strcasecmp(name, toy_fonts[i]) == 0)
  172. return 1;
  173. return 0;
  174. }
  175. /*!
  176. \brief Set font
  177. \param name font name
  178. */
  179. void Cairo_set_font(const char *name)
  180. {
  181. #if CAIRO_HAS_FT_FONT
  182. if (is_toy_font(name))
  183. set_font_toy(name);
  184. else
  185. set_font_fc(name);
  186. #else
  187. set_font_toy(name);
  188. #endif
  189. }
  190. static void font_list_toy(char ***list, int *count, int verbose)
  191. {
  192. char **fonts = *list;
  193. int num_fonts = *count;
  194. int i;
  195. fonts = G_realloc(fonts, (num_fonts + num_toy_fonts) * sizeof(char *));
  196. for (i = 0; i < num_toy_fonts; i++) {
  197. char buf[256];
  198. sprintf(buf, "%s%s",
  199. toy_fonts[i],
  200. verbose ? "||1||0|utf-8|" : "");
  201. fonts[num_fonts++] = G_store(buf);
  202. }
  203. *list = fonts;
  204. *count = num_fonts;
  205. }
  206. /*!
  207. \brief Get list of fonts
  208. \param[out] list font list
  209. \param[out] number of items in the list
  210. */
  211. void Cairo_font_list(char ***list, int *count)
  212. {
  213. font_list(list, count, 0);
  214. font_list_toy(list, count, 0);
  215. }
  216. /*!
  217. \brief Get fonts into
  218. \param[out] list font list
  219. \param[out] number of items in the list
  220. */
  221. void Cairo_font_info(char ***list, int *count)
  222. {
  223. font_list(list, count, 1);
  224. font_list_toy(list, count, 1);
  225. }