Implement prop fonts; Fix algo styles.
[bertos.git] / gfx / text.c
index 084e9511f9b84495bbf20010d3eeba1514efbe9c..0fa994cd55189e41abbd9a8ba44b9ad9a7d6392b 100755 (executable)
@@ -1,7 +1,7 @@
 /*!
  * \file
  * <!--
- * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 2003, 2004, 2005 Develer S.r.l. (http://www.develer.com/)
  * Copyright 1999 Bernardo Innocenti <bernie@develer.com>
  * This file is part of DevLib - See README.devlib for information.
  * -->
 
 /*#*
  *#* $Log$
+ *#* Revision 1.4  2006/02/15 09:10:15  bernie
+ *#* Implement prop fonts; Fix algo styles.
+ *#*
+ *#* Revision 1.3  2006/02/10 12:31:55  bernie
+ *#* Add multiple font support in bitmaps.
+ *#*
+ *#* Revision 1.2  2005/11/04 18:17:45  bernie
+ *#* Fix header guards and includes for new location of gfx module.
+ *#*
  *#* Revision 1.1  2005/11/04 18:11:35  bernie
  *#* Move graphics stuff from mware/ to gfx/.
  *#*
  *#* documentation fixes
  *#*/
 
-#include "gfx.h"
-#include "font.h"
-#include "text.h"
+#include <gfx/gfx.h>
+#include <gfx/font.h>
+#include <gfx/text.h>
+#include <gfx/text.h>
+
+#include <gfx/gfx_p.h> // FIXME: BM_DRAWPIXEL
 
 #include <cfg/debug.h>
 
@@ -101,12 +113,12 @@ static bool ansi_mode = false;
 void text_moveto(struct Bitmap *bm, int row, int col)
 {
        ASSERT(col >= 0);
-       ASSERT(col < bm->width / FONT_WIDTH);
+       ASSERT(col < bm->width / bm->font->width);
        ASSERT(row >= 0);
-       ASSERT(row < bm->height / FONT_HEIGHT);
+       ASSERT(row < bm->height / bm->font->height);
 
-       bm->penX = col * FONT_WIDTH;
-       bm->penY = row * FONT_HEIGHT;
+       bm->penX = col * bm->font->width;
+       bm->penY = row * bm->font->height;
 }
 
 
