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