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