@@ -121,92 +133,125 @@ void text_setcoord(struct Bitmap *bm, int x, int y)
 
 
 /*!
- * Render char \a c on Bitmap \a bm
+ * Render char \a c on Bitmap \a bm.
  */
 static int text_putglyph(char c, struct Bitmap *bm)
 {
        const uint8_t * PROGMEM glyph;  /* font is in progmem */
-       uint8_t glyph_width;
-       uint8_t i;
-       uint8_t *buf;
+       uint8_t glyph_width, glyph_height, glyph_height_bytes;
+       unsigned char index = (unsigned char)c;
 
-       /*
-        * Il carattere da stampare viene usato come indice per prelevare
-        * la prima colonna di dots del glyph all'interno del font.
-        */
-       glyph = font + (((unsigned char)c) * FONT_WIDTH);
-       glyph_width = FONT_WIDTH;
+       /* Check for out of range char and replace with '?' or first char in font. */
+       if (index < bm->font->first || index > bm->font->last)
+       {
+               kprintf("Illegal char '%c' (0x%02x)\n", index, index);
+               if ('?' >= bm->font->first && '?' <= bm->font->last)
+                       index = '?';
+               else
+                       index = bm->font->first;
+       }
 
-       if (text_styles & STYLEF_CONDENSED)
-               --glyph_width;
+       /* Make character relative to font start */
+       index -= bm->font->first;
 
-       if (text_styles & STYLEF_EXPANDED)
-               glyph_width *= 2;
-
-       /* The y coord is rounded at multiples of 8 for simplicity */
-       bm->penY &= ~((coord_t)7);
+       glyph_height = bm->font->height;
+       // FIXME: for vertical fonts only
+       glyph_height_bytes = (glyph_height + 7) / 8;
 
-       /* Check if glyph to write fits in the bitmap */
-       if ((bm->penX < 0) || (bm->penX + glyph_width > bm->width) ||
-               (bm->penY < 0) || (bm->penY + FONT_HEIGHT > bm->height))
+       if (bm->font->offset)
+       {
+               /* Proportional font */
+               glyph_width = bm->font->widths[index]; /* TODO: optimize away */
+               glyph = bm->font->glyph + bm->font->offset[index];
+       }
+       else
        {
-               DB(kprintf("bad coords x=%d y=%d\n", bm->penX, bm->penY);)
-               return 0;
+               /*
+                * Fixed-width font: compute the first column of pixels
+                * of the selected glyph using the character code to index
+                * the glyph array.
+                */
+               glyph_width = bm->font->width;
+
+               //For horizontal fonts
+               //glyph = bm->font->glyph + index * (((glyph_width + 7) / 8) * glyph_height);
+               glyph = bm->font->glyph + index * glyph_height_bytes * glyph_width;
        }
 
-       /* Locate position where to write in the raster */
-       buf = bm->raster + bm->penY / 8 * bm->width + bm->penX;
+       if (text_styles & STYLEF_CONDENSED)
+               --glyph_width;
 
-       bm->penX += glyph_width;
+       if (text_styles & STYLEF_EXPANDED)
+               glyph_width *= 2;
 
-       /* If some styles are set */
+       /* Slow path for styled glyphs */
        if (text_styles)
        {
-               uint8_t prev_dots = 0, italic_prev_dots = 0, new_dots;
+               uint8_t prev_dots = 0, italic_prev_dots = 0;
                uint8_t dots;
+               uint8_t row, col;
 
-               /* Per ogni colonna di dot del glyph... */
-               for (i = 0; i < glyph_width; ++i)
+               /* Check if glyph fits in the bitmap. */
+               if ((bm->penX < 0) || (bm->penX + glyph_width > bm->width)
+                       || (bm->penY < 0) || (bm->penY + glyph_height > bm->height))
                {
-                       dots = PGM_READ_CHAR(glyph);
-
-                       /* Advance to next column in glyph.
-                        * Expand: advances only once every two columns
-                        */
-                       if (!(text_styles & STYLEF_EXPANDED) || (i & 1))
-                               glyph++;
-
-                       /* Italic: get lower 4 dots from previous column */
-                       if (text_styles & STYLEF_ITALIC)
-                       {
-                               new_dots = dots;
-                               dots = (dots & 0xF0) | italic_prev_dots;
-                               italic_prev_dots = new_dots & 0x0F;
-                       }
+                       kprintf("bad coords x=%d y=%d\n", bm->penX, bm->penY);
+                       return 0;
+               }
 
-                       /* Bold: "or" pixels with the previous column */
-                       if (text_styles & STYLEF_BOLD)
+               for (row = 0; row < glyph_height_bytes; ++row)
+               {
+                       /* For each dot column in the glyph... */
+                       for (col = 0; col < glyph_width; ++col)
                        {
-                               new_dots = dots;
-                               dots |= prev_dots;
-                               prev_dots = new_dots;
+                               uint8_t src_col = col;
+                               uint8_t i;
+
+                               /* Expanded style: advances only once every two columns. */
+                               if (text_styles & STYLEF_EXPANDED)
+                                       src_col /= 2;
+
+                               /* Fetch a column of dots from glyph. */
+                               dots = PGM_READ_CHAR(glyph + src_col * glyph_height_bytes + row);
+
+                               /* Italic: get lower 4 dots from previous column */
+                               if (text_styles & STYLEF_ITALIC)
+                               {
+                                       uint8_t new_dots = dots;
+                                       dots = (dots & 0xF0) | italic_prev_dots;
+                                       italic_prev_dots = new_dots & 0x0F;
+                               }
+
+                               /* Bold: "or" pixels with the previous column */
+                               if (text_styles & STYLEF_BOLD)
+                               {
+                                       uint8_t new_dots = dots;
+                                       dots |= prev_dots;
+                                       prev_dots = new_dots;
+                               }
+
+                               /* Underlined: turn on base pixel */
+                               if (text_styles & STYLEF_UNDERLINE)
+                                       dots |= 0x80;
+
+                               /* Inverted: invert pixels */
+                               if (text_styles & STYLEF_INVERT)
+                                       dots = ~dots;
+
+                               /* Output dots */
+                               for (i = 0; i < 8 && (row * 8) + i < glyph_height; ++i)
+                                       BM_DRAWPIXEL(bm, bm->penX + col, bm->penY + row * 8 + i, dots & (1<<i));
                        }
-
-                       /* Underlined: turn on base pixel */
-                       if (text_styles & STYLEF_UNDERLINE)
-                               dots |= 0x80;
-
-                       /* Inverted: invert pixels */
-                       if (text_styles & STYLEF_INVERT)
-                               dots = ~dots;
-
-                       /* Output dots */
-                       *buf++ = dots;
                }
        }
-       else /* No style: fast vanilla copy of glyph to line buffer */
-               while (glyph_width--)
-                       *buf++ = PGM_READ_CHAR(glyph++);
+       else
+       {
+               /* No style: fast vanilla copy of glyph to bitmap */
+               gfx_blitRaster(bm, bm->penX, bm->penY, glyph, glyph_width, glyph_height, glyph_height_bytes);
+       }
+
+       /* Update current pen position */
+       bm->penX += glyph_width;
 
        return c;
 }
@@ -240,9 +285,9 @@ int text_putchar(char c, struct Bitmap *bm)
        }
        else if (c == '\n')  /* Go one line down on a line-feed */
        {
-               if (bm->penY + FONT_HEIGHT < bm->height)
+               if (bm->penY + bm->font->height < bm->height)
                {
-                       bm->penY += FONT_HEIGHT;
+                       bm->penY += bm->font->height;
                        bm->penX = 0;
                }
        }
@@ -264,9 +309,9 @@ void text_clear(struct Bitmap *bmp)
 }
 
 
-void text_clearLine(struct Bitmap *bmp, int line)
+void text_clearLine(struct Bitmap *bm, int line)
 {
-       gfx_rectClear(bmp, 0, line * FONT_HEIGHT, bmp->width, (line + 1) * FONT_HEIGHT);
+       gfx_rectClear(bm, 0, line * bm->font->height, bm->width, (line + 1) * bm->font->height);
 }