00001
00040 #include <gfx/gfx.h>
00041 #include <gfx/font.h>
00042 #include <gfx/text.h>
00043
00044 #include <gfx/gfx_p.h>
00045
00046 #include <cfg/debug.h>
00047
00048
00054 static bool ansi_mode = false;
00055
00059 void text_setCoord(struct Bitmap *bm, int x, int y)
00060 {
00061 bm->penX = x;
00062 bm->penY = y;
00063 }
00064
00065
00070 void text_moveTo(struct Bitmap *bm, int row, int col)
00071 {
00072 ASSERT(col >= 0);
00073 ASSERT(col < bm->width / bm->font->width);
00074 ASSERT(row >= 0);
00075 ASSERT(row < bm->height / bm->font->height);
00076
00077 text_setCoord(bm, col * bm->font->width, row * bm->font->height);
00078 }
00079
00080
00084 static int text_putglyph(char c, struct Bitmap *bm)
00085 {
00086 const uint8_t * PROGMEM glyph;
00087 uint8_t glyph_width, glyph_height, glyph_height_bytes;
00088 unsigned char index = (unsigned char)c;
00089
00090
00091 if (UNLIKELY(!FONT_HAS_GLYPH(bm->font, index)))
00092 {
00093 kprintf("Illegal char '%c' (0x%02x)\n", index, index);
00094 if (FONT_HAS_GLYPH(bm->font, '?'))
00095 index = '?';
00096 else
00097 index = bm->font->first;
00098 }
00099
00100
00101 index -= bm->font->first;
00102
00103 glyph_height = bm->font->height;
00104
00105 glyph_height_bytes = (glyph_height + 7) / 8;
00106
00107 if (bm->font->offset)
00108 {
00109
00110 glyph_width = bm->font->widths[index];
00111 glyph = bm->font->glyph + bm->font->offset[index];
00112 }
00113 else
00114 {
00115
00116
00117
00118
00119
00120 glyph_width = bm->font->width;
00121
00122
00123
00124 glyph = bm->font->glyph + index * glyph_height_bytes * glyph_width;
00125 }
00126
00127
00128 if (UNLIKELY(bm->styles))
00129 {
00130 uint8_t styles = bm->styles;
00131 uint8_t prev_dots = 0, italic_prev_dots = 0;
00132 uint8_t dots;
00133 uint8_t row, col, row_bit;
00134
00135
00136
00137
00138
00139 #define CONFIG_TEXT_RENDER_OPTIMIZE 1
00140 #if CONFIG_TEXT_RENDER_OPTIMIZE
00141 #define RENDER_BUF_WIDTH 12
00142 #define RENDER_BUF_HEIGHT 8
00143 uint8_t render_buf[RAST_SIZE(RENDER_BUF_WIDTH, RENDER_BUF_HEIGHT)];
00144 uint8_t render_xpos = 0;
00145 #endif
00146
00147
00148 if (bm->styles & STYLEF_CONDENSED)
00149 --glyph_width;
00150
00151 if (bm->styles & STYLEF_EXPANDED)
00152 glyph_width *= 2;
00153
00154 for (row = 0, row_bit = 0; row < glyph_height_bytes; ++row, row_bit += 8)
00155 {
00156
00157 for (col = 0; col < glyph_width; ++col)
00158 {
00159 uint8_t src_col = col;
00160
00161
00162 if (styles & STYLEF_EXPANDED)
00163 src_col /= 2;
00164
00165
00166 dots = PGM_READ_CHAR(RAST_ADDR(glyph, src_col, row_bit, glyph_width));
00167
00168
00169 if (styles & STYLEF_ITALIC)
00170 {
00171 uint8_t new_dots = dots;
00172 dots = (dots & 0xF0) | italic_prev_dots;
00173 italic_prev_dots = new_dots & 0x0F;
00174 }
00175
00176
00177 if (styles & STYLEF_BOLD)
00178 {
00179 uint8_t new_dots = dots;
00180 dots |= prev_dots;
00181 prev_dots = new_dots;
00182 }
00183
00184
00185 if ((styles & STYLEF_UNDERLINE)
00186 && (row == glyph_height_bytes - 1))
00187 dots |= (1 << (glyph_height - row_bit - 1));
00188
00189
00190 if (styles & STYLEF_INVERT)
00191 dots = ~dots;
00192
00193
00194 #if CONFIG_TEXT_RENDER_OPTIMIZE
00195 render_buf[render_xpos++] = dots;
00196 if (render_xpos == RENDER_BUF_WIDTH)
00197 {
00198 gfx_blitRaster(bm, bm->penX + col - render_xpos + 1, bm->penY + row_bit,
00199 render_buf, render_xpos,
00200 MIN((uint8_t)RENDER_BUF_HEIGHT, (uint8_t)(glyph_height - row_bit)),
00201 RENDER_BUF_WIDTH);
00202 render_xpos = 0;
00203 }
00204 #else
00205 gfx_blitRaster(bm, bm->penX + col, bm->penY + row_bit,
00206 &dots, 1, MIN((uint8_t)8, glyph_height - row_bit), 1);
00207 #endif
00208 }
00209
00210 #if CONFIG_TEXT_RENDER_OPTIMIZE
00211
00212 if (render_xpos != 0)
00213 {
00214 gfx_blitRaster(bm, bm->penX + col - render_xpos, bm->penY + row_bit,
00215 render_buf, render_xpos,
00216 MIN((uint8_t)RENDER_BUF_HEIGHT, (uint8_t)(glyph_height - row_bit)),
00217 RENDER_BUF_WIDTH);
00218 render_xpos = 0;
00219 }
00220 #endif
00221 }
00222 }
00223 else
00224 {
00225
00226 gfx_blitRaster(bm, bm->penX, bm->penY, glyph, glyph_width, glyph_height, glyph_width);
00227 }
00228
00229
00230 bm->penX += glyph_width;
00231
00232 return c;
00233 }
00234
00235
00240 int text_putchar(char c, struct Bitmap *bm)
00241 {
00242
00243 if (UNLIKELY(ansi_mode))
00244 {
00245 switch (c)
00246 {
00247 case ANSI_ESC_CLEARSCREEN:
00248 gfx_bitmapClear(bm);
00249 bm->penX = 0;
00250 bm->penY = 0;
00251 text_style(bm, 0, STYLEF_MASK);
00252 break;
00253 DB(default:
00254 kprintf("Unknown ANSI esc code: %x\n", c);)
00255 }
00256 ansi_mode = false;
00257 }
00258 else if (c == '\033')
00259 {
00260 ansi_mode = true;
00261 }
00262 else if (c == '\n')
00263 {
00264 if (bm->penY + bm->font->height < bm->height)
00265 {
00266 bm->penY += bm->font->height;
00267 bm->penX = 0;
00268 }
00269 }
00270 else
00271 {
00272 text_putglyph(c, bm);
00273 }
00274 return c;
00275 }
00276
00277
00281 void text_clear(struct Bitmap *bmp)
00282 {
00283 text_putchar('\x1b', bmp);
00284 text_putchar('c', bmp);
00285 }
00286
00287
00288 void text_clearLine(struct Bitmap *bm, int line)
00289 {
00290 gfx_rectClear(bm, 0, line * bm->font->height, bm->width, (line + 1) * bm->font->height);
00291 }
00292
00293
00315 uint8_t text_style(struct Bitmap *bm, uint8_t flags, uint8_t mask)
00316 {
00317 uint8_t old = bm->styles;
00318 bm->styles = (bm->styles & ~mask) | flags;
00319 return old;
00320 }