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