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>
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;
00089 uint8_t glyph_width, glyph_height, glyph_height_bytes;
00090 unsigned char index = (unsigned char)c;
00091
00092
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
00103 index -= bm->font->first;
00104
00105 glyph_height = bm->font->height;
00106
00107 glyph_height_bytes = (glyph_height + 7) / 8;
00108
00109 if (bm->font->offset)
00110 {
00111
00112 glyph_width = bm->font->widths[index];
00113 glyph = bm->font->glyph + bm->font->offset[index];
00114 }
00115 else
00116 {
00117
00118
00119
00120
00121
00122 glyph_width = bm->font->width;
00123
00124
00125
00126 glyph = bm->font->glyph + index * glyph_height_bytes * glyph_width;
00127 }
00128
00129
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
00139
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
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
00159 for (col = 0; col < glyph_width; ++col)
00160 {
00161 uint8_t src_col = col;
00162
00163
00164 if (styles & STYLEF_EXPANDED)
00165 src_col /= 2;
00166
00167
00168 dots = PGM_READ_CHAR(RAST_ADDR(glyph, src_col, row_bit, glyph_width));
00169
00170
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
00179 if (styles & STYLEF_BOLD)
00180 {
00181 uint8_t new_dots = dots;
00182 dots |= prev_dots;
00183 prev_dots = new_dots;
00184 }
00185
00186
00187 if ((styles & STYLEF_UNDERLINE)
00188 && (row == glyph_height_bytes - 1))
00189 dots |= (1 << (glyph_height - row_bit - 1));
00190
00191
00192 if (styles & STYLEF_INVERT)
00193 dots = ~dots;
00194
00195
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
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
00228 gfx_blitRaster(bm, bm->penX, bm->penY, glyph, glyph_width, glyph_height, glyph_width);
00229 }
00230
00231
00232 bm->penX += glyph_width;
00233
00234 return c;
00235 }
00236
00237
00242 int text_putchar(char c, struct Bitmap *bm)
00243 {
00244
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')
00261 {
00262 ansi_mode = true;
00263 }
00264 else if (c == '\n')
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 }