Ignore:
File:
1 edited

Legend:

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

    rf2d4a46 r17fac946  
    11/*
    2  * Copyright (c) 2022 Jiri Svoboda
     2 * Copyright (c) 2020 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    9797/** Print string using text characters in text mode.
    9898 *
     99 * @param font Font
    99100 * @param pos Position of top-left corner of text
    100  * @param fmt Formatting
     101 * @param color Text color
    101102 * @param str String
    102103 * @return EOK on success or an error code
    103104 */
    104 static 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;
     105static 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;
    108109        gfx_bitmap_params_t params;
    109110        gfx_bitmap_t *bitmap;
    110111        gfx_bitmap_alloc_t alloc;
    111         gfx_coord_t width;
    112         uint8_t attr;
     112        uint16_t r, g, b;
    113113        pixelmap_t pmap;
    114114        gfx_coord_t x;
    115         gfx_coord_t rmargin;
    116115        pixel_t pixel;
    117         char32_t c;
    118         size_t off;
    119         bool ellipsis;
    120116        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         }
    134117
    135118        /*
     
    138121         */
    139122
    140         gfx_color_get_ega(fmt->color, &attr);
     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);
    141132
    142133        gfx_bitmap_params_init(&params);
    143134        params.rect.p0.x = 0;
    144135        params.rect.p0.y = 0;
    145         params.rect.p1.x = width;
     136        params.rect.p1.x = str_width(str);
    146137        params.rect.p1.y = 1;
    147138
     
    165156        pmap.data = alloc.pixels;
    166157
    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);
     158        for (x = 0; x < params.rect.p1.x; x++) {
     159                pixel = PIXEL(str[x], r, g, b);
    174160                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                 }
    186161        }
    187162
     
    192167}
    193168
    194 /** Get text starting position.
    195  *
    196  * @param pos Anchor position
    197  * @param fmt Text formatting
    198  * @param str String
    199  * @param spos Place to store starting position
    200  */
    201 void 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 
    248169/** Render text.
    249170 *
     171 * @param font Font
    250172 * @param pos Anchor position
    251173 * @param fmt Text formatting
     
    253175 * @return EOK on success or an error code
    254176 */
    255 errno_t gfx_puttext(gfx_coord2_t *pos, gfx_text_fmt_t *fmt, const char *str)
    256 {
    257         gfx_glyph_metrics_t gmetrics;
     177errno_t gfx_puttext(gfx_font_t *font, gfx_coord2_t *pos,
     178    gfx_text_fmt_t *fmt, const char *str)
     179{
    258180        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  */
    369 size_t gfx_text_find_pos(gfx_coord2_t *pos, gfx_text_fmt_t *fmt,
    370     const char *str, gfx_coord2_t *fpos)
    371 {
    372181        gfx_glyph_metrics_t gmetrics;
    373182        size_t stradv;
     
    375184        gfx_glyph_t *glyph;
    376185        gfx_coord2_t cpos;
    377         size_t off;
    378         size_t strsize;
     186        gfx_coord_t width;
    379187        errno_t rc;
    380188
    381         gfx_text_start_pos(pos, fmt, str, &cpos);
     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        }
    382224
    383225        /* Text mode */
    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         }
     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;
    396232
    397233        cp = str;
    398         off = 0;
    399234        while (*cp != '\0') {
    400                 rc = gfx_font_search_glyph(fmt->font, cp, &glyph, &stradv);
     235                rc = gfx_font_search_glyph(font, cp, &glyph, &stradv);
    401236                if (rc != EOK) {
    402237                        ++cp;
     
    406241                gfx_glyph_get_metrics(glyph, &gmetrics);
    407242
    408                 if (fpos->x < cpos.x + gmetrics.advance / 2)
    409                         return off;
     243                rc = gfx_glyph_render(glyph, &cpos);
     244                if (rc != EOK)
     245                        return rc;
    410246
    411247                cp += stradv;
    412                 off += stradv;
    413248                cpos.x += gmetrics.advance;
    414249        }
    415250
    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  */
    432 void 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  */
    464 void 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;
     251        return EOK;
    479252}
    480253
Note: See TracChangeset for help on using the changeset viewer.