Changes in uspace/lib/gfxfont/src/text.c [f2d4a46:17fac946] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/gfxfont/src/text.c
rf2d4a46 r17fac946 1 1 /* 2 * Copyright (c) 202 2Jiri Svoboda2 * Copyright (c) 2020 Jiri Svoboda 3 3 * All rights reserved. 4 4 * … … 97 97 /** Print string using text characters in text mode. 98 98 * 99 * @param font Font 99 100 * @param pos Position of top-left corner of text 100 * @param fmt Formatting101 * @param color Text color 101 102 * @param str String 102 103 * @return EOK on success or an error code 103 104 */ 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 = f mt->font->typeface->gc;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; 108 109 gfx_bitmap_params_t params; 109 110 gfx_bitmap_t *bitmap; 110 111 gfx_bitmap_alloc_t alloc; 111 gfx_coord_t width; 112 uint8_t attr; 112 uint16_t r, g, b; 113 113 pixelmap_t pmap; 114 114 gfx_coord_t x; 115 gfx_coord_t rmargin;116 115 pixel_t pixel; 117 char32_t c;118 size_t off;119 bool ellipsis;120 116 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 else129 rmargin = width;130 } else {131 ellipsis = false;132 rmargin = width;133 }134 117 135 118 /* … … 138 121 */ 139 122 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); 141 132 142 133 gfx_bitmap_params_init(¶ms); 143 134 params.rect.p0.x = 0; 144 135 params.rect.p0.y = 0; 145 params.rect.p1.x = width;136 params.rect.p1.x = str_width(str); 146 137 params.rect.p1.y = 1; 147 138 … … 165 156 pmap.data = alloc.pixels; 166 157 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); 174 160 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 }186 161 } 187 162 … … 192 167 } 193 168 194 /** Get text starting position.195 *196 * @param pos Anchor position197 * @param fmt Text formatting198 * @param str String199 * @param spos Place to store starting position200 */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 248 169 /** Render text. 249 170 * 171 * @param font Font 250 172 * @param pos Anchor position 251 173 * @param fmt Text formatting … … 253 175 * @return EOK on success or an error code 254 176 */ 255 errno_t gfx_puttext(gfx_ coord2_t *pos, gfx_text_fmt_t *fmt, const char *str)256 { 257 gfx_glyph_metrics_t gmetrics; 177 errno_t gfx_puttext(gfx_font_t *font, gfx_coord2_t *pos, 178 gfx_text_fmt_t *fmt, const char *str) 179 { 258 180 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 position359 * @param fmt Text formatting360 * @param str String361 * @param fpos Position for which we need to find offset362 *363 * @return Byte offset in @a str of character corresponding to position364 * @a fpos. Note that the position is rounded, that is,365 * if it is before the center of character A, it will return366 * offset of A, if it is after the center of A, it will return367 * 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 {372 181 gfx_glyph_metrics_t gmetrics; 373 182 size_t stradv; … … 375 184 gfx_glyph_t *glyph; 376 185 gfx_coord2_t cpos; 377 size_t off; 378 size_t strsize; 186 gfx_coord_t width; 379 187 errno_t rc; 380 188 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 } 382 224 383 225 /* 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; 396 232 397 233 cp = str; 398 off = 0;399 234 while (*cp != '\0') { 400 rc = gfx_font_search_glyph(f mt->font, cp, &glyph, &stradv);235 rc = gfx_font_search_glyph(font, cp, &glyph, &stradv); 401 236 if (rc != EOK) { 402 237 ++cp; … … 406 241 gfx_glyph_get_metrics(glyph, &gmetrics); 407 242 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; 410 246 411 247 cp += stradv; 412 off += stradv;413 248 cpos.x += gmetrics.advance; 414 249 } 415 250 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; 479 252 } 480 253
Note:
See TracChangeset
for help on using the changeset viewer.