Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/gfxfont/src/text.c

    r9eb8d12 rf2d4a46  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2022 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    9797/** Print string using text characters in text mode.
    9898 *
    99  * @param font Font
    10099 * @param pos Position of top-left corner of text
    101  * @param color Text color
     100 * @param fmt Formatting
    102101 * @param str String
    103102 * @return EOK on success or an error code
    104103 */
    105 static errno_t gfx_puttext_textmode(gfx_font_t *font, gfx_coord2_t *pos,
    106     gfx_color_t *color, const char *str)
    107 {
    108         gfx_context_t *gc = font->typeface->gc;
     104static errno_t gfx_puttext_textmode(gfx_coord2_t *pos, gfx_text_fmt_t *fmt,
     105    const char *str)
     106{
     107        gfx_context_t *gc = fmt->font->typeface->gc;
    109108        gfx_bitmap_params_t params;
    110109        gfx_bitmap_t *bitmap;
    111110        gfx_bitmap_alloc_t alloc;
    112         uint16_t r, g, b;
     111        gfx_coord_t width;
     112        uint8_t attr;
    113113        pixelmap_t pmap;
    114114        gfx_coord_t x;
     115        gfx_coord_t rmargin;
    115116        pixel_t pixel;
     117        char32_t c;
     118        size_t off;
     119        bool ellipsis;
    116120        errno_t rc;
     121
     122        width = str_width(str);
     123        if (fmt->abbreviate && width > fmt->width) {
     124                ellipsis = true;
     125                width = fmt->width;
     126                if (width > 3)
     127                        rmargin = width - 3;
     128                else
     129                        rmargin = width;
     130        } else {
     131                ellipsis = false;
     132                rmargin = width;
     133        }
    117134
    118135        /*
     
    121138         */
    122139
    123         gfx_color_get_rgb_i16(color, &r, &g, &b);
    124 
    125         /*
    126          * We are setting the *background* color, the foreground color
    127          * will be set to its complement.
    128          */
    129         r = 0xff ^ (r >> 8);
    130         g = 0xff ^ (g >> 8);
    131         b = 0xff ^ (b >> 8);
     140        gfx_color_get_ega(fmt->color, &attr);
    132141
    133142        gfx_bitmap_params_init(&params);
    134143        params.rect.p0.x = 0;
    135144        params.rect.p0.y = 0;
    136         params.rect.p1.x = str_width(str);
     145        params.rect.p1.x = width;
    137146        params.rect.p1.y = 1;
    138147
     
    156165        pmap.data = alloc.pixels;
    157166
    158         for (x = 0; x < params.rect.p1.x; x++) {
    159                 pixel = PIXEL(str[x], r, g, b);
     167        off = 0;
     168        for (x = 0; x < rmargin; x++) {
     169                c = str_decode(str, &off, STR_NO_LIMIT);
     170                pixel = PIXEL(attr,
     171                    (c >> 16) & 0xff,
     172                    (c >> 8) & 0xff,
     173                    c & 0xff);
    160174                pixelmap_put_pixel(&pmap, x, 0, pixel);
     175        }
     176
     177        if (ellipsis) {
     178                for (x = rmargin; x < params.rect.p1.x; x++) {
     179                        c = '.';
     180                        pixel = PIXEL(attr,
     181                            (c >> 16) & 0xff,
     182                            (c >> 8) & 0xff,
     183                            c & 0xff);
     184                        pixelmap_put_pixel(&pmap, x, 0, pixel);
     185                }
    161186        }
    162187
     
    169194/** Get text starting position.
    170195 *
    171  * @param font Font
    172196 * @param pos Anchor position
    173197 * @param fmt Text formatting
     
    175199 * @param spos Place to store starting position
    176200 */
    177 void gfx_text_start_pos(gfx_font_t *font, gfx_coord2_t *pos,
    178     gfx_text_fmt_t *fmt, const char *str, gfx_coord2_t *spos)
     201void gfx_text_start_pos(gfx_coord2_t *pos, gfx_text_fmt_t *fmt,
     202    const char *str, gfx_coord2_t *spos)
    179203{
    180204        gfx_font_metrics_t fmetrics;
    181         gfx_coord2_t cpos;
    182205        gfx_coord_t width;
    183206
     
    186209        /* Adjust position for horizontal alignment */
    187210        if (fmt->halign != gfx_halign_left) {
    188                 width = gfx_text_width(font, str);
     211                /* Compute text width */
     212                width = gfx_text_width(fmt->font, str);
     213                if (fmt->abbreviate && width > fmt->width)
     214                        width = fmt->width;
     215
    189216                switch (fmt->halign) {
    190217                case gfx_halign_center:
     
    192219                        break;
    193220                case gfx_halign_right:
    194                         spos->x -= width - 1;
     221                        spos->x -= width;
    195222                        break;
    196223                default:
     
    200227
    201228        /* Adjust position for vertical alignment */
    202         gfx_font_get_metrics(font, &fmetrics);
     229        gfx_font_get_metrics(fmt->font, &fmetrics);
    203230
    204231        if (fmt->valign != gfx_valign_baseline) {
     
    211238                        break;
    212239                case gfx_valign_bottom:
    213                         cpos.y -= fmetrics.descent;
     240                        spos->y -= fmetrics.descent + 1;
    214241                        break;
    215242                default:
     
    221248/** Render text.
    222249 *
    223  * @param font Font
    224250 * @param pos Anchor position
    225251 * @param fmt Text formatting
     
    227253 * @return EOK on success or an error code
    228254 */
    229 errno_t gfx_puttext(gfx_font_t *font, gfx_coord2_t *pos,
    230     gfx_text_fmt_t *fmt, const char *str)
     255errno_t gfx_puttext(gfx_coord2_t *pos, gfx_text_fmt_t *fmt, const char *str)
    231256{
    232257        gfx_glyph_metrics_t gmetrics;
     258        gfx_font_metrics_t fmetrics;
    233259        size_t stradv;
    234260        const char *cp;
    235261        gfx_glyph_t *glyph;
    236262        gfx_coord2_t cpos;
     263        gfx_coord2_t spos;
     264        gfx_rect_t rect;
     265        gfx_coord_t width;
     266        gfx_coord_t rmargin;
     267        bool ellipsis;
    237268        errno_t rc;
    238269
    239         gfx_text_start_pos(font, pos, fmt, str, &cpos);
     270        gfx_text_start_pos(pos, fmt, str, &spos);
    240271
    241272        /* Text mode */
    242         if ((font->finfo->props.flags & gff_text_mode) != 0)
    243                 return gfx_puttext_textmode(font, &cpos, fmt->color, str);
    244 
    245         rc = gfx_set_color(font->typeface->gc, fmt->color);
     273        if ((fmt->font->finfo->props.flags & gff_text_mode) != 0)
     274                return gfx_puttext_textmode(&spos, fmt, str);
     275
     276        rc = gfx_set_color(fmt->font->typeface->gc, fmt->color);
    246277        if (rc != EOK)
    247278                return rc;
    248279
     280        width = gfx_text_width(fmt->font, str);
     281
     282        if (fmt->abbreviate && width > fmt->width) {
     283                /* Need to append ellipsis */
     284                ellipsis = true;
     285                rmargin = spos.x + fmt->width - gfx_text_width(fmt->font, "...");
     286        } else {
     287                ellipsis = false;
     288                rmargin = spos.x + width;
     289        }
     290
     291        cpos = spos;
    249292        cp = str;
    250293        while (*cp != '\0') {
    251                 rc = gfx_font_search_glyph(font, cp, &glyph, &stradv);
     294                rc = gfx_font_search_glyph(fmt->font, cp, &glyph, &stradv);
    252295                if (rc != EOK) {
    253296                        ++cp;
     
    257300                gfx_glyph_get_metrics(glyph, &gmetrics);
    258301
     302                /* Stop if we would run over the right margin */
     303                if (fmt->abbreviate && cpos.x + gmetrics.advance > rmargin)
     304                        break;
     305
    259306                rc = gfx_glyph_render(glyph, &cpos);
    260307                if (rc != EOK)
     
    265312        }
    266313
     314        /* Text underlining */
     315        if (fmt->underline) {
     316                gfx_font_get_metrics(fmt->font, &fmetrics);
     317
     318                rect.p0.x = spos.x;
     319                rect.p0.y = spos.y + fmetrics.underline_y0;
     320                rect.p1.x = cpos.x;
     321                rect.p1.y = spos.y + fmetrics.underline_y1;
     322
     323                rc = gfx_fill_rect(fmt->font->typeface->gc, &rect);
     324                if (rc != EOK)
     325                        return rc;
     326        }
     327
     328        /* Render ellipsis, if required */
     329        if (ellipsis) {
     330                rc = gfx_font_search_glyph(fmt->font, ".", &glyph, &stradv);
     331                if (rc != EOK)
     332                        return EOK;
     333
     334                gfx_glyph_get_metrics(glyph, &gmetrics);
     335
     336                rc = gfx_glyph_render(glyph, &cpos);
     337                if (rc != EOK)
     338                        return rc;
     339
     340                cpos.x += gmetrics.advance;
     341
     342                rc = gfx_glyph_render(glyph, &cpos);
     343                if (rc != EOK)
     344                        return rc;
     345
     346                cpos.x += gmetrics.advance;
     347
     348                rc = gfx_glyph_render(glyph, &cpos);
     349                if (rc != EOK)
     350                        return rc;
     351        }
     352
    267353        return EOK;
    268354}
     
    270356/** Find character position in string by X coordinate.
    271357 *
    272  * @param font Font
    273358 * @param pos Anchor position
    274359 * @param fmt Text formatting
     
    282367 *         offset of the following character.
    283368 */
    284 size_t gfx_text_find_pos(gfx_font_t *font, gfx_coord2_t *pos,
    285     gfx_text_fmt_t *fmt, const char *str, gfx_coord2_t *fpos)
     369size_t gfx_text_find_pos(gfx_coord2_t *pos, gfx_text_fmt_t *fmt,
     370    const char *str, gfx_coord2_t *fpos)
    286371{
    287372        gfx_glyph_metrics_t gmetrics;
     
    294379        errno_t rc;
    295380
    296         gfx_text_start_pos(font, pos, fmt, str, &cpos);
     381        gfx_text_start_pos(pos, fmt, str, &cpos);
    297382
    298383        /* Text mode */
    299         if ((font->finfo->props.flags & gff_text_mode) != 0) {
     384        if ((fmt->font->finfo->props.flags & gff_text_mode) != 0) {
    300385                off = 0;
    301386                strsize = str_size(str);
     
    313398        off = 0;
    314399        while (*cp != '\0') {
    315                 rc = gfx_font_search_glyph(font, cp, &glyph, &stradv);
     400                rc = gfx_font_search_glyph(fmt->font, cp, &glyph, &stradv);
    316401                if (rc != EOK) {
    317402                        ++cp;
     
    339424 * to the same objects, respectively.
    340425 *
    341  * @param font Font
    342426 * @param pos Anchor position
    343427 * @param fmt Text formatting
     
    346430 * @param cfmt Place to store format for continuation
    347431 */
    348 void gfx_text_cont(gfx_font_t *font, gfx_coord2_t *pos,
    349     gfx_text_fmt_t *fmt, const char *str, gfx_coord2_t *cpos,
    350     gfx_text_fmt_t *cfmt)
     432void gfx_text_cont(gfx_coord2_t *pos, gfx_text_fmt_t *fmt, const char *str,
     433    gfx_coord2_t *cpos, gfx_text_fmt_t *cfmt)
    351434{
    352435        gfx_coord2_t spos;
     
    354437
    355438        /* Continuation should start where the current string ends */
    356         gfx_text_start_pos(font, pos, fmt, str, &spos);
    357         cpos->x = spos.x + gfx_text_width(font, str);
     439        gfx_text_start_pos(pos, fmt, str, &spos);
     440        cpos->x = spos.x + gfx_text_width(fmt->font, str);
    358441        cpos->y = spos.y;
    359442
     
    366449        tfmt.valign = gfx_valign_baseline;
    367450
     451        /* Remaining available width */
     452        tfmt.width = fmt->width - (cpos->x - spos.x);
     453
    368454        *cfmt = tfmt;
    369455}
     
    371457/** Get text bounding rectangle.
    372458 *
    373  * @param font Font
    374459 * @param pos Anchor position
    375460 * @param fmt Text formatting
     
    377462 * @param rect Place to store bounding rectangle
    378463 */
    379 void gfx_text_rect(gfx_font_t *font, gfx_coord2_t *pos,
    380     gfx_text_fmt_t *fmt, const char *str, gfx_rect_t *rect)
     464void gfx_text_rect(gfx_coord2_t *pos, gfx_text_fmt_t *fmt, const char *str,
     465    gfx_rect_t *rect)
    381466{
    382467        gfx_coord2_t spos;
    383 
    384         gfx_text_start_pos(font, pos, fmt, str, &spos);
     468        gfx_coord_t width;
     469
     470        gfx_text_start_pos(pos, fmt, str, &spos);
     471        width = gfx_text_width(fmt->font, str);
     472        if (fmt->abbreviate && width > fmt->width)
     473                width = fmt->width;
    385474
    386475        rect->p0.x = spos.x;
    387         rect->p0.y = spos.y - font->metrics.ascent;
    388         rect->p1.x = spos.x + gfx_text_width(font, str);
    389         rect->p1.y = spos.y + font->metrics.descent + 1;
     476        rect->p0.y = spos.y - fmt->font->metrics.ascent;
     477        rect->p1.x = spos.x + width;
     478        rect->p1.y = spos.y +  fmt->font->metrics.descent + 1;
    390479}
    391480
Note: See TracChangeset for help on using the changeset viewer.