HelenOS sources
This source file includes following definitions.
- gfx_text_fmt_init
- gfx_text_width
- gfx_puttext_textmode
- gfx_text_start_pos
- gfx_puttext
- gfx_text_find_pos
- gfx_text_cont
- gfx_text_rect
#include <errno.h>
#include <gfx/bitmap.h>
#include <gfx/color.h>
#include <gfx/font.h>
#include <gfx/glyph.h>
#include <gfx/render.h>
#include <gfx/text.h>
#include <io/pixelmap.h>
#include <mem.h>
#include <str.h>
#include "../private/font.h"
#include "../private/typeface.h"
void gfx_text_fmt_init(gfx_text_fmt_t *fmt)
{
memset(fmt, 0, sizeof(gfx_text_fmt_t));
}
gfx_coord_t gfx_text_width(gfx_font_t *font, const char *str)
{
gfx_glyph_metrics_t gmetrics;
size_t stradv;
const char *cp;
gfx_glyph_t *glyph;
gfx_coord_t width;
errno_t rc;
if ((font->finfo->props.flags & gff_text_mode) != 0)
return str_width(str);
width = 0;
cp = str;
while (*cp != '\0') {
rc = gfx_font_search_glyph(font, cp, &glyph, &stradv);
if (rc != EOK) {
++cp;
continue;
}
gfx_glyph_get_metrics(glyph, &gmetrics);
cp += stradv;
width += gmetrics.advance;
}
return width;
}
static errno_t gfx_puttext_textmode(gfx_coord2_t *pos, gfx_text_fmt_t *fmt,
const char *str)
{
gfx_context_t *gc = fmt->font->typeface->gc;
gfx_bitmap_params_t params;
gfx_bitmap_t *bitmap;
gfx_bitmap_alloc_t alloc;
gfx_coord_t width;
uint8_t attr;
pixelmap_t pmap;
gfx_coord_t x;
gfx_coord_t rmargin;
pixel_t pixel;
char32_t c;
size_t off;
bool ellipsis;
errno_t rc;
width = str_width(str);
if (fmt->abbreviate && width > fmt->width) {
ellipsis = true;
width = fmt->width;
if (width > 3)
rmargin = width - 3;
else
rmargin = width;
} else {
ellipsis = false;
rmargin = width;
}
gfx_color_get_ega(fmt->color, &attr);
gfx_bitmap_params_init(¶ms);
params.rect.p0.x = 0;
params.rect.p0.y = 0;
params.rect.p1.x = width;
params.rect.p1.y = 1;
if (params.rect.p1.x == 0) {
return EOK;
}
rc = gfx_bitmap_create(gc, ¶ms, NULL, &bitmap);
if (rc != EOK)
return rc;
rc = gfx_bitmap_get_alloc(bitmap, &alloc);
if (rc != EOK) {
gfx_bitmap_destroy(bitmap);
return rc;
}
pmap.width = params.rect.p1.x;
pmap.height = 1;
pmap.data = alloc.pixels;
off = 0;
for (x = 0; x < rmargin; x++) {
c = str_decode(str, &off, STR_NO_LIMIT);
pixel = PIXEL(attr,
(c >> 16) & 0xff,
(c >> 8) & 0xff,
c & 0xff);
pixelmap_put_pixel(&pmap, x, 0, pixel);
}
if (ellipsis) {
for (x = rmargin; x < params.rect.p1.x; x++) {
c = '.';
pixel = PIXEL(attr,
(c >> 16) & 0xff,
(c >> 8) & 0xff,
c & 0xff);
pixelmap_put_pixel(&pmap, x, 0, pixel);
}
}
rc = gfx_bitmap_render(bitmap, NULL, pos);
gfx_bitmap_destroy(bitmap);
return rc;
}
void gfx_text_start_pos(gfx_coord2_t *pos, gfx_text_fmt_t *fmt,
const char *str, gfx_coord2_t *spos)
{
gfx_font_metrics_t fmetrics;
gfx_coord_t width;
*spos = *pos;
if (fmt->halign != gfx_halign_left) {
width = gfx_text_width(fmt->font, str);
if (fmt->abbreviate && width > fmt->width)
width = fmt->width;
switch (fmt->halign) {
case gfx_halign_center:
spos->x -= width / 2;
break;
case gfx_halign_right:
spos->x -= width;
break;
default:
break;
}
}
gfx_font_get_metrics(fmt->font, &fmetrics);
if (fmt->valign != gfx_valign_baseline) {
switch (fmt->valign) {
case gfx_valign_top:
spos->y += fmetrics.ascent;
break;
case gfx_valign_center:
spos->y += fmetrics.ascent / 2;
break;
case gfx_valign_bottom:
spos->y -= fmetrics.descent + 1;
break;
default:
break;
}
}
}
errno_t gfx_puttext(gfx_coord2_t *pos, gfx_text_fmt_t *fmt, const char *str)
{
gfx_glyph_metrics_t gmetrics;
gfx_font_metrics_t fmetrics;
size_t stradv;
const char *cp;
gfx_glyph_t *glyph;
gfx_coord2_t cpos;
gfx_coord2_t spos;
gfx_rect_t rect;
gfx_coord_t width;
gfx_coord_t rmargin;
bool ellipsis;
errno_t rc;
gfx_text_start_pos(pos, fmt, str, &spos);
if ((fmt->font->finfo->props.flags & gff_text_mode) != 0)
return gfx_puttext_textmode(&spos, fmt, str);
rc = gfx_set_color(fmt->font->typeface->gc, fmt->color);
if (rc != EOK)
return rc;
width = gfx_text_width(fmt->font, str);
if (fmt->abbreviate && width > fmt->width) {
ellipsis = true;
rmargin = spos.x + fmt->width - gfx_text_width(fmt->font, "...");
} else {
ellipsis = false;
rmargin = spos.x + width;
}
cpos = spos;
cp = str;
while (*cp != '\0') {
rc = gfx_font_search_glyph(fmt->font, cp, &glyph, &stradv);
if (rc != EOK) {
++cp;
continue;
}
gfx_glyph_get_metrics(glyph, &gmetrics);
if (fmt->abbreviate && cpos.x + gmetrics.advance > rmargin)
break;
rc = gfx_glyph_render(glyph, &cpos);
if (rc != EOK)
return rc;
cp += stradv;
cpos.x += gmetrics.advance;
}
if (fmt->underline) {
gfx_font_get_metrics(fmt->font, &fmetrics);
rect.p0.x = spos.x;
rect.p0.y = spos.y + fmetrics.underline_y0;
rect.p1.x = cpos.x;
rect.p1.y = spos.y + fmetrics.underline_y1;
rc = gfx_fill_rect(fmt->font->typeface->gc, &rect);
if (rc != EOK)
return rc;
}
if (ellipsis) {
rc = gfx_font_search_glyph(fmt->font, ".", &glyph, &stradv);
if (rc != EOK)
return EOK;
gfx_glyph_get_metrics(glyph, &gmetrics);
rc = gfx_glyph_render(glyph, &cpos);
if (rc != EOK)
return rc;
cpos.x += gmetrics.advance;
rc = gfx_glyph_render(glyph, &cpos);
if (rc != EOK)
return rc;
cpos.x += gmetrics.advance;
rc = gfx_glyph_render(glyph, &cpos);
if (rc != EOK)
return rc;
}
return EOK;
}
size_t gfx_text_find_pos(gfx_coord2_t *pos, gfx_text_fmt_t *fmt,
const char *str, gfx_coord2_t *fpos)
{
gfx_glyph_metrics_t gmetrics;
size_t stradv;
const char *cp;
gfx_glyph_t *glyph;
gfx_coord2_t cpos;
size_t off;
size_t strsize;
errno_t rc;
gfx_text_start_pos(pos, fmt, str, &cpos);
if ((fmt->font->finfo->props.flags & gff_text_mode) != 0) {
off = 0;
strsize = str_size(str);
while (off < strsize) {
if (fpos->x <= cpos.x)
return off;
(void) str_decode(str, &off, strsize);
cpos.x++;
}
return off;
}
cp = str;
off = 0;
while (*cp != '\0') {
rc = gfx_font_search_glyph(fmt->font, cp, &glyph, &stradv);
if (rc != EOK) {
++cp;
continue;
}
gfx_glyph_get_metrics(glyph, &gmetrics);
if (fpos->x < cpos.x + gmetrics.advance / 2)
return off;
cp += stradv;
off += stradv;
cpos.x += gmetrics.advance;
}
return off;
}
void gfx_text_cont(gfx_coord2_t *pos, gfx_text_fmt_t *fmt, const char *str,
gfx_coord2_t *cpos, gfx_text_fmt_t *cfmt)
{
gfx_coord2_t spos;
gfx_text_fmt_t tfmt;
gfx_text_start_pos(pos, fmt, str, &spos);
cpos->x = spos.x + gfx_text_width(fmt->font, str);
cpos->y = spos.y;
tfmt = *fmt;
tfmt.halign = gfx_halign_left;
tfmt.valign = gfx_valign_baseline;
tfmt.width = fmt->width - (cpos->x - spos.x);
*cfmt = tfmt;
}
void gfx_text_rect(gfx_coord2_t *pos, gfx_text_fmt_t *fmt, const char *str,
gfx_rect_t *rect)
{
gfx_coord2_t spos;
gfx_coord_t width;
gfx_text_start_pos(pos, fmt, str, &spos);
width = gfx_text_width(fmt->font, str);
if (fmt->abbreviate && width > fmt->width)
width = fmt->width;
rect->p0.x = spos.x;
rect->p0.y = spos.y - fmt->font->metrics.ascent;
rect->p1.x = spos.x + width;
rect->p1.y = spos.y + fmt->font->metrics.descent + 1;
}
HelenOS homepage, sources at GitHub