4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2003, 2004, 2005 Develer S.r.l. (http://www.develer.com/)
30 * Copyright 1999 Bernardo Innocenti <bernie@develer.com>
34 * \brief Text graphic routines
37 * \author Bernardo Innocenti <bernie@develer.com>
38 * \author Stefano Fedrigo <aleph@develer.com>
43 *#* Revision 1.13 2006/07/19 12:56:26 bernie
44 *#* Convert to new Doxygen style.
46 *#* Revision 1.12 2006/05/25 23:35:22 bernie
47 *#* Implement correct and faster clipping for algo text.
49 *#* Revision 1.11 2006/05/15 07:21:06 bernie
52 *#* Revision 1.10 2006/04/27 05:39:23 bernie
53 *#* Enhance text rendering to arbitrary x,y coords.
55 *#* Revision 1.9 2006/04/11 00:08:24 bernie
56 *#* text_offset(): New function, but I'm not quite confident with the design.
58 *#* Revision 1.8 2006/03/22 09:50:37 bernie
59 *#* Use the same format for fonts and rasters.
61 *#* Revision 1.7 2006/03/20 17:51:55 bernie
64 *#* Revision 1.6 2006/03/13 02:05:54 bernie
65 *#* Mark slow paths as UNLIKELY.
67 *#* Revision 1.5 2006/03/07 22:18:04 bernie
68 *#* Correctly compute text width for prop fonts; Make styles a per-bitmap attribute.
70 *#* Revision 1.4 2006/02/15 09:10:15 bernie
71 *#* Implement prop fonts; Fix algo styles.
73 *#* Revision 1.3 2006/02/10 12:31:55 bernie
74 *#* Add multiple font support in bitmaps.
76 *#* Revision 1.2 2005/11/04 18:17:45 bernie
77 *#* Fix header guards and includes for new location of gfx module.
79 *#* Revision 1.1 2005/11/04 18:11:35 bernie
80 *#* Move graphics stuff from mware/ to gfx/.
82 *#* Revision 1.13 2005/11/04 16:20:02 bernie
83 *#* Fix reference to README.devlib in header.
85 *#* Revision 1.12 2005/04/11 19:10:28 bernie
86 *#* Include top-level headers from cfg/ subdir.
88 *#* Revision 1.11 2005/01/20 18:46:31 aleph
89 *#* Fix progmem includes.
91 *#* Revision 1.10 2005/01/08 09:20:12 bernie
92 *#* Really make it work on both architectures.
94 *#* Revision 1.9 2004/12/31 16:44:29 bernie
95 *#* Sanitize for non-Harvard processors.
97 *#* Revision 1.8 2004/11/16 21:16:28 bernie
98 *#* Update to new naming scheme in mware/gfx.c.
100 *#* Revision 1.7 2004/09/20 03:28:28 bernie
103 *#* Revision 1.6 2004/09/14 20:57:15 bernie
104 *#* Use debug.h instead of kdebug.h.
106 *#* Revision 1.5 2004/09/06 21:51:26 bernie
107 *#* Extend interface to allow any algorithmic style.
109 *#* Revision 1.2 2004/06/03 11:27:09 bernie
110 *#* Add dual-license information.
112 *#* Revision 1.1 2004/05/23 15:43:16 bernie
113 *#* Import mware modules.
115 *#* Revision 1.17 2004/05/15 16:57:01 aleph
116 *#* Fixes for non-DEBUG build
118 *#* Revision 1.16 2004/04/03 20:42:49 aleph
121 *#* Revision 1.15 2004/03/24 15:03:45 bernie
122 *#* Use explicit include paths; clean Doxygen comments
124 *#* Revision 1.14 2004/03/19 16:52:28 bernie
125 *#* Move printf() like functions from text.c to text_format.c and add PROGMEM versions.
127 *#* Revision 1.13 2004/03/17 18:23:32 bernie
130 *#* Revision 1.12 2004/03/17 18:03:22 bernie
131 *#* Make diagnostic message shorter
133 *#* Revision 1.11 2004/03/13 22:52:54 aleph
134 *#* documentation fixes
138 #include <gfx/font.h>
139 #include <gfx/text.h>
140 #include <gfx/text.h>
142 #include <gfx/gfx_p.h> // FIXME: BM_DRAWPIXEL
144 #include <cfg/debug.h>
148 * ANSI escape sequences flag: true for ESC state on.
150 * \todo Move to Bitmap.flags.
152 static bool ansi_mode = false;
155 * Move (imaginary) cursor to coordinates specified.
157 void text_setCoord(struct Bitmap *bm, int x, int y)
165 * Move (imaginary) cursor to column and row specified.
166 * Next text write will start a that row and col.
168 void text_moveTo(struct Bitmap *bm, int row, int col)
171 ASSERT(col < bm->width / bm->font->width);
173 ASSERT(row < bm->height / bm->font->height);
175 text_setCoord(bm, col * bm->font->width, row * bm->font->height);
180 * Render char \a c on Bitmap \a bm.
182 static int text_putglyph(char c, struct Bitmap *bm)
184 const uint8_t * PROGMEM glyph; /* font is in progmem */
185 uint8_t glyph_width, glyph_height, glyph_height_bytes;
186 unsigned char index = (unsigned char)c;
188 /* Check for out of range char and replace with '?' or first char in font. */
189 if (UNLIKELY(!FONT_HAS_GLYPH(bm->font, index)))
191 kprintf("Illegal char '%c' (0x%02x)\n", index, index);
192 if (FONT_HAS_GLYPH(bm->font, '?'))
195 index = bm->font->first;
198 /* Make character relative to font start */
199 index -= bm->font->first;
201 glyph_height = bm->font->height;
202 // FIXME: for vertical fonts only
203 glyph_height_bytes = (glyph_height + 7) / 8;
205 if (bm->font->offset)
207 /* Proportional font */
208 glyph_width = bm->font->widths[index]; /* TODO: optimize away */
209 glyph = bm->font->glyph + bm->font->offset[index];
214 * Fixed-width font: compute the first column of pixels
215 * of the selected glyph using the character code to index
218 glyph_width = bm->font->width;
220 //For horizontal fonts
221 //glyph = bm->font->glyph + index * (((glyph_width + 7) / 8) * glyph_height);
222 glyph = bm->font->glyph + index * glyph_height_bytes * glyph_width;
225 /* Slow path for styled glyphs */
226 if (UNLIKELY(bm->styles))
228 uint8_t styles = bm->styles;
229 uint8_t prev_dots = 0, italic_prev_dots = 0;
231 uint8_t row, col, row_bit;
234 * To avoid repeating clipping and other expensive computations,
235 * we cluster calls to gfx_blitRaster() using a small buffer.
237 #define CONFIG_TEXT_RENDER_OPTIMIZE 1
238 #if CONFIG_TEXT_RENDER_OPTIMIZE
239 #define RENDER_BUF_WIDTH 12
240 #define RENDER_BUF_HEIGHT 8
241 uint8_t render_buf[RAST_SIZE(RENDER_BUF_WIDTH, RENDER_BUF_HEIGHT)];
242 uint8_t render_xpos = 0;
245 /* This style alone could be handled by the fast path too */
246 if (bm->styles & STYLEF_CONDENSED)
249 if (bm->styles & STYLEF_EXPANDED)
252 for (row = 0, row_bit = 0; row < glyph_height_bytes; ++row, row_bit += 8)
254 /* For each dot column in the glyph... */
255 for (col = 0; col < glyph_width; ++col)
257 uint8_t src_col = col;
259 /* Expanded style: advances only once every two columns. */
260 if (styles & STYLEF_EXPANDED)
263 /* Fetch a column of dots from glyph. */
264 dots = PGM_READ_CHAR(RAST_ADDR(glyph, src_col, row_bit, glyph_width));
266 /* Italic: get lower 4 dots from previous column */
267 if (styles & STYLEF_ITALIC)
269 uint8_t new_dots = dots;
270 dots = (dots & 0xF0) | italic_prev_dots;
271 italic_prev_dots = new_dots & 0x0F;
274 /* Bold: "or" pixels with the previous column */
275 if (styles & STYLEF_BOLD)
277 uint8_t new_dots = dots;
279 prev_dots = new_dots;
282 /* Underlined: turn on base pixel */
283 if ((styles & STYLEF_UNDERLINE)
284 && (row == glyph_height_bytes - 1))
285 dots |= (1 << (glyph_height - row_bit - 1));
287 /* Inverted: invert pixels */
288 if (styles & STYLEF_INVERT)
292 #if CONFIG_TEXT_RENDER_OPTIMIZE
293 render_buf[render_xpos++] = dots;
294 if (render_xpos == RENDER_BUF_WIDTH)
296 gfx_blitRaster(bm, bm->penX + col - render_xpos + 1, bm->penY + row_bit,
297 render_buf, render_xpos,
298 MIN((uint8_t)RENDER_BUF_HEIGHT, (uint8_t)(glyph_height - row_bit)),
303 gfx_blitRaster(bm, bm->penX + col, bm->penY + row_bit,
304 &dots, 1, MIN((uint8_t)8, glyph_height - row_bit), 1);
308 #if CONFIG_TEXT_RENDER_OPTIMIZE
309 /* Flush out rest of render buffer */
310 if (render_xpos != 0)
312 gfx_blitRaster(bm, bm->penX + col - render_xpos, bm->penY + row_bit,
313 render_buf, render_xpos,
314 MIN((uint8_t)RENDER_BUF_HEIGHT, (uint8_t)(glyph_height - row_bit)),
323 /* No style: fast vanilla copy of glyph to bitmap */
324 gfx_blitRaster(bm, bm->penX, bm->penY, glyph, glyph_width, glyph_height, glyph_width);
327 /* Update current pen position */
328 bm->penX += glyph_width;
335 * Render char \c c, with (currently) limited ANSI escapes
336 * emulation support and '\n' for newline.
338 int text_putchar(char c, struct Bitmap *bm)
340 /* Handle ANSI escape sequences */
341 if (UNLIKELY(ansi_mode))
345 case ANSI_ESC_CLEARSCREEN:
349 text_style(bm, 0, STYLEF_MASK);
352 kprintf("Unknown ANSI esc code: %x\n", c);)
356 else if (c == '\033') /* Enter ANSI ESC mode */
360 else if (c == '\n') /* Go one line down on a line-feed */
362 if (bm->penY + bm->font->height < bm->height)
364 bm->penY += bm->font->height;
370 text_putglyph(c, bm);
377 * Clear the screen and reset cursor position
379 void text_clear(struct Bitmap *bmp)
381 text_putchar('\x1b', bmp);
382 text_putchar('c', bmp);
386 void text_clearLine(struct Bitmap *bm, int line)
388 gfx_rectClear(bm, 0, line * bm->font->height, bm->width, (line + 1) * bm->font->height);
393 * Set/clear algorithmic font style bits.
395 * \param bm Pointer to Bitmap to affect.
396 * \param flags Style flags to set
397 * \param mask Mask of flags to modify
398 * \return Old style flags
401 * Turn on bold, leave other styles alone
402 * \code text_style(bm, STYLEF_BOLD, STYLEF_BOLD); \endcode
404 * Turn off bold and turn on italic, leave others as they are
405 * \code text_style(bm, STYLEF_ITALIC, STYLEF_BOLD | STYLEF_ITALIC); \endcode
407 * Query current style without chaning it
408 * \code style = text_style(bm, 0, 0); \endcode
410 * Reset all styles (plain text)
411 * \code text_style(bm, 0, STYLE_MASK); \endcode
413 uint8_t text_style(struct Bitmap *bm, uint8_t flags, uint8_t mask)
415 uint8_t old = bm->styles;
416 bm->styles = (bm->styles & ~mask) | flags;