laytext.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #include <stdlib.h>
  2. #include "laytext.h"
  3. #include "dynar.h"
  4. #include "utf8.h"
  5. /** Text layout functions that work with UTF-8.
  6. These functions don't actually draw anything but calculate
  7. layout parameters for text based on the incoming text, parameters and
  8. callbacks.
  9. */
  10. /*
  11. Make callback compatible with
  12. void al_get_ustr_dimensions(const ALLEGRO_FONT *f,
  13. ALLEGRO_USTR const *ustr,
  14. int *bbx, int *bby, int *bbw, int *bbh)
  15. or
  16. int al_get_ustr_width(const ALLEGRO_FONT *f, ALLEGRO_USTR const *ustr);
  17. */
  18. /* Finds the position of the first candidate line break in the 今日は
  19. utf8-encoded text str. Returns -1 if no candidate could be found.
  20. Returns -2 if the string is empty.
  21. */
  22. int
  23. laytext_find_first_break(char * str, float max_width, laytext_callback * callback, void * extra) {
  24. int length = 0;
  25. int total_length = 0;
  26. long character;
  27. float width, delta_width;
  28. float height;
  29. int candidate = -1;
  30. char * index = str;
  31. width = 0.0;
  32. while (index) {
  33. callback(index, total_length, extra, &delta_width, &height);
  34. width = delta_width;
  35. if((width - max_width) > 0.5) {
  36. if (candidate == -1) /* No break candidate, break before this character in stead. */ {
  37. return index - str - 1;
  38. } else { /* break at candidate. */
  39. return candidate;
  40. }
  41. }
  42. if ((*index) == ' ') {
  43. candidate = index - str;
  44. }
  45. /* If a newline the break is here. */
  46. if((*index) == '\n') {
  47. return index - str;
  48. }
  49. length = utf8_next(index, &index, &character);
  50. total_length += length;
  51. }
  52. /* If we get here the strin is short, no break needed. Negative indicates
  53. * this. */
  54. return -1;
  55. }
  56. /* Returns a newly allocated dynamic array filled with long integer indexes of
  57. * the byte positions where the string should be split to make it fit the
  58. * given width. It must be freed with dynar_free(). */
  59. Dynar * laytext_layout(char * str, float max_width, laytext_callback * callback, void * extra) {
  60. Dynar * result = dynar_new_long();
  61. int count = 0; /* Amount of lines. */
  62. int index = 0;
  63. int step = 0;
  64. int last = 0;
  65. int length = 0;
  66. int candidate =-1; /* Candidate break position. */
  67. length = strlen(str);
  68. while(index < length) {
  69. candidate = laytext_find_first_break(str + index, max_width, callback, extra);
  70. if (candidate < 0) return result;
  71. dynar_append_long(result, index + candidate);
  72. index += candidate + 1;
  73. }
  74. return result;
  75. }
  76. #ifdef COMMENT_
  77. /* Fills the array breaks of size size with up to size break positions, long integer indexes of
  78. * the byte positions where the string should be split to make it fit the
  79. * given width. Returns the amount of indexes stored. Will give up if
  80. * the space in the array isn't enough.
  81. */
  82. int laytext_layout_array(long * results, size_t result_size, size_t * result_amount,
  83. char * str, float max_width, laytext_callback * callback,
  84. void * extra) {
  85. int count = 0; /* Amount of lines. */
  86. int index = 0;
  87. int step = 0;
  88. int last = 0;
  89. int length = 0;
  90. int candidate =-1; /* Candidate break position. */
  91. length = strlen(str);
  92. while(index < length) {
  93. candidate = laytext_find_first_break(str + index, max_width, callback, extra);
  94. if (candidate < 0) return result;
  95. dynar_append_long(result, index + candidate);
  96. index += candidate + 1;
  97. }
  98. return result;
  99. }
  100. #endif