Workaround for a known fifobuf bug.
[bertos.git] / mware / text.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 devlib/README for information.
7  * -->
8  *
9  * \brief Text graphic routines
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.8  2004/11/16 21:16:28  bernie
19  *#* Update to new naming scheme in mware/gfx.c.
20  *#*
21  *#* Revision 1.7  2004/09/20 03:28:28  bernie
22  *#* Fix header.
23  *#*
24  *#* Revision 1.6  2004/09/14 20:57:15  bernie
25  *#* Use debug.h instead of kdebug.h.
26  *#*
27  *#* Revision 1.5  2004/09/06 21:51:26  bernie
28  *#* Extend interface to allow any algorithmic style.
29  *#*
30  *#* Revision 1.2  2004/06/03 11:27:09  bernie
31  *#* Add dual-license information.
32  *#*
33  *#* Revision 1.1  2004/05/23 15:43:16  bernie
34  *#* Import mware modules.
35  *#*
36  *#* Revision 1.17  2004/05/15 16:57:01  aleph
37  *#* Fixes for non-DEBUG build
38  *#*
39  *#* Revision 1.16  2004/04/03 20:42:49  aleph
40  *#* Add text_clear()
41  *#*
42  *#* Revision 1.15  2004/03/24 15:03:45  bernie
43  *#* Use explicit include paths; clean Doxygen comments
44  *#*
45  *#* Revision 1.14  2004/03/19 16:52:28  bernie
46  *#* Move printf() like functions from text.c to text_format.c and add PROGMEM versions.
47  *#*
48  *#* Revision 1.13  2004/03/17 18:23:32  bernie
49  *#* Oops.
50  *#*
51  *#* Revision 1.12  2004/03/17 18:03:22  bernie
52  *#* Make diagnostic message shorter
53  *#*
54  *#* Revision 1.11  2004/03/13 22:52:54  aleph
55  *#* documentation fixes
56  *#*/
57
58 #include "gfx.h"
59 #include "font.h"
60 #include "text.h"
61 #include <debug.h>
62
63 /*!
64  * Flags degli stili algoritmici
65  *
66  * La routine di rendering del testo e' in grado di applicare
67  * delle semplici trasformazioni al font interno per generare
68  * automaticamente degli stili predefiniti (bold, italic,
69  * underline) a partire dal set di caratteri plain.
70  */
71 static uint8_t text_styles;
72
73 /*! ANSI escape sequences flag: true for ESC state on */
74 static bool ansi_mode = false;
75
76
77 /*!
78  * Move (imaginary) cursor to column and row specified.
79  * Next text write will start a that row and col.
80  */
81 void text_moveto(struct Bitmap *bm, int row, int col)
82 {
83         ASSERT(col >= 0);
84         ASSERT(col < bm->width / FONT_WIDTH);
85         ASSERT(row >= 0);
86         ASSERT(row < bm->height / FONT_HEIGHT);
87
88         bm->penX = col * FONT_WIDTH;
89         bm->penY = row * FONT_HEIGHT;
90 }
91
92
93 /*!
94  * Move (imaginary) cursor to coordinates specified.
95  */
96 void text_setcoord(struct Bitmap *bm, int x, int y)
97 {
98         bm->penX = x;
99         bm->penY = y;
100 }
101
102
103 /*!
104  * Render char \a c on Bitmap \a bm
105  */
106 static int text_putglyph(char c, struct Bitmap *bm)
107 {
108         const uint8_t * PROGMEM glyph;  /* font is in progmem */
109         uint8_t glyph_width;
110         uint8_t i;
111         uint8_t *buf;
112
113         /*
114          * Il carattere da stampare viene usato come indice per prelevare
115          * la prima colonna di dots del glyph all'interno del font.
116          */
117         glyph = font + (((unsigned char)c) * FONT_WIDTH);
118         glyph_width = FONT_WIDTH;
119
120         if (text_styles & STYLEF_CONDENSED)
121                 --glyph_width;
122
123         if (text_styles & STYLEF_EXPANDED)
124                 glyph_width *= 2;
125
126         /* The y coord is rounded at multiples of 8 for simplicity */
127         bm->penY &= ~((coord_t)7);
128
129         /* Check if glyph to write fits in the bitmap */
130         if ((bm->penX < 0) || (bm->penX + glyph_width > bm->width) ||
131                 (bm->penY < 0) || (bm->penY + FONT_HEIGHT > bm->height))
132         {
133                 DB(kprintf("bad coords x=%d y=%d\n", bm->penX, bm->penY);)
134                 return 0;
135         }
136
137         /* Locate position where to write in the raster */
138         buf = bm->raster + bm->penY / 8 * bm->width + bm->penX;
139
140         bm->penX += glyph_width;
141
142         /* If some styles are set */
143         if (text_styles)
144         {
145                 uint8_t prev_dots = 0, italic_prev_dots = 0, new_dots;
146                 uint8_t dots;
147
148                 /* Per ogni colonna di dot del glyph... */
149                 for (i = 0; i < glyph_width; ++i)
150                 {
151                         dots = pgm_read_byte(glyph);
152
153                         /* Advance to next column in glyph.
154                          * Expand: advances only once every two columns
155                          */
156                         if (!(text_styles & STYLEF_EXPANDED) || (i & 1))
157                                 glyph++;
158
159                         /* Italic: get lower 4 dots from previous column */
160                         if (text_styles & STYLEF_ITALIC)
161                         {
162                                 new_dots = dots;
163                                 dots = (dots & 0xF0) | italic_prev_dots;
164                                 italic_prev_dots = new_dots & 0x0F;
165                         }
166
167                         /* Bold: "or" pixels with the previous column */
168                         if (text_styles & STYLEF_BOLD)
169                         {
170                                 new_dots = dots;
171                                 dots |= prev_dots;
172                                 prev_dots = new_dots;
173                         }
174
175                         /* Underlined: turn on base pixel */
176                         if (text_styles & STYLEF_UNDERLINE)
177                                 dots |= 0x80;
178
179                         /* Inverted: invert pixels */
180                         if (text_styles & STYLEF_INVERT)
181                                 dots = ~dots;
182
183                         /* Output dots */
184                         *buf++ = dots;
185                 }
186         }
187         else /* No style: fast vanilla copy of glyph to line buffer */
188                 while (glyph_width--)
189                         *buf++ = pgm_read_byte(glyph++);
190
191         return c;
192 }
193
194
195 /*!
196  * Render char \c c, with (currently) limited ANSI escapes
197  * emulation support and '\n' for newline.
198  */
199 int text_putchar(char c, struct Bitmap *bm)
200 {
201         /* Handle ANSI escape sequences */
202         if (ansi_mode)
203         {
204                 switch (c)
205                 {
206                 case ANSI_ESC_CLEARSCREEN:
207                         gfx_bitmapClear(bm);
208                         bm->penX = 0;
209                         bm->penY = 0;
210                         text_style(0, STYLEF_MASK);
211                         break;
212                 DB(default:
213                         kprintf("Unknown ANSI esc code: %x\n", c);)
214                 }
215                 ansi_mode = false;
216         }
217         else if (c == '\033')  /* Enter ANSI ESC mode */
218         {
219                 ansi_mode = true;
220         }
221         else if (c == '\n')  /* Go one line down on a line-feed */
222         {
223                 if (bm->penY + FONT_HEIGHT < bm->height)
224                 {
225                         bm->penY += FONT_HEIGHT;
226                         bm->penX = 0;
227                 }
228         }
229         else
230         {
231                 text_putglyph(c, bm);
232         }
233         return c;
234 }
235
236
237 /*!
238  * Clear the screen and reset cursor position
239  */
240 void text_clear(struct Bitmap *bmp)
241 {
242         text_putchar('\x1b', bmp);
243         text_putchar('c', bmp);
244 }
245
246
247 void text_clearLine(struct Bitmap *bmp, int line)
248 {
249         gfx_rectClear(bmp, 0, line * FONT_HEIGHT, bmp->width, (line + 1) * FONT_HEIGHT);
250 }
251
252
253 /*!
254  * Set/clear algorithmic font style bits.
255  *
256  * \param flags  Style flags to set
257  * \param mask   Mask of flags to modify
258  * \return       Old style flags
259  *
260  * Examples:
261  * Turn on bold, leave other styles alone
262  *   \code prt_style(STYLEF_BOLD, STYLEF_BOLD); \endcode
263  *
264  * Turn off bold and turn on italic, leave others as they are
265  *   \code prt_style(STYLEF_ITALIC, STYLEF_BOLD | STYLEF_ITALIC); \endcode
266  *
267  * Query current style without chaning it
268  *   \code style = prt_style(0, 0); \endcode
269  *
270  * Reset all styles (plain text)
271  *   \code prt_style(0, STYLE_MASK); \endcode
272  */
273 uint8_t text_style(uint8_t flags, uint8_t mask)
274 {
275         uint8_t old = text_styles;
276         text_styles = (text_styles & ~mask) | flags;
277         return old;
278 }