text.c

Go to the documentation of this file.
00001 
00041 #include <gfx/gfx.h>
00042 #include <gfx/font.h>
00043 #include <gfx/text.h>
00044 #include <gfx/text.h>
00045 
00046 #include <gfx/gfx_p.h> // FIXME: BM_DRAWPIXEL
00047 
00048 #include <cfg/debug.h>
00049 
00050 
00056 static bool ansi_mode = false;
00057 
00061 void text_setCoord(struct Bitmap *bm, int x, int y)
00062 {
00063     bm->penX = x;
00064     bm->penY = y;
00065 }
00066 
00067 
00072 void text_moveTo(struct Bitmap *bm, int row, int col)
00073 {
00074     ASSERT(col >= 0);
00075     ASSERT(col < bm->width / bm->font->width);
00076     ASSERT(row >= 0);
00077     ASSERT(row < bm->height / bm->font->height);
00078 
00079     text_setCoord(bm, col * bm->font->width, row * bm->font->height);
00080 }
00081 
00082 
00086 static int text_putglyph(char c, struct Bitmap *bm)
00087 {
00088     const uint8_t * PROGMEM glyph;  /* font is in progmem */
00089     uint8_t glyph_width, glyph_height, glyph_height_bytes;
00090     unsigned char index = (unsigned char)c;
00091 
00092     /* Check for out of range char and replace with '?' or first char in font. */
00093     if (UNLIKELY(!FONT_HAS_GLYPH(bm->font, index)))
00094     {
00095         kprintf("Illegal char '%c' (0x%02x)\n", index, index);
00096         if (FONT_HAS_GLYPH(bm->font, '?'))
00097             index = '?';
00098         else
00099             index = bm->font->first;
00100     }
00101 
00102     /* Make character relative to font start */
00103     index -= bm->font->first;
00104 
00105     glyph_height = bm->font->height;
00106     // FIXME: for vertical fonts only
00107     glyph_height_bytes = (glyph_height + 7) / 8;
00108 
00109     if (bm->font->offset)
00110     {
00111         /* Proportional font */
00112         glyph_width = bm->font->widths[index]; /* TODO: optimize away */
00113         glyph = bm->font->glyph + bm->font->offset[index];
00114     }
00115     else
00116     {
00117         /*
00118          * Fixed-width font: compute the first column of pixels
00119          * of the selected glyph using the character code to index
00120          * the glyph array.
00121          */
00122         glyph_width = bm->font->width;
00123 
00124         //For horizontal fonts
00125         //glyph = bm->font->glyph + index * (((glyph_width + 7) / 8) * glyph_height);
00126         glyph = bm->font->glyph + index * glyph_height_bytes * glyph_width;
00127     }
00128 
00129     /* Slow path for styled glyphs */
00130     if (UNLIKELY(bm->styles))
00131     {
00132         uint8_t styles = bm->styles;
00133         uint8_t prev_dots = 0, italic_prev_dots = 0;
00134         uint8_t dots;
00135         uint8_t row, col, row_bit;
00136 
00137         /*
00138          * To avoid repeating clipping and other expensive computations,
00139          * we cluster calls to gfx_blitRaster() using a small buffer.
00140          */
00141         #define CONFIG_TEXT_RENDER_OPTIMIZE 1
00142         #if CONFIG_TEXT_RENDER_OPTIMIZE
00143             #define RENDER_BUF_WIDTH 12
00144             #define RENDER_BUF_HEIGHT 8
00145             uint8_t render_buf[RAST_SIZE(RENDER_BUF_WIDTH, RENDER_BUF_HEIGHT)];
00146             uint8_t render_xpos = 0;
00147         #endif
00148 
00149         /* This style alone could be handled by the fast path too */
00150         if (bm->styles & STYLEF_CONDENSED)
00151             --glyph_width;
00152 
00153         if (bm->styles & STYLEF_EXPANDED)
00154             glyph_width *= 2;
00155 
00156         for (row = 0, row_bit = 0; row < glyph_height_bytes; ++row, row_bit += 8)
00157         {
00158             /* For each dot column in the glyph... */
00159             for (col = 0; col < glyph_width; ++col)
00160             {
00161                 uint8_t src_col = col;
00162 
00163                 /* Expanded style: advances only once every two columns. */
00164                 if (styles & STYLEF_EXPANDED)
00165                     src_col /= 2;
00166 
00167                 /* Fetch a column of dots from glyph. */
00168                 dots = PGM_READ_CHAR(RAST_ADDR(glyph, src_col, row_bit, glyph_width));
00169 
00170                 /* Italic: get lower 4 dots from previous column */
00171                 if (styles & STYLEF_ITALIC)
00172                 {
00173                     uint8_t new_dots = dots;
00174                     dots = (dots & 0xF0) | italic_prev_dots;
00175                     italic_prev_dots = new_dots & 0x0F;
00176                 }
00177 
00178                 /* Bold: "or" pixels with the previous column */
00179                 if (styles & STYLEF_BOLD)
00180                 {
00181                     uint8_t new_dots = dots;
00182                     dots |= prev_dots;
00183                     prev_dots = new_dots;
00184                 }
00185 
00186                 /* Underlined: turn on base pixel */
00187                 if ((styles & STYLEF_UNDERLINE)
00188                     && (row == glyph_height_bytes - 1))
00189                     dots |= (1 << (glyph_height - row_bit - 1));
00190 
00191                 /* Inverted: invert pixels */
00192                 if (styles & STYLEF_INVERT)
00193                     dots = ~dots;
00194 
00195                 /* Output dots */
00196                 #if CONFIG_TEXT_RENDER_OPTIMIZE
00197                     render_buf[render_xpos++] = dots;
00198                     if (render_xpos == RENDER_BUF_WIDTH)
00199                     {
00200                         gfx_blitRaster(bm, bm->penX + col - render_xpos + 1, bm->penY + row_bit,
00201                             render_buf, render_xpos,
00202                             MIN((uint8_t)RENDER_BUF_HEIGHT, (uint8_t)(glyph_height - row_bit)),
00203                             RENDER_BUF_WIDTH);
00204                         render_xpos = 0;
00205                     }
00206                 #else
00207                     gfx_blitRaster(bm, bm->penX + col, bm->penY + row_bit,
00208                         &dots, 1, MIN((uint8_t)8, glyph_height - row_bit), 1);
00209                 #endif
00210             }
00211 
00212             #if CONFIG_TEXT_RENDER_OPTIMIZE
00213                 /* Flush out rest of render buffer */
00214                 if (render_xpos != 0)
00215                 {
00216                     gfx_blitRaster(bm, bm->penX + col - render_xpos, bm->penY + row_bit,
00217                         render_buf, render_xpos,
00218                         MIN((uint8_t)RENDER_BUF_HEIGHT, (uint8_t)(glyph_height - row_bit)),
00219                         RENDER_BUF_WIDTH);
00220                     render_xpos = 0;
00221                 }
00222             #endif
00223         }
00224     }
00225     else
00226     {
00227         /* No style: fast vanilla copy of glyph to bitmap */
00228         gfx_blitRaster(bm, bm->penX, bm->penY, glyph, glyph_width, glyph_height, glyph_width);
00229     }
00230 
00231     /* Update current pen position */
00232     bm->penX += glyph_width;
00233 
00234     return c;
00235 }
00236 
00237 
00242 int text_putchar(char c, struct Bitmap *bm)
00243 {
00244     /* Handle ANSI escape sequences */
00245     if (UNLIKELY(ansi_mode))
00246     {
00247         switch (c)
00248         {
00249         case ANSI_ESC_CLEARSCREEN:
00250             gfx_bitmapClear(bm);
00251             bm->penX = 0;
00252             bm->penY = 0;
00253             text_style(bm, 0, STYLEF_MASK);
00254             break;
00255         DB(default:
00256             kprintf("Unknown ANSI esc code: %x\n", c);)
00257         }
00258         ansi_mode = false;
00259     }
00260     else if (c == '\033')  /* Enter ANSI ESC mode */
00261     {
00262         ansi_mode = true;
00263     }
00264     else if (c == '\n')  /* Go one line down on a line-feed */
00265     {
00266         if (bm->penY + bm->font->height < bm->height)
00267         {
00268             bm->penY += bm->font->height;
00269             bm->penX = 0;
00270         }
00271     }
00272     else
00273     {
00274         text_putglyph(c, bm);
00275     }
00276     return c;
00277 }
00278 
00279 
00283 void text_clear(struct Bitmap *bmp)
00284 {
00285     text_putchar('\x1b', bmp);
00286     text_putchar('c', bmp);
00287 }
00288 
00289 
00290 void text_clearLine(struct Bitmap *bm, int line)
00291 {
00292     gfx_rectClear(bm, 0, line * bm->font->height, bm->width, (line + 1) * bm->font->height);
00293 }
00294 
00295 
00317 uint8_t text_style(struct Bitmap *bm, uint8_t flags, uint8_t mask)
00318 {
00319     uint8_t old = bm->styles;
00320     bm->styles = (bm->styles & ~mask) | flags;
00321     return old;
00322 }