Redesign of NXTEXT font cache
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3761 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
19133a2612
commit
a9f5dedc51
@ -161,8 +161,8 @@ static void nxbg_position(NXWINDOW hwnd, FAR const struct nxgl_size_s *size,
|
||||
|
||||
/* Save the window limits (these should be the same for all places and all windows */
|
||||
|
||||
g_xres = bounds->pt2.x;
|
||||
g_yres = bounds->pt2.y;
|
||||
g_xres = bounds->pt2.x + 1;
|
||||
g_yres = bounds->pt2.y + 1;
|
||||
|
||||
b_haveresolution = true;
|
||||
sem_post(&g_semevent);
|
||||
@ -202,7 +202,6 @@ static void nxbg_kbdin(NXWINDOW hwnd, uint8_t nch, FAR const uint8_t *ch,
|
||||
|
||||
static void nxbg_scroll(NXWINDOW hwnd, int lineheight)
|
||||
{
|
||||
struct nxgl_rect_s rect;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
@ -220,7 +219,7 @@ static void nxbg_scroll(NXWINDOW hwnd, int lineheight)
|
||||
|
||||
/* Has any part of this character scrolled off the screen? */
|
||||
|
||||
if (bm->bounds.pt1.y < lineheight)
|
||||
if (bm->pos.y < lineheight)
|
||||
{
|
||||
/* Yes... Delete the character by moving all of the data */
|
||||
|
||||
@ -242,10 +241,9 @@ static void nxbg_scroll(NXWINDOW hwnd, int lineheight)
|
||||
|
||||
else
|
||||
{
|
||||
bm->bounds.pt1.y -= lineheight;
|
||||
bm->bounds.pt2.y -= lineheight;
|
||||
bm->pos.y -= lineheight;
|
||||
|
||||
/* Increment to the next character */
|
||||
/* We are keeping this one so increment to the next character */
|
||||
|
||||
i++;
|
||||
}
|
||||
@ -258,11 +256,7 @@ static void nxbg_scroll(NXWINDOW hwnd, int lineheight)
|
||||
|
||||
/* Then re-draw the entire display */
|
||||
|
||||
rect.pt1.x = 0;
|
||||
rect.pt1.y = 0;
|
||||
rect.pt2.x = g_bgstate.wsize.w - 1;
|
||||
rect.pt2.y = g_bgstate.wsize.h - 1;
|
||||
nxbg_redrawrect(hwnd, &rect);
|
||||
nxbg_redrawrect(hwnd, NULL);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -375,7 +369,7 @@ void nxbg_redrawrect(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect)
|
||||
nxtext_home(&g_bgstate);
|
||||
for (i = 0; i < g_bgstate.nchars; i++)
|
||||
{
|
||||
nxtext_fillchar(hwnd, rect, &g_bgstate.bm[i]);
|
||||
nxtext_fillchar(hwnd, rect, &g_bgstate, &g_bgstate.bm[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,11 +111,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_EXAMPLES_NXTEXT_GLCACHE
|
||||
# if CONFIG_NXFONTS_CHARBITS < 8
|
||||
# define CONFIG_EXAMPLES_NXTEXT_GLCACHE MIN(CONFIG_EXAMPLES_NXTEXT_BMCACHE, 128)
|
||||
# else
|
||||
# define CONFIG_EXAMPLES_NXTEXT_GLCACHE MIN(CONFIG_EXAMPLES_NXTEXT_BMCACHE, 256)
|
||||
# endif
|
||||
# define CONFIG_EXAMPLES_NXTEXT_BMCACHE 16
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NX_MULTIUSER
|
||||
@ -168,6 +164,16 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Bitmap flags */
|
||||
|
||||
#define BMFLAGS_NOGLYPH (1 << 0) /* No glyph available, use space */
|
||||
|
||||
#define BM_ISSPACE(bm) (((bm)->flags & BMFLAGS_NOGLYPH) != 0)
|
||||
|
||||
/* Sizes and maximums */
|
||||
|
||||
#define MAX_USECNT 255
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
@ -202,6 +208,7 @@ struct nxtext_glyph_s
|
||||
uint8_t height; /* Height of this glyph (in rows) */
|
||||
uint8_t width; /* Width of this glyph (in pixels) */
|
||||
uint8_t stride; /* Width of the glyph row (in bytes) */
|
||||
uint8_t usecnt; /* Use count */
|
||||
FAR uint8_t *bitmap; /* Allocated bitmap memory */
|
||||
};
|
||||
|
||||
@ -209,8 +216,9 @@ struct nxtext_glyph_s
|
||||
|
||||
struct nxtext_bitmap_s
|
||||
{
|
||||
struct nxgl_rect_s bounds; /* Size/position of bitmap */
|
||||
FAR const struct nxtext_glyph_s *glyph; /* The cached glyph */
|
||||
uint8_t code; /* Character code */
|
||||
uint8_t flags; /* See BMFLAGS_* */
|
||||
struct nxgl_point_s pos; /* Character position */
|
||||
};
|
||||
|
||||
/* Describes the state of one text display */
|
||||
@ -236,7 +244,6 @@ struct nxtext_state_s
|
||||
uint16_t maxchars; /* Size of the mb array */
|
||||
uint8_t maxglyphs; /* Size of the glyph array */
|
||||
uint8_t nchars; /* Number of chars already displayed */
|
||||
uint8_t nglyphs; /* Number of glyphs cached */
|
||||
|
||||
FAR struct nxtext_bitmap_s *bm; /* List of characters on the display */
|
||||
FAR struct nxtext_glyph_s *glyph; /* Cache of rendered fonts in use */
|
||||
@ -301,6 +308,7 @@ extern void nxtext_newline(FAR struct nxtext_state_s *st);
|
||||
extern void nxtext_putc(NXWINDOW hwnd, FAR struct nxtext_state_s *st,
|
||||
uint8_t ch);
|
||||
extern void nxtext_fillchar(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect,
|
||||
FAR struct nxtext_state_s *st,
|
||||
FAR const struct nxtext_bitmap_s *bm);
|
||||
|
||||
#endif /* __EXAMPLES_NXTEXT_NXTEXT_INTERNAL_H */
|
||||
|
@ -196,7 +196,7 @@ static inline void nxpu_fillwindow(NXWINDOW hwnd,
|
||||
nxtext_home(st);
|
||||
for (i = 0; i < st->nchars; i++)
|
||||
{
|
||||
nxtext_fillchar(hwnd, rect, &st->bm[i]);
|
||||
nxtext_fillchar(hwnd, rect, st, &st->bm[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -103,7 +103,122 @@
|
||||
* Name: nxtext_renderglyph
|
||||
****************************************************************************/
|
||||
|
||||
static inline FAR const struct nxtext_glyph_s *
|
||||
static void nxtext_freeglyph(FAR struct nxtext_glyph_s *glyph)
|
||||
{
|
||||
if (glyph->bitmap)
|
||||
{
|
||||
free(glyph->bitmap);
|
||||
}
|
||||
memset(glyph, 0, sizeof(struct nxtext_glyph_s));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxtext_allocglyph
|
||||
****************************************************************************/
|
||||
|
||||
static inline FAR struct nxtext_glyph_s *
|
||||
nxtext_allocglyph(FAR struct nxtext_state_s *st)
|
||||
{
|
||||
FAR struct nxtext_glyph_s *glyph = NULL;
|
||||
FAR struct nxtext_glyph_s *luglyph = NULL;
|
||||
uint8_t luusecnt;
|
||||
int i;
|
||||
|
||||
/* Search through the glyph cache looking for an unused glyph. Also, keep
|
||||
* track of the least used glyph as well. We need that if we have to replace
|
||||
* a glyph in the cache.
|
||||
*/
|
||||
|
||||
for (i = 0; i < st->maxglyphs; i++)
|
||||
{
|
||||
/* Is this glyph in use? */
|
||||
|
||||
glyph = &st->glyph[i];
|
||||
if (!glyph->usecnt)
|
||||
{
|
||||
/* No.. return this glyph with a use count of one */
|
||||
|
||||
glyph->usecnt = 1;
|
||||
return glyph;
|
||||
}
|
||||
|
||||
/* Yes.. check for the least recently used */
|
||||
|
||||
if (!luglyph || glyph->usecnt < luglyph->usecnt)
|
||||
{
|
||||
luglyph = glyph;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we get here, the glyph cache is full. We replace the least used
|
||||
* glyph with the one we need now. (luglyph can't be NULL).
|
||||
*/
|
||||
|
||||
luusecnt = luglyph->usecnt;
|
||||
nxtext_freeglyph(luglyph);
|
||||
|
||||
/* But lets decrement all of the usecnts so that the new one one be so
|
||||
* far behind in the counts as the older ones.
|
||||
*/
|
||||
|
||||
if (luusecnt > 1)
|
||||
{
|
||||
uint8_t decr = luusecnt - 1;
|
||||
|
||||
for (i = 0; i < st->maxglyphs; i++)
|
||||
{
|
||||
/* Is this glyph in use? */
|
||||
|
||||
glyph = &st->glyph[i];
|
||||
if (glyph->usecnt > decr)
|
||||
{
|
||||
glyph->usecnt -= decr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Then return the least used glyph */
|
||||
|
||||
luglyph->usecnt = 1;
|
||||
return luglyph;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxtext_findglyph
|
||||
****************************************************************************/
|
||||
|
||||
static FAR struct nxtext_glyph_s *
|
||||
nxtext_findglyph(FAR struct nxtext_state_s *st, uint8_t ch)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* First, try to find the glyph in the cache of pre-rendered glyphs */
|
||||
|
||||
for (i = 0; i < st->maxglyphs; i++)
|
||||
{
|
||||
FAR struct nxtext_glyph_s *glyph = &st->glyph[i];
|
||||
if (glyph->usecnt > 0 && glyph->code == ch)
|
||||
{
|
||||
/* Increment the use count (unless it is already at the max) */
|
||||
|
||||
if (glyph->usecnt < MAX_USECNT)
|
||||
{
|
||||
glyph->usecnt++;
|
||||
}
|
||||
|
||||
/* And return the glyph that we found */
|
||||
|
||||
return glyph;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxtext_renderglyph
|
||||
****************************************************************************/
|
||||
|
||||
static inline FAR struct nxtext_glyph_s *
|
||||
nxtext_renderglyph(FAR struct nxtext_state_s *st,
|
||||
FAR const struct nx_fontbitmap_s *bm, uint8_t ch)
|
||||
{
|
||||
@ -120,11 +235,10 @@ nxtext_renderglyph(FAR struct nxtext_state_s *st,
|
||||
/* Make sure that there is room for another glyph */
|
||||
|
||||
message("nxtext_renderglyph: ch=%02x\n", ch);
|
||||
if (st->nglyphs < st->maxglyphs)
|
||||
{
|
||||
/* Allocate the glyph */
|
||||
|
||||
glyph = &st->glyph[st->nglyphs];
|
||||
/* Allocate the glyph (always succeeds) */
|
||||
|
||||
glyph = nxtext_allocglyph(st);
|
||||
glyph->code = ch;
|
||||
|
||||
/* Get the dimensions of the glyph */
|
||||
@ -200,102 +314,37 @@ nxtext_renderglyph(FAR struct nxtext_state_s *st,
|
||||
/* Actually, the RENDERER never returns a failure */
|
||||
|
||||
message("nxtext_renderglyph: RENDERER failed\n");
|
||||
free(glyph->bitmap);
|
||||
glyph->bitmap = NULL;
|
||||
nxtext_freeglyph(glyph);
|
||||
glyph = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Make it permanent */
|
||||
|
||||
st->nglyphs++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return glyph;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxtext_addspace
|
||||
****************************************************************************/
|
||||
|
||||
static inline FAR const struct nxtext_glyph_s *
|
||||
nxtext_addspace(FAR struct nxtext_state_s *st, uint8_t ch)
|
||||
{
|
||||
FAR struct nxtext_glyph_s *glyph = NULL;
|
||||
|
||||
/* Make sure that there is room for another glyph */
|
||||
|
||||
if (st->nglyphs < st->maxglyphs)
|
||||
{
|
||||
/* Allocate the NULL glyph */
|
||||
|
||||
glyph = &st->glyph[st->nglyphs];
|
||||
memset(glyph, 0, sizeof(struct nxtext_glyph_s));
|
||||
|
||||
glyph->code = ' ';
|
||||
glyph->width = st->spwidth;
|
||||
|
||||
st->nglyphs++;
|
||||
}
|
||||
return glyph;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxtext_findglyph
|
||||
****************************************************************************/
|
||||
|
||||
static FAR const struct nxtext_glyph_s *
|
||||
nxtext_findglyph(FAR struct nxtext_state_s *st, uint8_t ch)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* First, try to find the glyph in the cache of pre-rendered glyphs */
|
||||
|
||||
for (i = 0; i < st->nglyphs; i++)
|
||||
{
|
||||
if (st->glyph[i].code == ch)
|
||||
{
|
||||
return &st->glyph[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxtext_getglyph
|
||||
****************************************************************************/
|
||||
|
||||
static FAR const struct nxtext_glyph_s *
|
||||
static FAR struct nxtext_glyph_s *
|
||||
nxtext_getglyph(FAR struct nxtext_state_s *st, uint8_t ch)
|
||||
{
|
||||
FAR const struct nxtext_glyph_s *glyph;
|
||||
FAR const struct nx_fontbitmap_s *bm;
|
||||
FAR struct nxtext_glyph_s *glyph;
|
||||
FAR const struct nx_fontbitmap_s *fbm;
|
||||
|
||||
/* First, try to find the glyph in the cache of pre-rendered glyphs */
|
||||
|
||||
glyph = nxtext_findglyph(st, ch);
|
||||
if (!glyph)
|
||||
{
|
||||
/* No, it is not cached... Does the code map to a glyph? */
|
||||
/* No, it is not cached... Does the code map to a font? */
|
||||
|
||||
bm = nxf_getbitmap(ch);
|
||||
if (!bm)
|
||||
fbm = nxf_getbitmap(ch);
|
||||
if (fbm)
|
||||
{
|
||||
/* No, there is no glyph for this code. Use space */
|
||||
/* Yes.. render the glyph */
|
||||
|
||||
glyph = nxtext_findglyph(st, ' ');
|
||||
if (!glyph)
|
||||
{
|
||||
/* There isn't fake glyph for ' ' yet... create one */
|
||||
|
||||
glyph = nxtext_addspace(st, ' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
glyph = nxtext_renderglyph(st, bm, ch);
|
||||
glyph = nxtext_renderglyph(st, fbm, ch);
|
||||
}
|
||||
}
|
||||
|
||||
@ -304,50 +353,52 @@ nxtext_getglyph(FAR struct nxtext_state_s *st, uint8_t ch)
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxtext_addchar
|
||||
*
|
||||
* Description:
|
||||
* This is part of the nxtext_putc logic. It creates and positions a
|
||||
* the character and renders (or re-uses) a glyph for font.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static FAR const struct nxtext_bitmap_s *
|
||||
nxtext_addchar(FAR struct nxtext_state_s *st, uint8_t ch)
|
||||
{
|
||||
FAR struct nxtext_bitmap_s *bm = NULL;
|
||||
FAR struct nxtext_bitmap_s *bmleft;
|
||||
FAR struct nxtext_glyph_s *glyph;
|
||||
|
||||
/* Is there space for another character on the display? */
|
||||
|
||||
if (st->nchars < st->maxchars)
|
||||
{
|
||||
/* Yes, setup the bitmap */
|
||||
/* Yes, setup the bitmap information */
|
||||
|
||||
bm = &st->bm[st->nchars];
|
||||
bm->code = ch;
|
||||
bm->flags = 0;
|
||||
bm->pos.x = st->fpos.x;
|
||||
bm->pos.y = st->fpos.y;
|
||||
|
||||
/* Find the matching glyph */
|
||||
/* Find (or create) the matching glyph */
|
||||
|
||||
bm->glyph = nxtext_getglyph(st, ch);
|
||||
if (!bm->glyph)
|
||||
glyph = nxtext_getglyph(st, ch);
|
||||
if (!glyph)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
/* No, there is no font for this code. Just mark this as a space. */
|
||||
|
||||
/* Set up the bounds for the bitmap */
|
||||
bm->flags |= BMFLAGS_NOGLYPH;
|
||||
|
||||
if (st->nchars <= 0)
|
||||
{
|
||||
/* The first character is one space from the left */
|
||||
/* Set up the next character position */
|
||||
|
||||
st->fpos.x = st->spwidth;
|
||||
st->fpos.x += st->spwidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, it is to the left of the preceding char */
|
||||
/* Set up the next character position */
|
||||
|
||||
bmleft = &st->bm[st->nchars-1];
|
||||
st->fpos.x = bmleft->bounds.pt2.x + 1;
|
||||
st->fpos.x += glyph->width;
|
||||
}
|
||||
|
||||
bm->bounds.pt1.x = st->fpos.x;
|
||||
bm->bounds.pt1.y = st->fpos.y;
|
||||
bm->bounds.pt2.x = st->fpos.x + bm->glyph->width - 1;
|
||||
bm->bounds.pt2.y = st->fpos.y + bm->glyph->height - 1;
|
||||
/* Success.. increment nchars to retain this character */
|
||||
|
||||
st->nchars++;
|
||||
}
|
||||
@ -427,7 +478,7 @@ void nxtext_putc(NXWINDOW hwnd, FAR struct nxtext_state_s *st, uint8_t ch)
|
||||
bm = nxtext_addchar(st, ch);
|
||||
if (bm)
|
||||
{
|
||||
nxtext_fillchar(hwnd, &bm->bounds, bm);
|
||||
nxtext_fillchar(hwnd, NULL, st, bm);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -442,29 +493,64 @@ void nxtext_putc(NXWINDOW hwnd, FAR struct nxtext_state_s *st, uint8_t ch)
|
||||
****************************************************************************/
|
||||
|
||||
void nxtext_fillchar(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect,
|
||||
FAR struct nxtext_state_s *st,
|
||||
FAR const struct nxtext_bitmap_s *bm)
|
||||
{
|
||||
FAR const void *src = (FAR const void *)bm->glyph->bitmap;
|
||||
FAR struct nxtext_glyph_s *glyph;
|
||||
struct nxgl_rect_s bounds;
|
||||
struct nxgl_rect_s intersection;
|
||||
int ret;
|
||||
|
||||
/* Handle the special case of spaces which have no glyph bitmap */
|
||||
|
||||
if (src)
|
||||
if (BM_ISSPACE(bm))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find (or create) the matching glyph */
|
||||
|
||||
glyph = nxtext_getglyph(st, bm->code);
|
||||
if (!glyph)
|
||||
{
|
||||
/* This shouldn't happen */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Construct a bounding box for the glyph */
|
||||
|
||||
bounds.pt1.x = bm->pos.x;
|
||||
bounds.pt1.y = bm->pos.y;
|
||||
bounds.pt1.x = bm->pos.x + glyph->width - 1;
|
||||
bounds.pt1.y = bm->pos.y + glyph->height - 1;
|
||||
|
||||
/* Should this also be clipped to a region in the window? */
|
||||
|
||||
if (rect)
|
||||
{
|
||||
/* Get the intersection of the redraw region and the character bitmap */
|
||||
|
||||
nxgl_rectintersect(&intersection, rect, &bm->bounds);
|
||||
nxgl_rectintersect(&intersection, rect, &bounds);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The intersection is the whole glyph */
|
||||
|
||||
nxgl_rectcopy(&intersection, &bounds);
|
||||
}
|
||||
|
||||
/* Check for empty intersections */
|
||||
|
||||
if (!nxgl_nullrect(&intersection))
|
||||
{
|
||||
FAR const void *src = (FAR const void *)glyph->bitmap;
|
||||
ret = nx_bitmap((NXWINDOW)hwnd, &intersection, &src,
|
||||
&bm->bounds.pt1,
|
||||
(unsigned int)bm->glyph->stride);
|
||||
&bm->pos, (unsigned int)glyph->stride);
|
||||
if (ret < 0)
|
||||
{
|
||||
message("nxtext_fillchar: nx_bitmapwindow failed: %d\n", errno);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user