Fluid: Removed binary_python from fluid script
[blender.git] / source / blender / blenfont / intern / blf.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2009 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup blf
22  *
23  * Main BlenFont (BLF) API, public functions for font handling.
24  *
25  * Wraps OpenGL and FreeType.
26  */
27
28 #include <math.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <ft2build.h>
34
35 #include FT_FREETYPE_H
36 #include FT_GLYPH_H
37
38 #include "MEM_guardedalloc.h"
39
40 #include "BLI_math.h"
41 #include "BLI_threads.h"
42
43 #include "BLF_api.h"
44
45 #include "IMB_colormanagement.h"
46
47 #include "GPU_matrix.h"
48 #include "GPU_shader.h"
49
50 #include "blf_internal.h"
51 #include "blf_internal_types.h"
52
53 /* Max number of font in memory.
54  * Take care that now every font have a glyph cache per size/dpi,
55  * so we don't need load the same font with different size, just
56  * load one and call BLF_size.
57  */
58 #define BLF_MAX_FONT 16
59
60 #define BLF_RESULT_CHECK_INIT(r_info) \
61   if (r_info) { \
62     memset(r_info, 0, sizeof(*(r_info))); \
63   } \
64   ((void)0)
65
66 /* Font array. */
67 static FontBLF *global_font[BLF_MAX_FONT] = {NULL};
68
69 /* XXX, should these be made into global_font_'s too? */
70 int blf_mono_font = -1;
71 int blf_mono_font_render = -1;
72
73 static FontBLF *blf_get(int fontid)
74 {
75   if (fontid >= 0 && fontid < BLF_MAX_FONT) {
76     return global_font[fontid];
77   }
78   return NULL;
79 }
80
81 int BLF_init(void)
82 {
83   for (int i = 0; i < BLF_MAX_FONT; i++) {
84     global_font[i] = NULL;
85   }
86
87   BLF_default_dpi(72);
88
89   return blf_font_init();
90 }
91
92 void BLF_exit(void)
93 {
94   for (int i = 0; i < BLF_MAX_FONT; i++) {
95     FontBLF *font = global_font[i];
96     if (font) {
97       blf_font_free(font);
98       global_font[i] = NULL;
99     }
100   }
101
102   blf_font_exit();
103 }
104
105 void BLF_cache_clear(void)
106 {
107   for (int i = 0; i < BLF_MAX_FONT; i++) {
108     FontBLF *font = global_font[i];
109     if (font) {
110       blf_glyph_cache_clear(font);
111       blf_kerning_cache_clear(font);
112     }
113   }
114 }
115
116 bool blf_font_id_is_valid(int fontid)
117 {
118   return blf_get(fontid) != NULL;
119 }
120
121 static int blf_search(const char *name)
122 {
123   for (int i = 0; i < BLF_MAX_FONT; i++) {
124     FontBLF *font = global_font[i];
125     if (font && (STREQ(font->name, name))) {
126       return i;
127     }
128   }
129
130   return -1;
131 }
132
133 static int blf_search_available(void)
134 {
135   for (int i = 0; i < BLF_MAX_FONT; i++) {
136     if (!global_font[i]) {
137       return i;
138     }
139   }
140
141   return -1;
142 }
143
144 bool BLF_has_glyph(int fontid, unsigned int unicode)
145 {
146   FontBLF *font = blf_get(fontid);
147   if (font) {
148     return FT_Get_Char_Index(font->face, unicode) != 0;
149   }
150   return false;
151 }
152
153 int BLF_load(const char *name)
154 {
155   /* check if we already load this font. */
156   int i = blf_search(name);
157   if (i >= 0) {
158     FontBLF *font = global_font[i];
159     font->reference_count++;
160     return i;
161   }
162
163   return BLF_load_unique(name);
164 }
165
166 int BLF_load_unique(const char *name)
167 {
168   /* Don't search in the cache!! make a new
169    * object font, this is for keep fonts threads safe.
170    */
171   int i = blf_search_available();
172   if (i == -1) {
173     printf("Too many fonts!!!\n");
174     return -1;
175   }
176
177   char *filename = blf_dir_search(name);
178   if (!filename) {
179     printf("Can't find font: %s\n", name);
180     return -1;
181   }
182
183   FontBLF *font = blf_font_new(name, filename);
184   MEM_freeN(filename);
185
186   if (!font) {
187     printf("Can't load font: %s\n", name);
188     return -1;
189   }
190
191   font->reference_count = 1;
192   global_font[i] = font;
193   return i;
194 }
195
196 void BLF_metrics_attach(int fontid, unsigned char *mem, int mem_size)
197 {
198   FontBLF *font = blf_get(fontid);
199
200   if (font) {
201     blf_font_attach_from_mem(font, mem, mem_size);
202   }
203 }
204
205 int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size)
206 {
207   int i = blf_search(name);
208   if (i >= 0) {
209     /*font = global_font[i];*/ /*UNUSED*/
210     return i;
211   }
212   return BLF_load_mem_unique(name, mem, mem_size);
213 }
214
215 int BLF_load_mem_unique(const char *name, const unsigned char *mem, int mem_size)
216 {
217   /*
218    * Don't search in the cache, make a new object font!
219    * this is to keep the font thread safe.
220    */
221   int i = blf_search_available();
222   if (i == -1) {
223     printf("Too many fonts!!!\n");
224     return -1;
225   }
226
227   if (!mem_size) {
228     printf("Can't load font: %s from memory!!\n", name);
229     return -1;
230   }
231
232   FontBLF *font = blf_font_new_from_mem(name, mem, mem_size);
233   if (!font) {
234     printf("Can't load font: %s from memory!!\n", name);
235     return -1;
236   }
237
238   font->reference_count = 1;
239   global_font[i] = font;
240   return i;
241 }
242
243 void BLF_unload(const char *name)
244 {
245   for (int i = 0; i < BLF_MAX_FONT; i++) {
246     FontBLF *font = global_font[i];
247
248     if (font && (STREQ(font->name, name))) {
249       BLI_assert(font->reference_count > 0);
250       font->reference_count--;
251
252       if (font->reference_count == 0) {
253         blf_font_free(font);
254         global_font[i] = NULL;
255       }
256     }
257   }
258 }
259
260 void BLF_unload_id(int fontid)
261 {
262   FontBLF *font = blf_get(fontid);
263   if (font) {
264     BLI_assert(font->reference_count > 0);
265     font->reference_count--;
266
267     if (font->reference_count == 0) {
268       blf_font_free(font);
269       global_font[fontid] = NULL;
270     }
271   }
272 }
273
274 void BLF_enable(int fontid, int option)
275 {
276   FontBLF *font = blf_get(fontid);
277
278   if (font) {
279     font->flags |= option;
280   }
281 }
282
283 void BLF_disable(int fontid, int option)
284 {
285   FontBLF *font = blf_get(fontid);
286
287   if (font) {
288     font->flags &= ~option;
289   }
290 }
291
292 void BLF_aspect(int fontid, float x, float y, float z)
293 {
294   FontBLF *font = blf_get(fontid);
295
296   if (font) {
297     font->aspect[0] = x;
298     font->aspect[1] = y;
299     font->aspect[2] = z;
300   }
301 }
302
303 void BLF_matrix(int fontid, const float m[16])
304 {
305   FontBLF *font = blf_get(fontid);
306
307   if (font) {
308     memcpy(font->m, m, sizeof(font->m));
309   }
310 }
311
312 void BLF_position(int fontid, float x, float y, float z)
313 {
314   FontBLF *font = blf_get(fontid);
315
316   if (font) {
317     float xa, ya, za;
318     float remainder;
319
320     if (font->flags & BLF_ASPECT) {
321       xa = font->aspect[0];
322       ya = font->aspect[1];
323       za = font->aspect[2];
324     }
325     else {
326       xa = 1.0f;
327       ya = 1.0f;
328       za = 1.0f;
329     }
330
331     remainder = x - floorf(x);
332     if (remainder > 0.4f && remainder < 0.6f) {
333       if (remainder < 0.5f) {
334         x -= 0.1f * xa;
335       }
336       else {
337         x += 0.1f * xa;
338       }
339     }
340
341     remainder = y - floorf(y);
342     if (remainder > 0.4f && remainder < 0.6f) {
343       if (remainder < 0.5f) {
344         y -= 0.1f * ya;
345       }
346       else {
347         y += 0.1f * ya;
348       }
349     }
350
351     remainder = z - floorf(z);
352     if (remainder > 0.4f && remainder < 0.6f) {
353       if (remainder < 0.5f) {
354         z -= 0.1f * za;
355       }
356       else {
357         z += 0.1f * za;
358       }
359     }
360
361     font->pos[0] = x;
362     font->pos[1] = y;
363     font->pos[2] = z;
364   }
365 }
366
367 void BLF_size(int fontid, int size, int dpi)
368 {
369   FontBLF *font = blf_get(fontid);
370
371   if (font) {
372     blf_font_size(font, size, dpi);
373   }
374 }
375
376 #if BLF_BLUR_ENABLE
377 void BLF_blur(int fontid, int size)
378 {
379   FontBLF *font = blf_get(fontid);
380
381   if (font) {
382     font->blur = size;
383   }
384 }
385 #endif
386
387 void BLF_color4ubv(int fontid, const unsigned char rgba[4])
388 {
389   FontBLF *font = blf_get(fontid);
390
391   if (font) {
392     font->color[0] = rgba[0];
393     font->color[1] = rgba[1];
394     font->color[2] = rgba[2];
395     font->color[3] = rgba[3];
396   }
397 }
398
399 void BLF_color3ubv_alpha(int fontid, const unsigned char rgb[3], unsigned char alpha)
400 {
401   FontBLF *font = blf_get(fontid);
402
403   if (font) {
404     font->color[0] = rgb[0];
405     font->color[1] = rgb[1];
406     font->color[2] = rgb[2];
407     font->color[3] = alpha;
408   }
409 }
410
411 void BLF_color3ubv(int fontid, const unsigned char rgb[3])
412 {
413   BLF_color3ubv_alpha(fontid, rgb, 255);
414 }
415
416 void BLF_color4ub(
417     int fontid, unsigned char r, unsigned char g, unsigned char b, unsigned char alpha)
418 {
419   FontBLF *font = blf_get(fontid);
420
421   if (font) {
422     font->color[0] = r;
423     font->color[1] = g;
424     font->color[2] = b;
425     font->color[3] = alpha;
426   }
427 }
428
429 void BLF_color3ub(int fontid, unsigned char r, unsigned char g, unsigned char b)
430 {
431   FontBLF *font = blf_get(fontid);
432
433   if (font) {
434     font->color[0] = r;
435     font->color[1] = g;
436     font->color[2] = b;
437     font->color[3] = 255;
438   }
439 }
440
441 void BLF_color4fv(int fontid, const float rgba[4])
442 {
443   FontBLF *font = blf_get(fontid);
444
445   if (font) {
446     rgba_float_to_uchar(font->color, rgba);
447   }
448 }
449
450 void BLF_color4f(int fontid, float r, float g, float b, float a)
451 {
452   const float rgba[4] = {r, g, b, a};
453   BLF_color4fv(fontid, rgba);
454 }
455
456 void BLF_color3fv_alpha(int fontid, const float rgb[3], float alpha)
457 {
458   float rgba[4];
459   copy_v3_v3(rgba, rgb);
460   rgba[3] = alpha;
461   BLF_color4fv(fontid, rgba);
462 }
463
464 void BLF_color3f(int fontid, float r, float g, float b)
465 {
466   const float rgba[4] = {r, g, b, 1.0f};
467   BLF_color4fv(fontid, rgba);
468 }
469
470 void BLF_batch_draw_begin(void)
471 {
472   BLI_assert(g_batch.enabled == false);
473   g_batch.enabled = true;
474 }
475
476 void BLF_batch_draw_flush(void)
477 {
478   if (g_batch.enabled) {
479     blf_batch_draw();
480   }
481 }
482
483 void BLF_batch_draw_end(void)
484 {
485   BLI_assert(g_batch.enabled == true);
486   blf_batch_draw(); /* Draw remaining glyphs */
487   g_batch.enabled = false;
488 }
489
490 static void blf_draw_gl__start(FontBLF *font)
491 {
492   /*
493    * The pixmap alignment hack is handle
494    * in BLF_position (old ui_rasterpos_safe).
495    */
496
497   if ((font->flags & (BLF_ROTATION | BLF_MATRIX | BLF_ASPECT)) == 0) {
498     return; /* glyphs will be translated individually and batched. */
499   }
500
501   GPU_matrix_push();
502
503   if (font->flags & BLF_MATRIX) {
504     GPU_matrix_mul(font->m);
505   }
506
507   GPU_matrix_translate_3fv(font->pos);
508
509   if (font->flags & BLF_ASPECT) {
510     GPU_matrix_scale_3fv(font->aspect);
511   }
512
513   if (font->flags & BLF_ROTATION) {
514     GPU_matrix_rotate_2d(RAD2DEG(font->angle));
515   }
516 }
517
518 static void blf_draw_gl__end(FontBLF *font)
519 {
520   if ((font->flags & (BLF_ROTATION | BLF_MATRIX | BLF_ASPECT)) != 0) {
521     GPU_matrix_pop();
522   }
523 }
524
525 void BLF_draw_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info)
526 {
527   FontBLF *font = blf_get(fontid);
528
529   BLF_RESULT_CHECK_INIT(r_info);
530
531   if (font) {
532     blf_draw_gl__start(font);
533     if (font->flags & BLF_WORD_WRAP) {
534       blf_font_draw__wrap(font, str, len, r_info);
535     }
536     else {
537       blf_font_draw(font, str, len, r_info);
538     }
539     blf_draw_gl__end(font);
540   }
541 }
542 void BLF_draw(int fontid, const char *str, size_t len)
543 {
544   if (len == 0 || str[0] == '\0') {
545     return;
546   }
547
548   /* Avoid bgl usage to corrupt BLF drawing. */
549   GPU_bgl_end();
550
551   BLF_draw_ex(fontid, str, len, NULL);
552 }
553
554 void BLF_draw_ascii_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info)
555 {
556   FontBLF *font = blf_get(fontid);
557
558   BLF_RESULT_CHECK_INIT(r_info);
559
560   if (font) {
561     blf_draw_gl__start(font);
562     if (font->flags & BLF_WORD_WRAP) {
563       /* use non-ascii draw function for word-wrap */
564       blf_font_draw__wrap(font, str, len, r_info);
565     }
566     else {
567       blf_font_draw_ascii(font, str, len, r_info);
568     }
569     blf_draw_gl__end(font);
570   }
571 }
572
573 void BLF_draw_ascii(int fontid, const char *str, size_t len)
574 {
575   if (len == 0 || str[0] == '\0') {
576     return;
577   }
578
579   BLF_draw_ascii_ex(fontid, str, len, NULL);
580 }
581
582 int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth)
583 {
584   if (len == 0 || str[0] == '\0') {
585     return 0;
586   }
587
588   FontBLF *font = blf_get(fontid);
589   int columns = 0;
590
591   if (font) {
592     blf_draw_gl__start(font);
593     columns = blf_font_draw_mono(font, str, len, cwidth);
594     blf_draw_gl__end(font);
595   }
596
597   return columns;
598 }
599
600 /**
601  * Run \a user_fn for each character, with the bound-box that would be used for drawing.
602  *
603  * \param user_fn: Callback that runs on each glyph, returning false early exits.
604  * \param user_data: User argument passed to \a user_fn.
605  *
606  * \note The font position, clipping, matrix and rotation are not applied.
607  */
608 void BLF_boundbox_foreach_glyph_ex(int fontid,
609                                    const char *str,
610                                    size_t len,
611                                    BLF_GlyphBoundsFn user_fn,
612                                    void *user_data,
613                                    struct ResultBLF *r_info)
614 {
615   FontBLF *font = blf_get(fontid);
616
617   BLF_RESULT_CHECK_INIT(r_info);
618
619   if (font) {
620     if (font->flags & BLF_WORD_WRAP) {
621       /* TODO: word-wrap support. */
622       BLI_assert(0);
623     }
624     else {
625       blf_font_boundbox_foreach_glyph(font, str, len, user_fn, user_data, r_info);
626     }
627   }
628 }
629
630 void BLF_boundbox_foreach_glyph(
631     int fontid, const char *str, size_t len, BLF_GlyphBoundsFn user_fn, void *user_data)
632 {
633   BLF_boundbox_foreach_glyph_ex(fontid, str, len, user_fn, user_data, NULL);
634 }
635
636 size_t BLF_width_to_strlen(int fontid, const char *str, size_t len, float width, float *r_width)
637 {
638   FontBLF *font = blf_get(fontid);
639
640   if (font) {
641     const float xa = (font->flags & BLF_ASPECT) ? font->aspect[0] : 1.0f;
642     size_t ret;
643     ret = blf_font_width_to_strlen(font, str, len, width / xa, r_width);
644     if (r_width) {
645       *r_width *= xa;
646     }
647     return ret;
648   }
649
650   if (r_width) {
651     *r_width = 0.0f;
652   }
653   return 0;
654 }
655
656 size_t BLF_width_to_rstrlen(int fontid, const char *str, size_t len, float width, float *r_width)
657 {
658   FontBLF *font = blf_get(fontid);
659
660   if (font) {
661     const float xa = (font->flags & BLF_ASPECT) ? font->aspect[0] : 1.0f;
662     size_t ret;
663     ret = blf_font_width_to_rstrlen(font, str, len, width / xa, r_width);
664     if (r_width) {
665       *r_width *= xa;
666     }
667     return ret;
668   }
669
670   if (r_width) {
671     *r_width = 0.0f;
672   }
673   return 0;
674 }
675
676 void BLF_boundbox_ex(
677     int fontid, const char *str, size_t len, rctf *r_box, struct ResultBLF *r_info)
678 {
679   FontBLF *font = blf_get(fontid);
680
681   BLF_RESULT_CHECK_INIT(r_info);
682
683   if (font) {
684     if (font->flags & BLF_WORD_WRAP) {
685       blf_font_boundbox__wrap(font, str, len, r_box, r_info);
686     }
687     else {
688       blf_font_boundbox(font, str, len, r_box, r_info);
689     }
690   }
691 }
692
693 void BLF_boundbox(int fontid, const char *str, size_t len, rctf *r_box)
694 {
695   BLF_boundbox_ex(fontid, str, len, r_box, NULL);
696 }
697
698 void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_width, float *r_height)
699 {
700   FontBLF *font = blf_get(fontid);
701
702   if (font) {
703     blf_font_width_and_height(font, str, len, r_width, r_height, NULL);
704   }
705   else {
706     *r_width = *r_height = 0.0f;
707   }
708 }
709
710 float BLF_width_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info)
711 {
712   FontBLF *font = blf_get(fontid);
713
714   BLF_RESULT_CHECK_INIT(r_info);
715
716   if (font) {
717     return blf_font_width(font, str, len, r_info);
718   }
719
720   return 0.0f;
721 }
722
723 float BLF_width(int fontid, const char *str, size_t len)
724 {
725   return BLF_width_ex(fontid, str, len, NULL);
726 }
727
728 float BLF_fixed_width(int fontid)
729 {
730   FontBLF *font = blf_get(fontid);
731
732   if (font) {
733     return blf_font_fixed_width(font);
734   }
735
736   return 0.0f;
737 }
738
739 float BLF_height_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info)
740 {
741   FontBLF *font = blf_get(fontid);
742
743   BLF_RESULT_CHECK_INIT(r_info);
744
745   if (font) {
746     return blf_font_height(font, str, len, r_info);
747   }
748
749   return 0.0f;
750 }
751
752 float BLF_height(int fontid, const char *str, size_t len)
753 {
754   return BLF_height_ex(fontid, str, len, NULL);
755 }
756
757 int BLF_height_max(int fontid)
758 {
759   FontBLF *font = blf_get(fontid);
760
761   if (font) {
762     return blf_font_height_max(font);
763   }
764
765   return 0;
766 }
767
768 float BLF_width_max(int fontid)
769 {
770   FontBLF *font = blf_get(fontid);
771
772   if (font) {
773     return blf_font_width_max(font);
774   }
775
776   return 0.0f;
777 }
778
779 float BLF_descender(int fontid)
780 {
781   FontBLF *font = blf_get(fontid);
782
783   if (font) {
784     return blf_font_descender(font);
785   }
786
787   return 0.0f;
788 }
789
790 float BLF_ascender(int fontid)
791 {
792   FontBLF *font = blf_get(fontid);
793
794   if (font) {
795     return blf_font_ascender(font);
796   }
797
798   return 0.0f;
799 }
800
801 void BLF_rotation(int fontid, float angle)
802 {
803   FontBLF *font = blf_get(fontid);
804
805   if (font) {
806     font->angle = angle;
807   }
808 }
809
810 void BLF_clipping(int fontid, float xmin, float ymin, float xmax, float ymax)
811 {
812   FontBLF *font = blf_get(fontid);
813
814   if (font) {
815     font->clip_rec.xmin = xmin;
816     font->clip_rec.ymin = ymin;
817     font->clip_rec.xmax = xmax;
818     font->clip_rec.ymax = ymax;
819   }
820 }
821
822 void BLF_wordwrap(int fontid, int wrap_width)
823 {
824   FontBLF *font = blf_get(fontid);
825
826   if (font) {
827     font->wrap_width = wrap_width;
828   }
829 }
830
831 void BLF_shadow(int fontid, int level, const float rgba[4])
832 {
833   FontBLF *font = blf_get(fontid);
834
835   if (font) {
836     font->shadow = level;
837     rgba_float_to_uchar(font->shadow_color, rgba);
838   }
839 }
840
841 void BLF_shadow_offset(int fontid, int x, int y)
842 {
843   FontBLF *font = blf_get(fontid);
844
845   if (font) {
846     font->shadow_x = x;
847     font->shadow_y = y;
848   }
849 }
850
851 void BLF_buffer(int fontid,
852                 float *fbuf,
853                 unsigned char *cbuf,
854                 int w,
855                 int h,
856                 int nch,
857                 struct ColorManagedDisplay *display)
858 {
859   FontBLF *font = blf_get(fontid);
860
861   if (font) {
862     font->buf_info.fbuf = fbuf;
863     font->buf_info.cbuf = cbuf;
864     font->buf_info.dims[0] = w;
865     font->buf_info.dims[1] = h;
866     font->buf_info.ch = nch;
867     font->buf_info.display = display;
868   }
869 }
870
871 void BLF_buffer_col(int fontid, const float rgba[4])
872 {
873   FontBLF *font = blf_get(fontid);
874
875   if (font) {
876     copy_v4_v4(font->buf_info.col_init, rgba);
877   }
878 }
879
880 void blf_draw_buffer__start(FontBLF *font)
881 {
882   FontBufInfoBLF *buf_info = &font->buf_info;
883
884   rgba_float_to_uchar(buf_info->col_char, buf_info->col_init);
885
886   if (buf_info->display) {
887     copy_v4_v4(buf_info->col_float, buf_info->col_init);
888     IMB_colormanagement_display_to_scene_linear_v3(buf_info->col_float, buf_info->display);
889   }
890   else {
891     srgb_to_linearrgb_v4(buf_info->col_float, buf_info->col_init);
892   }
893 }
894 void blf_draw_buffer__end(void)
895 {
896 }
897
898 void BLF_draw_buffer_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info)
899 {
900   FontBLF *font = blf_get(fontid);
901
902   if (font && (font->buf_info.fbuf || font->buf_info.cbuf)) {
903     blf_draw_buffer__start(font);
904     if (font->flags & BLF_WORD_WRAP) {
905       blf_font_draw_buffer__wrap(font, str, len, r_info);
906     }
907     else {
908       blf_font_draw_buffer(font, str, len, r_info);
909     }
910     blf_draw_buffer__end();
911   }
912 }
913 void BLF_draw_buffer(int fontid, const char *str, size_t len)
914 {
915   BLF_draw_buffer_ex(fontid, str, len, NULL);
916 }
917
918 #ifdef DEBUG
919 void BLF_state_print(int fontid)
920 {
921   FontBLF *font = blf_get(fontid);
922   if (font) {
923     printf("fontid %d %p\n", fontid, (void *)font);
924     printf("  name:    '%s'\n", font->name);
925     printf("  size:     %u\n", font->size);
926     printf("  dpi:      %u\n", font->dpi);
927     printf("  pos:      %.6f %.6f %.6f\n", UNPACK3(font->pos));
928     printf("  aspect:   (%d) %.6f %.6f %.6f\n",
929            (font->flags & BLF_ROTATION) != 0,
930            UNPACK3(font->aspect));
931     printf("  angle:    (%d) %.6f\n", (font->flags & BLF_ASPECT) != 0, font->angle);
932     printf("  flag:     %d\n", font->flags);
933   }
934   else {
935     printf("fontid %d (NULL)\n", fontid);
936   }
937   fflush(stdout);
938 }
939 #endif