Changes in uspace/lib/gfxfont/src/text.c [f2d4a46:0d62c10] in mainline
- File:
-
- 1 edited
-
uspace/lib/gfxfont/src/text.c (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/gfxfont/src/text.c
rf2d4a46 r0d62c10 1 1 /* 2 * Copyright (c) 202 2Jiri Svoboda2 * Copyright (c) 2020 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>39 37 #include <gfx/font.h> 40 38 #include <gfx/glyph.h> 41 #include <gfx/render.h>42 39 #include <gfx/text.h> 43 #include <io/pixelmap.h>44 40 #include <mem.h> 45 #include <str.h>46 #include "../private/font.h"47 #include "../private/typeface.h"48 41 49 42 /** Initialize text formatting structure. … … 74 67 errno_t rc; 75 68 76 if ((font->finfo->props.flags & gff_text_mode) != 0)77 return str_width(str);78 79 69 width = 0; 80 70 cp = str; … … 95 85 } 96 86 97 /** Print string using text characters in text mode.87 /** Render text. 98 88 * 99 * @param pos Position of top-left corner of text 100 * @param fmt Formatting 89 * @param font Font 90 * @param pos Anchor position 91 * @param fmt Text formatting 101 92 * @param str String 102 93 * @return EOK on success or an error code 103 94 */ 104 static errno_t gfx_puttext_textmode(gfx_coord2_t *pos, gfx_text_fmt_t *fmt,105 const char *str)95 errno_t gfx_puttext(gfx_font_t *font, gfx_coord2_t *pos, 96 gfx_text_fmt_t *fmt, const char *str) 106 97 { 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; 98 gfx_font_metrics_t fmetrics; 99 gfx_glyph_metrics_t gmetrics; 100 size_t stradv; 101 const char *cp; 102 gfx_glyph_t *glyph; 103 gfx_coord2_t cpos; 111 104 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 105 errno_t rc; 121 106 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 * 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; 107 cpos = *pos; 208 108 209 109 /* Adjust position for horizontal alignment */ 210 110 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 111 width = gfx_text_width(font, str); 216 112 switch (fmt->halign) { 217 113 case gfx_halign_center: 218 spos->x -= width / 2;114 cpos.x -= width / 2; 219 115 break; 220 116 case gfx_halign_right: 221 spos->x -= width;117 cpos.x -= width; 222 118 break; 223 119 default: … … 227 123 228 124 /* Adjust position for vertical alignment */ 229 gfx_font_get_metrics(f mt->font, &fmetrics);125 gfx_font_get_metrics(font, &fmetrics); 230 126 231 127 if (fmt->valign != gfx_valign_baseline) { 232 128 switch (fmt->valign) { 233 129 case gfx_valign_top: 234 spos->y += fmetrics.ascent;130 cpos.y += fmetrics.ascent; 235 131 break; 236 132 case gfx_valign_center: 237 spos->y += fmetrics.ascent / 2;133 cpos.y += fmetrics.ascent / 2; 238 134 break; 239 135 case gfx_valign_bottom: 240 spos->y -= fmetrics.descent + 1;136 cpos.y -= fmetrics.descent; 241 137 break; 242 138 default: … … 244 140 } 245 141 } 246 }247 142 248 /** Render text.249 *250 * @param pos Anchor position251 * @param fmt Text formatting252 * @param str String253 * @return EOK on success or an error code254 */255 errno_t gfx_puttext(gfx_coord2_t *pos, gfx_text_fmt_t *fmt, const char *str)256 {257 gfx_glyph_metrics_t gmetrics;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 143 cp = str; 293 144 while (*cp != '\0') { 294 rc = gfx_font_search_glyph(f mt->font, cp, &glyph, &stradv);145 rc = gfx_font_search_glyph(font, cp, &glyph, &stradv); 295 146 if (rc != EOK) { 296 147 ++cp; … … 299 150 300 151 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 152 306 153 rc = gfx_glyph_render(glyph, &cpos); … … 312 159 } 313 160 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 161 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 gfx_glyph_metrics_t gmetrics;373 size_t stradv;374 const char *cp;375 gfx_glyph_t *glyph;376 gfx_coord2_t cpos;377 size_t off;378 size_t strsize;379 errno_t rc;380 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;395 }396 397 cp = str;398 off = 0;399 while (*cp != '\0') {400 rc = gfx_font_search_glyph(fmt->font, cp, &glyph, &stradv);401 if (rc != EOK) {402 ++cp;403 continue;404 }405 406 gfx_glyph_get_metrics(glyph, &gmetrics);407 408 if (fpos->x < cpos.x + gmetrics.advance / 2)409 return off;410 411 cp += stradv;412 off += stradv;413 cpos.x += gmetrics.advance;414 }415 416 return off;417 }418 419 /** Get text continuation parameters.420 *421 * Return the anchor position and format needed to continue printing422 * text after the specified string. It is allowed for the sources423 * (@a pos, @a fmt) and destinations (@a cpos, @a cfmt) to point424 * to the same objects, respectively.425 *426 * @param pos Anchor position427 * @param fmt Text formatting428 * @param str String429 * @param cpos Place to store anchor position for continuation430 * @param cfmt Place to store format for continuation431 */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 aligned445 * 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 position460 * @param fmt Text formatting461 * @param str String462 * @param rect Place to store bounding rectangle463 */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;479 162 } 480 163
Note:
See TracChangeset
for help on using the changeset viewer.
