pdf-layout.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. // Copyright (C) 2004-2021 Artifex Software, Inc.
  2. //
  3. // This file is part of MuPDF.
  4. //
  5. // MuPDF is free software: you can redistribute it and/or modify it under the
  6. // terms of the GNU Affero General Public License as published by the Free
  7. // Software Foundation, either version 3 of the License, or (at your option)
  8. // any later version.
  9. //
  10. // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
  11. // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12. // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. // details.
  14. //
  15. // You should have received a copy of the GNU Affero General Public License
  16. // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
  17. //
  18. // Alternative licensing terms are available from the licensor.
  19. // For commercial licensing, see <https://www.artifex.com/> or contact
  20. // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
  21. // CA 94129, USA, for further information.
  22. #include "mupdf/fitz.h"
  23. #include "mupdf/pdf.h"
  24. #include <float.h>
  25. #include <math.h>
  26. #define LINE_LIMIT (100)
  27. #define LINE_HEIGHT (1.2f)
  28. struct line { const char *a, *b; };
  29. struct font_info
  30. {
  31. fz_context *ctx;
  32. fz_font *font;
  33. float fontsize;
  34. };
  35. static float measure_character(struct font_info *info, int c)
  36. {
  37. fz_font *font;
  38. int gid = fz_encode_character_with_fallback(info->ctx, info->font, c, 0, 0, &font);
  39. return fz_advance_glyph(info->ctx, font, gid, 0) * info->fontsize;
  40. }
  41. static int break_lines(struct font_info *info, const char *a, struct line *lines, int maxlines, float width, float *maxwidth)
  42. {
  43. const char *next, *space = NULL, *b = a;
  44. int c, n = 0;
  45. float space_x, x = 0, w = 0;
  46. if (maxwidth)
  47. *maxwidth = 0;
  48. while (*b)
  49. {
  50. next = b + fz_chartorune(&c, b);
  51. if (c == '\r' || c == '\n')
  52. {
  53. if (lines && n < maxlines)
  54. {
  55. lines[n].a = a;
  56. lines[n].b = b;
  57. }
  58. ++n;
  59. if (maxwidth && *maxwidth < x)
  60. *maxwidth = x;
  61. a = next;
  62. x = 0;
  63. space = NULL;
  64. }
  65. else
  66. {
  67. if (c == ' ')
  68. {
  69. space = b;
  70. space_x = x;
  71. }
  72. w = measure_character(info, c);
  73. if (x + w > width)
  74. {
  75. if (space)
  76. {
  77. if (lines && n < maxlines)
  78. {
  79. lines[n].a = a;
  80. lines[n].b = space;
  81. }
  82. ++n;
  83. if (maxwidth && *maxwidth < space_x)
  84. *maxwidth = space_x;
  85. a = next = space + 1;
  86. x = 0;
  87. space = NULL;
  88. }
  89. else
  90. {
  91. if (lines && n < maxlines)
  92. {
  93. lines[n].a = a;
  94. lines[n].b = b;
  95. }
  96. ++n;
  97. if (maxwidth && *maxwidth < x)
  98. *maxwidth = x;
  99. a = b;
  100. x = w;
  101. space = NULL;
  102. }
  103. }
  104. else
  105. {
  106. x += w;
  107. }
  108. }
  109. b = next;
  110. }
  111. if (lines && n < maxlines)
  112. {
  113. lines[n].a = a;
  114. lines[n].b = b;
  115. }
  116. ++n;
  117. if (maxwidth && *maxwidth < x)
  118. *maxwidth = x;
  119. return n < maxlines ? n : maxlines;
  120. }
  121. static fz_matrix show_string(fz_context *ctx, fz_text *text, fz_font *user_font, fz_matrix trm, const char *s, int len,
  122. int wmode, int bidi_level, fz_bidi_direction markup_dir, fz_text_language language)
  123. {
  124. fz_font *font;
  125. int gid, ucs;
  126. float adv;
  127. int i = 0;
  128. while (i < len)
  129. {
  130. i += fz_chartorune(&ucs, s + i);
  131. gid = fz_encode_character_with_fallback(ctx, user_font, ucs, 0, language, &font);
  132. fz_show_glyph(ctx, text, font, trm, gid, ucs, wmode, bidi_level, markup_dir, language);
  133. adv = fz_advance_glyph(ctx, font, gid, wmode);
  134. if (wmode == 0)
  135. trm = fz_pre_translate(trm, adv, 0);
  136. else
  137. trm = fz_pre_translate(trm, 0, adv);
  138. }
  139. return trm;
  140. }
  141. fz_text *pdf_layout_fit_text(fz_context *ctx, fz_font *font, fz_text_language lang, const char *str, fz_rect bounds)
  142. {
  143. fz_text *text = NULL;
  144. struct font_info info;
  145. struct line *lines;
  146. float width = bounds.x1 - bounds.x0;
  147. float height = bounds.y1 - bounds.y0;
  148. lines = fz_malloc_array(ctx, LINE_LIMIT, struct line);
  149. fz_var(info);
  150. fz_try(ctx)
  151. {
  152. fz_matrix trm;
  153. int target_line_count;
  154. int line_count, l;
  155. float line_len;
  156. fz_rect tbounds;
  157. float xadj, yadj;
  158. fz_text_span *span;
  159. info.ctx = ctx;
  160. info.font = font;
  161. info.fontsize = 1;
  162. /* Find out how many lines the text requires without any wrapping */
  163. target_line_count = break_lines(&info, str, lines, LINE_LIMIT, FLT_MAX, &line_len);
  164. /* Try increasing line counts, which reduces the font size, until the text fits */
  165. do
  166. {
  167. info.fontsize = height / (target_line_count * LINE_HEIGHT);
  168. line_count = break_lines(&info, str, lines, LINE_LIMIT, width, &line_len);
  169. } while (line_count > target_line_count++);
  170. trm = fz_scale(info.fontsize, -info.fontsize);
  171. trm.e += bounds.x0;
  172. trm.f += bounds.y1;
  173. text = fz_new_text(ctx);
  174. for (l = 0; l < line_count; l++)
  175. {
  176. show_string(ctx, text, font, trm, lines[l].a, lines[l].b - lines[l].a, 0, 0, FZ_BIDI_LTR, lang);
  177. trm = fz_pre_translate(trm, 0.0f, -LINE_HEIGHT);
  178. }
  179. tbounds = fz_bound_text(ctx, text, NULL, fz_identity);
  180. xadj = (bounds.x0 + bounds.x1 - tbounds.x0 - tbounds.x1) / 2.0f;
  181. yadj = (bounds.y0 + bounds.y1 - tbounds.y0 - tbounds.y1) / 2.0f;
  182. for (span = text->head; span; span = span->next)
  183. {
  184. int i;
  185. for (i = 0; i < span->len; i++)
  186. {
  187. span->items[i].x += xadj;
  188. span->items[i].y += yadj;
  189. }
  190. }
  191. }
  192. fz_always(ctx)
  193. {
  194. fz_free(ctx, lines);
  195. }
  196. fz_catch(ctx)
  197. {
  198. fz_drop_text(ctx, text);
  199. fz_rethrow(ctx);
  200. }
  201. return text;
  202. }