Ignore:
File:
1 edited

Legend:

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

    r17fac946 rf2d4a46  
    11/*
    2  * Copyright (c) 2020 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
     
    167192}
    168193
    169 /** Render text.
    170  *
    171  * @param font Font
     194/** Get text starting position.
     195 *
    172196 * @param pos Anchor position
    173197 * @param fmt Text formatting
    174198 * @param str String
     199 * @param spos Place to store starting position
     200 */
     201void gfx_text_start_pos(gfx_coord2_t *pos, gfx_text_fmt_t *fmt,
     202    const char *str, gfx_coord2_t *spos)
     203{
     204        gfx_font_metrics_t fmetrics;
     205        gfx_coord_t width;
     206
     207        *spos = *pos;
     208
     209        /* Adjust position for horizontal alignment */
     210        if (fmt->halign != gfx_halign_left) {
     211                /* Compute text width */
     212                width = gfx_text_width(fmt->font, str);
     213                if (fmt->abbreviate && width > fmt->width)
     214                        width = fmt->width;
     215
     216                switch (fmt->halign) {
     217                case gfx_halign_center:
     218                        spos->x -= width / 2;
     219                        break;
     220                case gfx_halign_right:
     221                        spos->x -= width;
     222                        break;
     223                default:
     224                        break;
     225                }
     226        }
     227
     228        /* Adjust position for vertical alignment */
     229        gfx_font_get_metrics(fmt->font, &fmetrics);
     230
     231        if (fmt->valign != gfx_valign_baseline) {
     232                switch (fmt->valign) {
     233                case gfx_valign_top:
     234                        spos->y += fmetrics.ascent;
     235                        break;
     236                case gfx_valign_center:
     237                        spos->y += fmetrics.ascent / 2;
     238                        break;
     239                case gfx_valign_bottom:
     240                        spos->y -= fmetrics.descent + 1;
     241                        break;
     242                default:
     243                        break;
     244                }
     245        }
     246}
     247
     248/** Render text.
     249 *
     250 * @param pos Anchor position
     251 * @param fmt Text formatting
     252 * @param str String
    175253 * @return EOK on success or an error code
    176254 */
    177 errno_t gfx_puttext(gfx_font_t *font, gfx_coord2_t *pos,
    178     gfx_text_fmt_t *fmt, const char *str)
    179 {
     255errno_t gfx_puttext(gfx_coord2_t *pos, gfx_text_fmt_t *fmt, const char *str)
     256{
     257        gfx_glyph_metrics_t gmetrics;
    180258        gfx_font_metrics_t fmetrics;
     259        size_t stradv;
     260        const char *cp;
     261        gfx_glyph_t *glyph;
     262        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;
     268        errno_t rc;
     269
     270        gfx_text_start_pos(pos, fmt, str, &spos);
     271
     272        /* Text mode */
     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);
     277        if (rc != EOK)
     278                return rc;
     279
     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;
     292        cp = str;
     293        while (*cp != '\0') {
     294                rc = gfx_font_search_glyph(fmt->font, cp, &glyph, &stradv);
     295                if (rc != EOK) {
     296                        ++cp;
     297                        continue;
     298                }
     299
     300                gfx_glyph_get_metrics(glyph, &gmetrics);
     301
     302                /* Stop if we would run over the right margin */
     303                if (fmt->abbreviate && cpos.x + gmetrics.advance > rmargin)
     304                        break;
     305
     306                rc = gfx_glyph_render(glyph, &cpos);
     307                if (rc != EOK)
     308                        return rc;
     309
     310                cp += stradv;
     311                cpos.x += gmetrics.advance;
     312        }
     313
     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
     353        return EOK;
     354}
     355
     356/** Find character position in string by X coordinate.
     357 *
     358 * @param pos Anchor position
     359 * @param fmt Text formatting
     360 * @param str String
     361 * @param fpos Position for which we need to find offset
     362 *
     363 * @return Byte offset in @a str of character corresponding to position
     364 *         @a fpos. Note that the position is rounded, that is,
     365 *         if it is before the center of character A, it will return
     366 *         offset of A, if it is after the center of A, it will return
     367 *         offset of the following character.
     368 */
     369size_t gfx_text_find_pos(gfx_coord2_t *pos, gfx_text_fmt_t *fmt,
     370    const char *str, gfx_coord2_t *fpos)
     371{
    181372        gfx_glyph_metrics_t gmetrics;
    182373        size_t stradv;
     
    184375        gfx_glyph_t *glyph;
    185376        gfx_coord2_t cpos;
    186         gfx_coord_t width;
     377        size_t off;
     378        size_t strsize;
    187379        errno_t rc;
    188380
    189         cpos = *pos;
    190 
    191         /* Adjust position for horizontal alignment */
    192         if (fmt->halign != gfx_halign_left) {
    193                 width = gfx_text_width(font, str);
    194                 switch (fmt->halign) {
    195                 case gfx_halign_center:
    196                         cpos.x -= width / 2;
    197                         break;
    198                 case gfx_halign_right:
    199                         cpos.x -= width - 1;
    200                         break;
    201                 default:
    202                         break;
    203                 }
    204         }
    205 
    206         /* Adjust position for vertical alignment */
    207         gfx_font_get_metrics(font, &fmetrics);
    208 
    209         if (fmt->valign != gfx_valign_baseline) {
    210                 switch (fmt->valign) {
    211                 case gfx_valign_top:
    212                         cpos.y += fmetrics.ascent;
    213                         break;
    214                 case gfx_valign_center:
    215                         cpos.y += fmetrics.ascent / 2;
    216                         break;
    217                 case gfx_valign_bottom:
    218                         cpos.y -= fmetrics.descent;
    219                         break;
    220                 default:
    221                         break;
    222                 }
    223         }
     381        gfx_text_start_pos(pos, fmt, str, &cpos);
    224382
    225383        /* Text mode */
    226         if ((font->finfo->props.flags & gff_text_mode) != 0)
    227                 return gfx_puttext_textmode(font, &cpos, fmt->color, str);
    228 
    229         rc = gfx_set_color(font->typeface->gc, fmt->color);
    230         if (rc != EOK)
    231                 return rc;
     384        if ((fmt->font->finfo->props.flags & gff_text_mode) != 0) {
     385                off = 0;
     386                strsize = str_size(str);
     387                while (off < strsize) {
     388                        if (fpos->x <= cpos.x)
     389                                return off;
     390                        (void) str_decode(str, &off, strsize);
     391                        cpos.x++;
     392                }
     393
     394                return off;
     395        }
    232396
    233397        cp = str;
     398        off = 0;
    234399        while (*cp != '\0') {
    235                 rc = gfx_font_search_glyph(font, cp, &glyph, &stradv);
     400                rc = gfx_font_search_glyph(fmt->font, cp, &glyph, &stradv);
    236401                if (rc != EOK) {
    237402                        ++cp;
     
    241406                gfx_glyph_get_metrics(glyph, &gmetrics);
    242407
    243                 rc = gfx_glyph_render(glyph, &cpos);
    244                 if (rc != EOK)
    245                         return rc;
     408                if (fpos->x < cpos.x + gmetrics.advance / 2)
     409                        return off;
    246410
    247411                cp += stradv;
     412                off += stradv;
    248413                cpos.x += gmetrics.advance;
    249414        }
    250415
    251         return EOK;
     416        return off;
     417}
     418
     419/** Get text continuation parameters.
     420 *
     421 * Return the anchor position and format needed to continue printing
     422 * text after the specified string. It is allowed for the sources
     423 * (@a pos, @a fmt) and destinations (@a cpos, @a cfmt) to point
     424 * to the same objects, respectively.
     425 *
     426 * @param pos Anchor position
     427 * @param fmt Text formatting
     428 * @param str String
     429 * @param cpos Place to store anchor position for continuation
     430 * @param cfmt Place to store format for continuation
     431 */
     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)
     434{
     435        gfx_coord2_t spos;
     436        gfx_text_fmt_t tfmt;
     437
     438        /* Continuation should start where the current string ends */
     439        gfx_text_start_pos(pos, fmt, str, &spos);
     440        cpos->x = spos.x + gfx_text_width(fmt->font, str);
     441        cpos->y = spos.y;
     442
     443        /*
     444         * Formatting is the same, except the text should be aligned
     445         * so that it starts at the anchor point.
     446         */
     447        tfmt = *fmt;
     448        tfmt.halign = gfx_halign_left;
     449        tfmt.valign = gfx_valign_baseline;
     450
     451        /* Remaining available width */
     452        tfmt.width = fmt->width - (cpos->x - spos.x);
     453
     454        *cfmt = tfmt;
     455}
     456
     457/** Get text bounding rectangle.
     458 *
     459 * @param pos Anchor position
     460 * @param fmt Text formatting
     461 * @param str String
     462 * @param rect Place to store bounding rectangle
     463 */
     464void gfx_text_rect(gfx_coord2_t *pos, gfx_text_fmt_t *fmt, const char *str,
     465    gfx_rect_t *rect)
     466{
     467        gfx_coord2_t 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;
     474
     475        rect->p0.x = spos.x;
     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;
    252479}
    253480
Note: See TracChangeset for help on using the changeset viewer.