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