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