X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=gfx%2Ftext.c;h=f296be78d3ae11560e0f1fbbf43489ba39ae9ee3;hb=5f3952176a4e9a00ca8dd5ec4a6b994958f89e0a;hp=084e9511f9b84495bbf20010d3eeba1514efbe9c;hpb=41ee2287b2f2d7ec3e73e998b06076888608ed72;p=bertos.git diff --git a/gfx/text.c b/gfx/text.c old mode 100755 new mode 100644 index 084e9511..f296be78 --- a/gfx/text.c +++ b/gfx/text.c @@ -1,7 +1,7 @@ -/*! +/** * \file * @@ -15,6 +15,42 @@ /*#* *#* $Log$ + *#* Revision 1.13 2006/07/19 12:56:26 bernie + *#* Convert to new Doxygen style. + *#* + *#* Revision 1.12 2006/05/25 23:35:22 bernie + *#* Implement correct and faster clipping for algo text. + *#* + *#* Revision 1.11 2006/05/15 07:21:06 bernie + *#* Doxygen fix. + *#* + *#* Revision 1.10 2006/04/27 05:39:23 bernie + *#* Enhance text rendering to arbitrary x,y coords. + *#* + *#* Revision 1.9 2006/04/11 00:08:24 bernie + *#* text_offset(): New function, but I'm not quite confident with the design. + *#* + *#* Revision 1.8 2006/03/22 09:50:37 bernie + *#* Use the same format for fonts and rasters. + *#* + *#* Revision 1.7 2006/03/20 17:51:55 bernie + *#* Cleanups. + *#* + *#* Revision 1.6 2006/03/13 02:05:54 bernie + *#* Mark slow paths as UNLIKELY. + *#* + *#* Revision 1.5 2006/03/07 22:18:04 bernie + *#* Correctly compute text width for prop fonts; Make styles a per-bitmap attribute. + *#* + *#* Revision 1.4 2006/02/15 09:10:15 bernie + *#* Implement prop fonts; Fix algo styles. + *#* + *#* Revision 1.3 2006/02/10 12:31:55 bernie + *#* Add multiple font support in bitmaps. + *#* + *#* Revision 1.2 2005/11/04 18:17:45 bernie + *#* Fix header guards and includes for new location of gfx module. + *#* *#* Revision 1.1 2005/11/04 18:11:35 bernie *#* Move graphics stuff from mware/ to gfx/. *#* @@ -73,153 +109,211 @@ *#* documentation fixes *#*/ -#include "gfx.h" -#include "font.h" -#include "text.h" +#include +#include +#include +#include + +#include // FIXME: BM_DRAWPIXEL #include -/*! - * Flags degli stili algoritmici +/** + * ANSI escape sequences flag: true for ESC state on. * - * La routine di rendering del testo e' in grado di applicare - * delle semplici trasformazioni al font interno per generare - * automaticamente degli stili predefiniti (bold, italic, - * underline) a partire dal set di caratteri plain. + * \todo Move to Bitmap.flags. */ -static uint8_t text_styles; - -/*! ANSI escape sequences flag: true for ESC state on */ static bool ansi_mode = false; +/** + * Move (imaginary) cursor to coordinates specified. + */ +void text_setCoord(struct Bitmap *bm, int x, int y) +{ + bm->penX = x; + bm->penY = y; +} -/*! + +/** * Move (imaginary) cursor to column and row specified. * Next text write will start a that row and col. */ -void text_moveto(struct Bitmap *bm, int row, int col) +void text_moveTo(struct Bitmap *bm, int row, int col) { ASSERT(col >= 0); - ASSERT(col < bm->width / FONT_WIDTH); + ASSERT(col < bm->width / bm->font->width); ASSERT(row >= 0); - ASSERT(row < bm->height / FONT_HEIGHT); + ASSERT(row < bm->height / bm->font->height); - bm->penX = col * FONT_WIDTH; - bm->penY = row * FONT_HEIGHT; + text_setCoord(bm, col * bm->font->width, row * bm->font->height); } -/*! - * Move (imaginary) cursor to coordinates specified. - */ -void text_setcoord(struct Bitmap *bm, int x, int y) -{ - bm->penX = x; - bm->penY = y; -} - - -/*! - * Render char \a c on Bitmap \a bm +/** + * Render char \a c on Bitmap \a bm. */ static int text_putglyph(char c, struct Bitmap *bm) { const uint8_t * PROGMEM glyph; /* font is in progmem */ - uint8_t glyph_width; - uint8_t i; - uint8_t *buf; - - /* - * Il carattere da stampare viene usato come indice per prelevare - * la prima colonna di dots del glyph all'interno del font. - */ - glyph = font + (((unsigned char)c) * FONT_WIDTH); - glyph_width = FONT_WIDTH; + uint8_t glyph_width, glyph_height, glyph_height_bytes; + unsigned char index = (unsigned char)c; - if (text_styles & STYLEF_CONDENSED) - --glyph_width; + /* Check for out of range char and replace with '?' or first char in font. */ + if (UNLIKELY(!FONT_HAS_GLYPH(bm->font, index))) + { + kprintf("Illegal char '%c' (0x%02x)\n", index, index); + if (FONT_HAS_GLYPH(bm->font, '?')) + index = '?'; + else + index = bm->font->first; + } - if (text_styles & STYLEF_EXPANDED) - glyph_width *= 2; + /* Make character relative to font start */ + index -= bm->font->first; - /* The y coord is rounded at multiples of 8 for simplicity */ - bm->penY &= ~((coord_t)7); + glyph_height = bm->font->height; + // FIXME: for vertical fonts only + glyph_height_bytes = (glyph_height + 7) / 8; - /* Check if glyph to write fits in the bitmap */ - if ((bm->penX < 0) || (bm->penX + glyph_width > bm->width) || - (bm->penY < 0) || (bm->penY + FONT_HEIGHT > bm->height)) + if (bm->font->offset) { - DB(kprintf("bad coords x=%d y=%d\n", bm->penX, bm->penY);) - return 0; + /* Proportional font */ + glyph_width = bm->font->widths[index]; /* TODO: optimize away */ + glyph = bm->font->glyph + bm->font->offset[index]; + } + else + { + /* + * Fixed-width font: compute the first column of pixels + * of the selected glyph using the character code to index + * the glyph array. + */ + glyph_width = bm->font->width; + + //For horizontal fonts + //glyph = bm->font->glyph + index * (((glyph_width + 7) / 8) * glyph_height); + glyph = bm->font->glyph + index * glyph_height_bytes * glyph_width; } - /* Locate position where to write in the raster */ - buf = bm->raster + bm->penY / 8 * bm->width + bm->penX; - - bm->penX += glyph_width; - - /* If some styles are set */ - if (text_styles) + /* Slow path for styled glyphs */ + if (UNLIKELY(bm->styles)) { - uint8_t prev_dots = 0, italic_prev_dots = 0, new_dots; + uint8_t styles = bm->styles; + uint8_t prev_dots = 0, italic_prev_dots = 0; uint8_t dots; - - /* Per ogni colonna di dot del glyph... */ - for (i = 0; i < glyph_width; ++i) + uint8_t row, col, row_bit; + + /* + * To avoid repeating clipping and other expensive computations, + * we cluster calls to gfx_blitRaster() using a small buffer. + */ + #define CONFIG_TEXT_RENDER_OPTIMIZE 1 + #if CONFIG_TEXT_RENDER_OPTIMIZE + #define RENDER_BUF_WIDTH 12 + #define RENDER_BUF_HEIGHT 8 + uint8_t render_buf[RAST_SIZE(RENDER_BUF_WIDTH, RENDER_BUF_HEIGHT)]; + uint8_t render_xpos = 0; + #endif + + /* This style alone could be handled by the fast path too */ + if (bm->styles & STYLEF_CONDENSED) + --glyph_width; + + if (bm->styles & STYLEF_EXPANDED) + glyph_width *= 2; + + for (row = 0, row_bit = 0; row < glyph_height_bytes; ++row, row_bit += 8) { - dots = PGM_READ_CHAR(glyph); - - /* Advance to next column in glyph. - * Expand: advances only once every two columns - */ - if (!(text_styles & STYLEF_EXPANDED) || (i & 1)) - glyph++; - - /* Italic: get lower 4 dots from previous column */ - if (text_styles & STYLEF_ITALIC) - { - new_dots = dots; - dots = (dots & 0xF0) | italic_prev_dots; - italic_prev_dots = new_dots & 0x0F; - } - - /* Bold: "or" pixels with the previous column */ - if (text_styles & STYLEF_BOLD) + /* For each dot column in the glyph... */ + for (col = 0; col < glyph_width; ++col) { - new_dots = dots; - dots |= prev_dots; - prev_dots = new_dots; + uint8_t src_col = col; + + /* Expanded style: advances only once every two columns. */ + if (styles & STYLEF_EXPANDED) + src_col /= 2; + + /* Fetch a column of dots from glyph. */ + dots = PGM_READ_CHAR(RAST_ADDR(glyph, src_col, row_bit, glyph_width)); + + /* Italic: get lower 4 dots from previous column */ + if (styles & STYLEF_ITALIC) + { + uint8_t new_dots = dots; + dots = (dots & 0xF0) | italic_prev_dots; + italic_prev_dots = new_dots & 0x0F; + } + + /* Bold: "or" pixels with the previous column */ + if (styles & STYLEF_BOLD) + { + uint8_t new_dots = dots; + dots |= prev_dots; + prev_dots = new_dots; + } + + /* Underlined: turn on base pixel */ + if ((styles & STYLEF_UNDERLINE) + && (row == glyph_height_bytes - 1)) + dots |= (1 << (glyph_height - row_bit - 1)); + + /* Inverted: invert pixels */ + if (styles & STYLEF_INVERT) + dots = ~dots; + + /* Output dots */ + #if CONFIG_TEXT_RENDER_OPTIMIZE + render_buf[render_xpos++] = dots; + if (render_xpos == RENDER_BUF_WIDTH) + { + gfx_blitRaster(bm, bm->penX + col - render_xpos + 1, bm->penY + row_bit, + render_buf, render_xpos, + MIN((uint8_t)RENDER_BUF_HEIGHT, (uint8_t)(glyph_height - row_bit)), + RENDER_BUF_WIDTH); + render_xpos = 0; + } + #else + gfx_blitRaster(bm, bm->penX + col, bm->penY + row_bit, + &dots, 1, MIN((uint8_t)8, glyph_height - row_bit), 1); + #endif } - /* Underlined: turn on base pixel */ - if (text_styles & STYLEF_UNDERLINE) - dots |= 0x80; - - /* Inverted: invert pixels */ - if (text_styles & STYLEF_INVERT) - dots = ~dots; - - /* Output dots */ - *buf++ = dots; + #if CONFIG_TEXT_RENDER_OPTIMIZE + /* Flush out rest of render buffer */ + if (render_xpos != 0) + { + gfx_blitRaster(bm, bm->penX + col - render_xpos, bm->penY + row_bit, + render_buf, render_xpos, + MIN((uint8_t)RENDER_BUF_HEIGHT, (uint8_t)(glyph_height - row_bit)), + RENDER_BUF_WIDTH); + render_xpos = 0; + } + #endif } } - else /* No style: fast vanilla copy of glyph to line buffer */ - while (glyph_width--) - *buf++ = PGM_READ_CHAR(glyph++); + else + { + /* No style: fast vanilla copy of glyph to bitmap */ + gfx_blitRaster(bm, bm->penX, bm->penY, glyph, glyph_width, glyph_height, glyph_width); + } + + /* Update current pen position */ + bm->penX += glyph_width; return c; } -/*! +/** * Render char \c c, with (currently) limited ANSI escapes * emulation support and '\n' for newline. */ int text_putchar(char c, struct Bitmap *bm) { /* Handle ANSI escape sequences */ - if (ansi_mode) + if (UNLIKELY(ansi_mode)) { switch (c) { @@ -227,7 +321,7 @@ int text_putchar(char c, struct Bitmap *bm) gfx_bitmapClear(bm); bm->penX = 0; bm->penY = 0; - text_style(0, STYLEF_MASK); + text_style(bm, 0, STYLEF_MASK); break; DB(default: kprintf("Unknown ANSI esc code: %x\n", c);) @@ -240,9 +334,9 @@ int text_putchar(char c, struct Bitmap *bm) } else if (c == '\n') /* Go one line down on a line-feed */ { - if (bm->penY + FONT_HEIGHT < bm->height) + if (bm->penY + bm->font->height < bm->height) { - bm->penY += FONT_HEIGHT; + bm->penY += bm->font->height; bm->penX = 0; } } @@ -254,7 +348,7 @@ int text_putchar(char c, struct Bitmap *bm) } -/*! +/** * Clear the screen and reset cursor position */ void text_clear(struct Bitmap *bmp) @@ -264,35 +358,36 @@ void text_clear(struct Bitmap *bmp) } -void text_clearLine(struct Bitmap *bmp, int line) +void text_clearLine(struct Bitmap *bm, int line) { - gfx_rectClear(bmp, 0, line * FONT_HEIGHT, bmp->width, (line + 1) * FONT_HEIGHT); + gfx_rectClear(bm, 0, line * bm->font->height, bm->width, (line + 1) * bm->font->height); } -/*! +/** * Set/clear algorithmic font style bits. * + * \param bm Pointer to Bitmap to affect. * \param flags Style flags to set * \param mask Mask of flags to modify * \return Old style flags * * Examples: * Turn on bold, leave other styles alone - * \code prt_style(STYLEF_BOLD, STYLEF_BOLD); \endcode + * \code text_style(bm, STYLEF_BOLD, STYLEF_BOLD); \endcode * * Turn off bold and turn on italic, leave others as they are - * \code prt_style(STYLEF_ITALIC, STYLEF_BOLD | STYLEF_ITALIC); \endcode + * \code text_style(bm, STYLEF_ITALIC, STYLEF_BOLD | STYLEF_ITALIC); \endcode * * Query current style without chaning it - * \code style = prt_style(0, 0); \endcode + * \code style = text_style(bm, 0, 0); \endcode * * Reset all styles (plain text) - * \code prt_style(0, STYLE_MASK); \endcode + * \code text_style(bm, 0, STYLE_MASK); \endcode */ -uint8_t text_style(uint8_t flags, uint8_t mask) +uint8_t text_style(struct Bitmap *bm, uint8_t flags, uint8_t mask) { - uint8_t old = text_styles; - text_styles = (text_styles & ~mask) | flags; + uint8_t old = bm->styles; + bm->styles = (bm->styles & ~mask) | flags; return old; }