text.c

Go to the documentation of this file.
00001 
00041 /*#*
00042  *#* $Log$
00043  *#* Revision 1.13  2006/07/19 12:56:26  bernie
00044  *#* Convert to new Doxygen style.
00045  *#*
00046  *#* Revision 1.12  2006/05/25 23:35:22  bernie
00047  *#* Implement correct and faster clipping for algo text.
00048  *#*
00049  *#* Revision 1.11  2006/05/15 07:21:06  bernie
00050  *#* Doxygen fix.
00051  *#*
00052  *#* Revision 1.10  2006/04/27 05:39:23  bernie
00053  *#* Enhance text rendering to arbitrary x,y coords.
00054  *#*
00055  *#* Revision 1.9  2006/04/11 00:08:24  bernie
00056  *#* text_offset(): New function, but I'm not quite confident with the design.
00057  *#*
00058  *#* Revision 1.8  2006/03/22 09:50:37  bernie
00059  *#* Use the same format for fonts and rasters.
00060  *#*
00061  *#* Revision 1.7  2006/03/20 17:51:55  bernie
00062  *#* Cleanups.
00063  *#*
00064  *#* Revision 1.6  2006/03/13 02:05:54  bernie
00065  *#* Mark slow paths as UNLIKELY.
00066  *#*
00067  *#* Revision 1.5  2006/03/07 22:18:04  bernie
00068  *#* Correctly compute text width for prop fonts; Make styles a per-bitmap attribute.
00069  *#*
00070  *#* Revision 1.4  2006/02/15 09:10:15  bernie
00071  *#* Implement prop fonts; Fix algo styles.
00072  *#*
00073  *#* Revision 1.3  2006/02/10 12:31:55  bernie
00074  *#* Add multiple font support in bitmaps.
00075  *#*
00076  *#* Revision 1.2  2005/11/04 18:17:45  bernie
00077  *#* Fix header guards and includes for new location of gfx module.
00078  *#*
00079  *#* Revision 1.1  2005/11/04 18:11:35  bernie
00080  *#* Move graphics stuff from mware/ to gfx/.
00081  *#*
00082  *#* Revision 1.13  2005/11/04 16:20:02  bernie
00083  *#* Fix reference to README.devlib in header.
00084  *#*
00085  *#* Revision 1.12  2005/04/11 19:10:28  bernie
00086  *#* Include top-level headers from cfg/ subdir.
00087  *#*
00088  *#* Revision 1.11  2005/01/20 18:46:31  aleph
00089  *#* Fix progmem includes.
00090  *#*
00091  *#* Revision 1.10  2005/01/08 09:20:12  bernie
00092  *#* Really make it work on both architectures.
00093  *#*
00094  *#* Revision 1.9  2004/12/31 16:44:29  bernie
00095  *#* Sanitize for non-Harvard processors.
00096  *#*
00097  *#* Revision 1.8  2004/11/16 21:16:28  bernie
00098  *#* Update to new naming scheme in mware/gfx.c.
00099  *#*
00100  *#* Revision 1.7  2004/09/20 03:28:28  bernie
00101  *#* Fix header.
00102  *#*
00103  *#* Revision 1.6  2004/09/14 20:57:15  bernie
00104  *#* Use debug.h instead of kdebug.h.
00105  *#*
00106  *#* Revision 1.5  2004/09/06 21:51:26  bernie
00107  *#* Extend interface to allow any algorithmic style.
00108  *#*
00109  *#* Revision 1.2  2004/06/03 11:27:09  bernie
00110  *#* Add dual-license information.
00111  *#*
00112  *#* Revision 1.1  2004/05/23 15:43:16  bernie
00113  *#* Import mware modules.
00114  *#*
00115  *#* Revision 1.17  2004/05/15 16:57:01  aleph
00116  *#* Fixes for non-DEBUG build
00117  *#*
00118  *#* Revision 1.16  2004/04/03 20:42:49  aleph
00119  *#* Add text_clear()
00120  *#*
00121  *#* Revision 1.15  2004/03/24 15:03:45  bernie
00122  *#* Use explicit include paths; clean Doxygen comments
00123  *#*
00124  *#* Revision 1.14  2004/03/19 16:52:28  bernie
00125  *#* Move printf() like functions from text.c to text_format.c and add PROGMEM versions.
00126  *#*
00127  *#* Revision 1.13  2004/03/17 18:23:32  bernie
00128  *#* Oops.
00129  *#*
00130  *#* Revision 1.12  2004/03/17 18:03:22  bernie
00131  *#* Make diagnostic message shorter
00132  *#*
00133  *#* Revision 1.11  2004/03/13 22:52:54  aleph
00134  *#* documentation fixes
00135  *#*/
00136 
00137 #include <gfx/gfx.h>
00138 #include <gfx/font.h>
00139 #include <gfx/text.h>
00140 #include <gfx/text.h>
00141 
00142 #include <gfx/gfx_p.h> // FIXME: BM_DRAWPIXEL
00143 
00144 #include <cfg/debug.h>
00145 
00146 
00152 static bool ansi_mode = false;
00153 
00157 void text_setCoord(struct Bitmap *bm, int x, int y)
00158 {
00159     bm->penX = x;
00160     bm->penY = y;
00161 }
00162 
00163 
00168 void text_moveTo(struct Bitmap *bm, int row, int col)
00169 {
00170     ASSERT(col >= 0);
00171     ASSERT(col < bm->width / bm->font->width);
00172     ASSERT(row >= 0);
00173     ASSERT(row < bm->height / bm->font->height);
00174 
00175     text_setCoord(bm, col * bm->font->width, row * bm->font->height);
00176 }
00177 
00178 
00182 static int text_putglyph(char c, struct Bitmap *bm)
00183 {
00184     const uint8_t * PROGMEM glyph;  /* font is in progmem */
00185     uint8_t glyph_width, glyph_height, glyph_height_bytes;
00186     unsigned char index = (unsigned char)c;
00187 
00188     /* Check for out of range char and replace with '?' or first char in font. */
00189     if (UNLIKELY(!FONT_HAS_GLYPH(bm->font, index)))
00190     {
00191         kprintf("Illegal char '%c' (0x%02x)\n", index, index);
00192         if (FONT_HAS_GLYPH(bm->font, '?'))
00193             index = '?';
00194         else
00195             index = bm->font->first;
00196     }
00197 
00198     /* Make character relative to font start */
00199     index -= bm->font->first;
00200 
00201     glyph_height = bm->font->height;
00202     // FIXME: for vertical fonts only
00203     glyph_height_bytes = (glyph_height + 7) / 8;
00204 
00205     if (bm->font->offset)
00206     {
00207         /* Proportional font */
00208         glyph_width = bm->font->widths[index]; /* TODO: optimize away */
00209         glyph = bm->font->glyph + bm->font->offset[index];
00210     }
00211     else
00212     {
00213         /*
00214          * Fixed-width font: compute the first column of pixels
00215          * of the selected glyph using the character code to index
00216          * the glyph array.
00217          */
00218         glyph_width = bm->font->width;
00219 
00220         //For horizontal fonts
00221         //glyph = bm->font->glyph + index * (((glyph_width + 7) / 8) * glyph_height);
00222         glyph = bm->font->glyph + index * glyph_height_bytes * glyph_width;
00223     }
00224 
00225     /* Slow path for styled glyphs */
00226     if (UNLIKELY(bm->styles))
00227     {
00228         uint8_t styles = bm->styles;
00229         uint8_t prev_dots = 0, italic_prev_dots = 0;
00230         uint8_t dots;
00231         uint8_t row, col, row_bit;
00232 
00233         /*
00234          * To avoid repeating clipping and other expensive computations,
00235          * we cluster calls to gfx_blitRaster() using a small buffer.
00236          */
00237         #define CONFIG_TEXT_RENDER_OPTIMIZE 1
00238         #if CONFIG_TEXT_RENDER_OPTIMIZE
00239             #define RENDER_BUF_WIDTH 12
00240             #define RENDER_BUF_HEIGHT 8
00241             uint8_t render_buf[RAST_SIZE(RENDER_BUF_WIDTH, RENDER_BUF_HEIGHT)];
00242             uint8_t render_xpos = 0;
00243         #endif
00244 
00245         /* This style alone could be handled by the fast path too */
00246         if (bm->styles & STYLEF_CONDENSED)
00247             --glyph_width;
00248 
00249         if (bm->styles & STYLEF_EXPANDED)
00250             glyph_width *= 2;
00251 
00252         for (row = 0, row_bit = 0; row < glyph_height_bytes; ++row, row_bit += 8)
00253         {
00254             /* For each dot column in the glyph... */
00255             for (col = 0; col < glyph_width; ++col)
00256             {
00257                 uint8_t src_col = col;
00258 
00259                 /* Expanded style: advances only once every two columns. */
00260                 if (styles & STYLEF_EXPANDED)
00261                     src_col /= 2;
00262 
00263                 /* Fetch a column of dots from glyph. */
00264                 dots = PGM_READ_CHAR(RAST_ADDR(glyph, src_col, row_bit, glyph_width));
00265 
00266                 /* Italic: get lower 4 dots from previous column */
00267                 if (styles & STYLEF_ITALIC)
00268                 {
00269                     uint8_t new_dots = dots;
00270                     dots = (dots & 0xF0) | italic_prev_dots;
00271                     italic_prev_dots = new_dots & 0x0F;
00272                 }
00273 
00274                 /* Bold: "or" pixels with the previous column */
00275                 if (styles & STYLEF_BOLD)
00276                 {
00277                     uint8_t new_dots = dots;
00278                     dots |= prev_dots;
00279                     prev_dots = new_dots;
00280                 }
00281 
00282                 /* Underlined: turn on base pixel */
00283                 if ((styles & STYLEF_UNDERLINE)
00284                     && (row == glyph_height_bytes - 1))
00285                     dots |= (1 << (glyph_height - row_bit - 1));
00286 
00287                 /* Inverted: invert pixels */
00288                 if (styles & STYLEF_INVERT)
00289                     dots = ~dots;
00290 
00291                 /* Output dots */
00292                 #if CONFIG_TEXT_RENDER_OPTIMIZE
00293                     render_buf[render_xpos++] = dots;
00294                     if (render_xpos == RENDER_BUF_WIDTH)
00295                     {
00296                         gfx_blitRaster(bm, bm->penX + col - render_xpos + 1, bm->penY + row_bit,
00297                             render_buf, render_xpos,
00298                             MIN((uint8_t)RENDER_BUF_HEIGHT, (uint8_t)(glyph_height - row_bit)),
00299                             RENDER_BUF_WIDTH);
00300                         render_xpos = 0;
00301                     }
00302                 #else
00303                     gfx_blitRaster(bm, bm->penX + col, bm->penY + row_bit,
00304                         &dots, 1, MIN((uint8_t)8, glyph_height - row_bit), 1);
00305                 #endif
00306             }
00307 
00308             #if CONFIG_TEXT_RENDER_OPTIMIZE
00309                 /* Flush out rest of render buffer */
00310                 if (render_xpos != 0)
00311                 {
00312                     gfx_blitRaster(bm, bm->penX + col - render_xpos, bm->penY + row_bit,
00313                         render_buf, render_xpos,
00314                         MIN((uint8_t)RENDER_BUF_HEIGHT, (uint8_t)(glyph_height - row_bit)),
00315                         RENDER_BUF_WIDTH);
00316                     render_xpos = 0;
00317                 }
00318             #endif
00319         }
00320     }
00321     else
00322     {
00323         /* No style: fast vanilla copy of glyph to bitmap */
00324         gfx_blitRaster(bm, bm->penX, bm->penY, glyph, glyph_width, glyph_height, glyph_width);
00325     }
00326 
00327     /* Update current pen position */
00328     bm->penX += glyph_width;
00329 
00330     return c;
00331 }
00332 
00333 
00338 int text_putchar(char c, struct Bitmap *bm)
00339 {
00340     /* Handle ANSI escape sequences */
00341     if (UNLIKELY(ansi_mode))
00342     {
00343         switch (c)
00344         {
00345         case ANSI_ESC_CLEARSCREEN:
00346             gfx_bitmapClear(bm);
00347             bm->penX = 0;
00348             bm->penY = 0;
00349             text_style(bm, 0, STYLEF_MASK);
00350             break;
00351         DB(default:
00352             kprintf("Unknown ANSI esc code: %x\n", c);)
00353         }
00354         ansi_mode = false;
00355     }
00356     else if (c == '\033')  /* Enter ANSI ESC mode */
00357     {
00358         ansi_mode = true;
00359     }
00360     else if (c == '\n')  /* Go one line down on a line-feed */
00361     {
00362         if (bm->penY + bm->font->height < bm->height)
00363         {
00364             bm->penY += bm->font->height;
00365             bm->penX = 0;
00366         }
00367     }
00368     else
00369     {
00370         text_putglyph(c, bm);
00371     }
00372     return c;
00373 }
00374 
00375 
00379 void text_clear(struct Bitmap *bmp)
00380 {
00381     text_putchar('\x1b', bmp);
00382     text_putchar('c', bmp);
00383 }
00384 
00385 
00386 void text_clearLine(struct Bitmap *bm, int line)
00387 {
00388     gfx_rectClear(bm, 0, line * bm->font->height, bm->width, (line + 1) * bm->font->height);
00389 }
00390 
00391 
00413 uint8_t text_style(struct Bitmap *bm, uint8_t flags, uint8_t mask)
00414 {
00415     uint8_t old = bm->styles;
00416     bm->styles = (bm->styles & ~mask) | flags;
00417     return old;
00418 }