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