00001
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 #include <gfx/gfx.h>
00138 #include <gfx/font.h>
00139 #include <gfx/text.h>
00140 #include <gfx/text.h>
00141
00142 #include <gfx/gfx_p.h>
00143
00144 #include <cfg/debug.h>
00145
00146
00152 static bool ansi_mode = false;
00153
00157 void text_setCoord(struct Bitmap *bm, int x, int y)
00158 {
00159 bm->penX = x;
00160 bm->penY = y;
00161 }
00162
00163
00168 void text_moveTo(struct Bitmap *bm, int row, int col)
00169 {
00170 ASSERT(col >= 0);
00171 ASSERT(col < bm->width / bm->font->width);
00172 ASSERT(row >= 0);
00173 ASSERT(row < bm->height / bm->font->height);
00174
00175 text_setCoord(bm, col * bm->font->width, row * bm->font->height);
00176 }
00177
00178
00182 static int text_putglyph(char c, struct Bitmap *bm)
00183 {
00184 const uint8_t * PROGMEM glyph;
00185 uint8_t glyph_width, glyph_height, glyph_height_bytes;
00186 unsigned char index = (unsigned char)c;
00187
00188
00189 if (UNLIKELY(!FONT_HAS_GLYPH(bm->font, index)))
00190 {
00191 kprintf("Illegal char '%c' (0x%02x)\n", index, index);
00192 if (FONT_HAS_GLYPH(bm->font, '?'))
00193 index = '?';
00194 else
00195 index = bm->font->first;
00196 }
00197
00198
00199 index -= bm->font->first;
00200
00201 glyph_height = bm->font->height;
00202
00203 glyph_height_bytes = (glyph_height + 7) / 8;
00204
00205 if (bm->font->offset)
00206 {
00207
00208 glyph_width = bm->font->widths[index];
00209 glyph = bm->font->glyph + bm->font->offset[index];
00210 }
00211 else
00212 {
00213
00214
00215
00216
00217
00218 glyph_width = bm->font->width;
00219
00220
00221
00222 glyph = bm->font->glyph + index * glyph_height_bytes * glyph_width;
00223 }
00224
00225
00226 if (UNLIKELY(bm->styles))
00227 {
00228 uint8_t styles = bm->styles;
00229 uint8_t prev_dots = 0, italic_prev_dots = 0;
00230 uint8_t dots;
00231 uint8_t row, col, row_bit;
00232
00233
00234
00235
00236
00237 #define CONFIG_TEXT_RENDER_OPTIMIZE 1
00238 #if CONFIG_TEXT_RENDER_OPTIMIZE
00239 #define RENDER_BUF_WIDTH 12
00240 #define RENDER_BUF_HEIGHT 8
00241 uint8_t render_buf[RAST_SIZE(RENDER_BUF_WIDTH, RENDER_BUF_HEIGHT)];
00242 uint8_t render_xpos = 0;
00243 #endif
00244
00245
00246 if (bm->styles & STYLEF_CONDENSED)
00247 --glyph_width;
00248
00249 if (bm->styles & STYLEF_EXPANDED)
00250 glyph_width *= 2;
00251
00252 for (row = 0, row_bit = 0; row < glyph_height_bytes; ++row, row_bit += 8)
00253 {
00254
00255 for (col = 0; col < glyph_width; ++col)
00256 {
00257 uint8_t src_col = col;
00258
00259
00260 if (styles & STYLEF_EXPANDED)
00261 src_col /= 2;
00262
00263
00264 dots = PGM_READ_CHAR(RAST_ADDR(glyph, src_col, row_bit, glyph_width));
00265
00266
00267 if (styles & STYLEF_ITALIC)
00268 {
00269 uint8_t new_dots = dots;
00270 dots = (dots & 0xF0) | italic_prev_dots;
00271 italic_prev_dots = new_dots & 0x0F;
00272 }
00273
00274
00275 if (styles & STYLEF_BOLD)
00276 {
00277 uint8_t new_dots = dots;
00278 dots |= prev_dots;
00279 prev_dots = new_dots;
00280 }
00281
00282
00283 if ((styles & STYLEF_UNDERLINE)
00284 && (row == glyph_height_bytes - 1))
00285 dots |= (1 << (glyph_height - row_bit - 1));
00286
00287
00288 if (styles & STYLEF_INVERT)
00289 dots = ~dots;
00290
00291
00292 #if CONFIG_TEXT_RENDER_OPTIMIZE
00293 render_buf[render_xpos++] = dots;
00294 if (render_xpos == RENDER_BUF_WIDTH)
00295 {
00296 gfx_blitRaster(bm, bm->penX + col - render_xpos + 1, bm->penY + row_bit,
00297 render_buf, render_xpos,
00298 MIN((uint8_t)RENDER_BUF_HEIGHT, (uint8_t)(glyph_height - row_bit)),
00299 RENDER_BUF_WIDTH);
00300 render_xpos = 0;
00301 }
00302 #else
00303 gfx_blitRaster(bm, bm->penX + col, bm->penY + row_bit,
00304 &dots, 1, MIN((uint8_t)8, glyph_height - row_bit), 1);
00305 #endif
00306 }
00307
00308 #if CONFIG_TEXT_RENDER_OPTIMIZE
00309
00310 if (render_xpos != 0)
00311 {
00312 gfx_blitRaster(bm, bm->penX + col - render_xpos, bm->penY + row_bit,
00313 render_buf, render_xpos,
00314 MIN((uint8_t)RENDER_BUF_HEIGHT, (uint8_t)(glyph_height - row_bit)),
00315 RENDER_BUF_WIDTH);
00316 render_xpos = 0;
00317 }
00318 #endif
00319 }
00320 }
00321 else
00322 {
00323
00324 gfx_blitRaster(bm, bm->penX, bm->penY, glyph, glyph_width, glyph_height, glyph_width);
00325 }
00326
00327
00328 bm->penX += glyph_width;
00329
00330 return c;
00331 }
00332
00333
00338 int text_putchar(char c, struct Bitmap *bm)
00339 {
00340
00341 if (UNLIKELY(ansi_mode))
00342 {
00343 switch (c)
00344 {
00345 case ANSI_ESC_CLEARSCREEN:
00346 gfx_bitmapClear(bm);
00347 bm->penX = 0;
00348 bm->penY = 0;
00349 text_style(bm, 0, STYLEF_MASK);
00350 break;
00351 DB(default:
00352 kprintf("Unknown ANSI esc code: %x\n", c);)
00353 }
00354 ansi_mode = false;
00355 }
00356 else if (c == '\033')
00357 {
00358 ansi_mode = true;
00359 }
00360 else if (c == '\n')
00361 {
00362 if (bm->penY + bm->font->height < bm->height)
00363 {
00364 bm->penY += bm->font->height;
00365 bm->penX = 0;
00366 }
00367 }
00368 else
00369 {
00370 text_putglyph(c, bm);
00371 }
00372 return c;
00373 }
00374
00375
00379 void text_clear(struct Bitmap *bmp)
00380 {
00381 text_putchar('\x1b', bmp);
00382 text_putchar('c', bmp);
00383 }
00384
00385
00386 void text_clearLine(struct Bitmap *bm, int line)
00387 {
00388 gfx_rectClear(bm, 0, line * bm->font->height, bm->width, (line + 1) * bm->font->height);
00389 }
00390
00391
00413 uint8_t text_style(struct Bitmap *bm, uint8_t flags, uint8_t mask)
00414 {
00415 uint8_t old = bm->styles;
00416 bm->styles = (bm->styles & ~mask) | flags;
00417 return old;
00418 }