Changes in uspace/lib/gfxfont/src/text.c [0d62c10:f2d4a46] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/gfxfont/src/text.c
r0d62c10 rf2d4a46 1 1 /* 2 * Copyright (c) 202 0Jiri Svoboda2 * Copyright (c) 2022 Jiri Svoboda 3 3 * All rights reserved. 4 4 * … … 35 35 36 36 #include <errno.h> 37 #include <gfx/bitmap.h> 38 #include <gfx/color.h> 37 39 #include <gfx/font.h> 38 40 #include <gfx/glyph.h> 41 #include <gfx/render.h> 39 42 #include <gfx/text.h> 43 #include <io/pixelmap.h> 40 44 #include <mem.h> 45 #include <str.h> 46 #include "../private/font.h" 47 #include "../private/typeface.h" 41 48 42 49 /** Initialize text formatting structure. … … 66 73 gfx_coord_t width; 67 74 errno_t rc; 75 76 if ((font->finfo->props.flags & gff_text_mode) != 0) 77 return str_width(str); 68 78 69 79 width = 0; … … 85 95 } 86 96 87 /** Render text. 88 * 89 * @param font Font 97 /** Print string using text characters in text mode. 98 * 99 * @param pos Position of top-left corner of text 100 * @param fmt Formatting 101 * @param str String 102 * @return EOK on success or an error code 103 */ 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; 108 gfx_bitmap_params_t params; 109 gfx_bitmap_t *bitmap; 110 gfx_bitmap_alloc_t alloc; 111 gfx_coord_t width; 112 uint8_t attr; 113 pixelmap_t pmap; 114 gfx_coord_t x; 115 gfx_coord_t rmargin; 116 pixel_t pixel; 117 char32_t c; 118 size_t off; 119 bool ellipsis; 120 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 } 134 135 /* 136 * NOTE: Creating and destroying bitmap each time is not probably 137 * the most efficient way. 138 */ 139 140 gfx_color_get_ega(fmt->color, &attr); 141 142 gfx_bitmap_params_init(¶ms); 143 params.rect.p0.x = 0; 144 params.rect.p0.y = 0; 145 params.rect.p1.x = width; 146 params.rect.p1.y = 1; 147 148 if (params.rect.p1.x == 0) { 149 /* Nothing to do. Avoid creating bitmap of zero width. */ 150 return EOK; 151 } 152 153 rc = gfx_bitmap_create(gc, ¶ms, NULL, &bitmap); 154 if (rc != EOK) 155 return rc; 156 157 rc = gfx_bitmap_get_alloc(bitmap, &alloc); 158 if (rc != EOK) { 159 gfx_bitmap_destroy(bitmap); 160 return rc; 161 } 162 163 pmap.width = params.rect.p1.x; 164 pmap.height = 1; 165 pmap.data = alloc.pixels; 166 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); 174 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 } 187 188 rc = gfx_bitmap_render(bitmap, NULL, pos); 189 190 gfx_bitmap_destroy(bitmap); 191 return rc; 192 } 193 194 /** Get text starting position. 195 * 90 196 * @param pos Anchor position 91 197 * @param fmt Text formatting 92 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 248 /** Render text. 249 * 250 * @param pos Anchor position 251 * @param fmt Text formatting 252 * @param str String 93 253 * @return EOK on success or an error code 94 254 */ 95 errno_t gfx_puttext(gfx_ font_t *font, gfx_coord2_t *pos,96 gfx_text_fmt_t *fmt, const char *str) 97 { 255 errno_t gfx_puttext(gfx_coord2_t *pos, gfx_text_fmt_t *fmt, const char *str) 256 { 257 gfx_glyph_metrics_t gmetrics; 98 258 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 { 99 372 gfx_glyph_metrics_t gmetrics; 100 373 size_t stradv; … … 102 375 gfx_glyph_t *glyph; 103 376 gfx_coord2_t cpos; 104 gfx_coord_t width; 377 size_t off; 378 size_t strsize; 105 379 errno_t rc; 106 380 107 cpos = *pos; 108 109 /* Adjust position for horizontal alignment */ 110 if (fmt->halign != gfx_halign_left) { 111 width = gfx_text_width(font, str); 112 switch (fmt->halign) { 113 case gfx_halign_center: 114 cpos.x -= width / 2; 115 break; 116 case gfx_halign_right: 117 cpos.x -= width; 118 break; 119 default: 120 break; 121 } 122 } 123 124 /* Adjust position for vertical alignment */ 125 gfx_font_get_metrics(font, &fmetrics); 126 127 if (fmt->valign != gfx_valign_baseline) { 128 switch (fmt->valign) { 129 case gfx_valign_top: 130 cpos.y += fmetrics.ascent; 131 break; 132 case gfx_valign_center: 133 cpos.y += fmetrics.ascent / 2; 134 break; 135 case gfx_valign_bottom: 136 cpos.y -= fmetrics.descent; 137 break; 138 default: 139 break; 140 } 381 gfx_text_start_pos(pos, fmt, str, &cpos); 382 383 /* 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; 141 395 } 142 396 143 397 cp = str; 398 off = 0; 144 399 while (*cp != '\0') { 145 rc = gfx_font_search_glyph(f ont, cp, &glyph, &stradv);400 rc = gfx_font_search_glyph(fmt->font, cp, &glyph, &stradv); 146 401 if (rc != EOK) { 147 402 ++cp; … … 151 406 gfx_glyph_get_metrics(glyph, &gmetrics); 152 407 153 rc = gfx_glyph_render(glyph, &cpos); 154 if (rc != EOK) 155 return rc; 408 if (fpos->x < cpos.x + gmetrics.advance / 2) 409 return off; 156 410 157 411 cp += stradv; 412 off += stradv; 158 413 cpos.x += gmetrics.advance; 159 414 } 160 415 161 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 */ 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; 162 479 } 163 480
Note:
See TracChangeset
for help on using the changeset viewer.