Mark slow paths as UNLIKELY.
[bertos.git] / gfx / text_format.c
1 /*!
2  * \file
3  * <!--
4  * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
5  * Copyright 1999 Bernardo Innocenti <bernie@develer.com>
6  * This file is part of DevLib - See README.devlib for information.
7  * -->
8  *
9  * \brief printf-family routines for text output
10  *
11  * \version $Id$
12  * \author Bernardo Innocenti <bernie@develer.com>
13  * \author Stefano Fedrigo <aleph@develer.com>
14  */
15
16 /*#*
17  *#* $Log$
18  *#* Revision 1.6  2006/03/13 02:05:54  bernie
19  *#* Mark slow paths as UNLIKELY.
20  *#*
21  *#* Revision 1.5  2006/03/07 22:18:04  bernie
22  *#* Correctly compute text width for prop fonts; Make styles a per-bitmap attribute.
23  *#*
24  *#* Revision 1.4  2006/02/10 12:31:33  bernie
25  *#* Add multiple font support in bitmaps.
26  *#*
27  *#* Revision 1.3  2005/11/27 23:31:58  bernie
28  *#* Reorder includes.
29  *#*
30  *#* Revision 1.2  2005/11/04 18:17:45  bernie
31  *#* Fix header guards and includes for new location of gfx module.
32  *#*
33  *#* Revision 1.1  2005/11/04 18:11:35  bernie
34  *#* Move graphics stuff from mware/ to gfx/.
35  *#*
36  *#* Revision 1.10  2005/11/04 16:20:02  bernie
37  *#* Fix reference to README.devlib in header.
38  *#*
39  *#* Revision 1.9  2004/12/31 17:47:45  bernie
40  *#* Rename UNUSED() to UNUSED_ARG().
41  *#*
42  *#* Revision 1.8  2004/11/16 21:16:56  bernie
43  *#* Update to new naming scheme in mware/gfx.c.
44  *#*
45  *#* Revision 1.7  2004/10/03 19:05:04  bernie
46  *#* text_widthf(), text_vwidthf(): New functions.
47  *#*
48  *#* Revision 1.6  2004/09/14 20:59:04  bernie
49  *#* text_xprintf(): Support all styles; Pixel-wise text centering.
50  *#*
51  *#* Revision 1.5  2004/08/25 14:12:09  rasky
52  *#* Aggiornato il comment block dei log RCS
53  *#*
54  *#* Revision 1.4  2004/08/05 18:46:44  bernie
55  *#* Documentation improvements.
56  *#*
57  *#* Revision 1.3  2004/08/03 15:57:18  aleph
58  *#* Add include to fix warning for vsprintf()
59  *#*
60  *#* Revision 1.2  2004/06/03 11:27:09  bernie
61  *#* Add dual-license information.
62  *#*
63  *#* Revision 1.1  2004/05/23 15:43:16  bernie
64  *#* Import mware modules.
65  *#*
66  *#* Revision 1.2  2004/03/26 18:50:50  bernie
67  *#* Move _PROGMEM stuff to compiler.h
68  *#*
69  *#* Revision 1.1  2004/03/19 16:52:28  bernie
70  *#* Move printf() like functions from text.c to text_format.c and add PROGMEM versions.
71  *#*
72  *#*/
73
74 #include "text.h"
75
76 #include <mware/formatwr.h> /* _formatted_write() */
77 #include <gfx/font.h>
78 #include <gfx/gfx.h>
79
80 #include <stdio.h> /* vsprintf() */
81 #include <stdarg.h>
82 #include <string.h> /* strlen() */
83
84 /*!
85  * Render string \a str in Bitmap \a bm at current cursor position
86  *
87  * \note Text formatting functions are also available with an _P suffix
88  *       accepting the source string from program memory.  This feature
89  *       is only available (and useful) on Harvard microprocessors such
90  *       as the AVR.
91  *
92  * \see text_putchar()
93  */
94 int PGM_FUNC(text_puts)(const char * PGM_ATTR str, struct Bitmap *bm)
95 {
96         char c;
97
98         while ((c = PGM_READ_CHAR(str++)))
99                 text_putchar(c, bm);
100
101         return 0;
102 }
103
104
105 /*!
106  * vprintf()-like formatter to render text in a Bitmap.
107  *
108  * Perform vprintf()-like formatting on the \a fmt format string using the
109  * variable-argument list \a ap.
110  * Render the resulting string in Bitmap \a bm starting at the current
111  * cursor position.
112  *
113  * \see text_puts() text_putchar() text_printf()
114  */
115 int PGM_FUNC(text_vprintf)(struct Bitmap *bm, const char * PGM_ATTR fmt, va_list ap)
116 {
117         return PGM_FUNC(_formatted_write)(fmt, (void (*)(char, void *))text_putchar, bm, ap);
118 }
119
120 /*!
121  * printf()-like formatter to render text in a Bitmap.
122  *
123  * Perform printf()-like formatting on the \a fmt format string.
124  * Render the resulting string in Bitmap \a bm starting at the
125  * current cursor position.
126  *
127  * \see text_puts() text_putchar() text_vprintf()
128  */
129 int PGM_FUNC(text_printf)(struct Bitmap *bm, const char * PGM_ATTR fmt, ...)
130 {
131         int len;
132
133         va_list ap;
134         va_start(ap, fmt);
135         len = PGM_FUNC(text_vprintf)(bm, fmt, ap);
136         va_end(ap);
137
138         return len;
139 }
140
141
142 /*!
143  * Render the result of printf()-like formatting in a specified position
144  * of a Bitmap.
145  *
146  * \param bm Bitmap where to render the text
147  * \param row   Starting row in character units (zero based)
148  * \param col   Starting column in character units (zero based)
149  * \param style Formatting style to use.  In addition to any STYLEF_
150  *        flag, it can be TEXT_NORMAL, TEXT_FILL, TEXT_INVERT or
151  *        TEXT_RIGHT, or a combination of these flags ORed together.
152  * \param fmt  String possibly containing printf() formatting commands.
153  *
154  * \see text_puts() text_putchar() text_printf() text_vprintf()
155  * \see text_moveto() text_style()
156  */
157 int PGM_FUNC(text_xprintf)(struct Bitmap *bm,
158                 uint8_t row, uint8_t col, uint16_t style, const char * PGM_ATTR fmt, ...)
159 {
160         int len;
161         uint8_t oldstyle = 0;
162         va_list ap;
163
164         va_start(ap, fmt);
165
166         text_moveto(bm, row, col);
167
168         if (style & STYLEF_MASK)
169                 oldstyle = text_style(bm, style, STYLEF_MASK);
170
171         if (style & (TEXT_CENTER | TEXT_RIGHT))
172         {
173                 uint8_t pad = bm->width - PGM_FUNC(text_vwidthf)(bm, fmt, ap);
174
175                 if (style & TEXT_CENTER)
176                         pad /= 2;
177
178                 if (style & TEXT_FILL)
179                         gfx_rectFillC(bm, 0, row * bm->font->height, pad, (row + 1) * bm->font->height,
180                                 (style & STYLEF_INVERT) ? 0xFF : 0x00);
181
182                 text_setcoord(bm, pad, row * bm->font->height);
183         }
184
185         len = PGM_FUNC(text_vprintf)(bm, fmt, ap);
186         va_end(ap);
187
188         if (style & TEXT_FILL)
189                 gfx_rectFillC(bm, bm->penX, row * bm->font->height, bm->width, (row + 1) * bm->font->height,
190                         (style & STYLEF_INVERT) ? 0xFF : 0x00);
191
192         /* Restore old style */
193         if (style & STYLEF_MASK)
194                 text_style(bm, oldstyle, STYLEF_MASK);
195
196         return len;
197 }
198
199
200 struct TextWidthData
201 {
202                 Bitmap *bitmap;
203                 coord_t width;
204 };
205
206 /**
207  * Compute width in pixels of a character.
208  *
209  * Compute the on screen width of a character, taking the
210  * current style and font into account.
211  *
212  * The width is accumulated in the WidthData structure
213  * passed as second argument.
214  *
215  * This is a formatted_write() callback used by text_vwidthf()
216  * to compute the length of a formatted string.
217  */
218 static int text_charWidth(int c, struct TextWidthData *twd)
219 {
220         unsigned char index = (unsigned char)c;
221         Bitmap *bm = twd->bitmap;
222         coord_t glyph_width;
223
224
225         if (UNLIKELY(index < bm->font->first || index > bm->font->last))
226         {
227                 if ('?' >= bm->font->first && '?' <= bm->font->last)
228                         index = '?';
229                 else
230                         index = bm->font->first;
231         }
232
233         /* Make character relative to font start */
234         index -= bm->font->first;
235
236         if (bm->font->offset)
237                 /* Proportional font */
238                 glyph_width = bm->font->widths[index]; /* TODO: optimize away */
239         else
240                 /* Fixed width font */
241                 glyph_width = bm->font->width;
242
243         if (bm->styles & STYLEF_CONDENSED)
244                 --glyph_width;
245
246         if (bm->styles & STYLEF_EXPANDED)
247                 glyph_width *= 2;
248
249         twd->width += glyph_width;
250
251         return c;
252 }
253
254 /*!
255  * Return the width in pixels of a vprintf()-formatted string.
256  */
257 int PGM_FUNC(text_vwidthf)(
258         UNUSED_ARG(struct Bitmap *, bm),
259         const char * PGM_ATTR fmt,
260         va_list ap)
261 {
262         /* Fixed font with no styles affecting the width? */
263         if (!bm->font->offset && !(bm->styles & (STYLEF_CONDENSED | STYLEF_EXPANDED)))
264                 return PGM_FUNC(vsprintf)(NULL, fmt, ap) * bm->font->width;
265         else
266         {
267                 struct TextWidthData twd = { bm, 0 };
268                 _formatted_write(fmt, (void (*)(char, void *))text_charWidth, &twd, ap);
269                 return twd.width;
270         }
271 }
272
273
274 /*!
275  * Return the width in pixels of a printf()-formatted string.
276  */
277 int PGM_FUNC(text_widthf)(struct Bitmap *bm, const char * PGM_ATTR fmt, ...)
278 {
279         int width;
280
281         va_list ap;
282         va_start(ap, fmt);
283         width = PGM_FUNC(text_vwidthf)(bm, fmt, ap);
284         va_end(ap);
285
286         return width;
287 }