source: mainline/uspace/lib/gfxfont/src/text.c@ a0aeb8f

serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a0aeb8f was a0aeb8f, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Fix broken T-shirt slogan

Need to make sure "# hello -d cons@" works well

  • Property mode set to 100644
File size: 9.2 KB
Line 
1/*
2 * Copyright (c) 2021 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libgfxfont
30 * @{
31 */
32/**
33 * @file Text rendering
34 */
35
36#include <errno.h>
37#include <gfx/bitmap.h>
38#include <gfx/color.h>
39#include <gfx/font.h>
40#include <gfx/glyph.h>
41#include <gfx/render.h>
42#include <gfx/text.h>
43#include <io/pixelmap.h>
44#include <mem.h>
45#include <str.h>
46#include "../private/font.h"
47#include "../private/typeface.h"
48
49/** Initialize text formatting structure.
50 *
51 * Text formatting structure must always be initialized using this function
52 * first.
53 *
54 * @param fmt Text formatting structure
55 */
56void gfx_text_fmt_init(gfx_text_fmt_t *fmt)
57{
58 memset(fmt, 0, sizeof(gfx_text_fmt_t));
59}
60
61/** Compute text width.
62 *
63 * @param font Font
64 * @param str String
65 * @return Text width
66 */
67gfx_coord_t gfx_text_width(gfx_font_t *font, const char *str)
68{
69 gfx_glyph_metrics_t gmetrics;
70 size_t stradv;
71 const char *cp;
72 gfx_glyph_t *glyph;
73 gfx_coord_t width;
74 errno_t rc;
75
76 if ((font->finfo->props.flags & gff_text_mode) != 0)
77 return str_width(str);
78
79 width = 0;
80 cp = str;
81 while (*cp != '\0') {
82 rc = gfx_font_search_glyph(font, cp, &glyph, &stradv);
83 if (rc != EOK) {
84 ++cp;
85 continue;
86 }
87
88 gfx_glyph_get_metrics(glyph, &gmetrics);
89
90 cp += stradv;
91 width += gmetrics.advance;
92 }
93
94 return width;
95}
96
97/** Print string using text characters in text mode.
98 *
99 * @param font Font
100 * @param pos Position of top-left corner of text
101 * @param color Text color
102 * @param str String
103 * @return EOK on success or an error code
104 */
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;
109 gfx_bitmap_params_t params;
110 gfx_bitmap_t *bitmap;
111 gfx_bitmap_alloc_t alloc;
112 uint8_t attr;
113 pixelmap_t pmap;
114 gfx_coord_t x;
115 pixel_t pixel;
116 char32_t c;
117 size_t off;
118 errno_t rc;
119
120 /*
121 * NOTE: Creating and destroying bitmap each time is not probably
122 * the most efficient way.
123 */
124
125 gfx_color_get_ega(color, &attr);
126
127 gfx_bitmap_params_init(&params);
128 params.rect.p0.x = 0;
129 params.rect.p0.y = 0;
130 params.rect.p1.x = str_width(str);
131 params.rect.p1.y = 1;
132
133 if (params.rect.p1.x == 0) {
134 /* Nothing to do. Avoid creating bitmap of zero width. */
135 return EOK;
136 }
137
138 rc = gfx_bitmap_create(gc, &params, NULL, &bitmap);
139 if (rc != EOK)
140 return rc;
141
142 rc = gfx_bitmap_get_alloc(bitmap, &alloc);
143 if (rc != EOK) {
144 gfx_bitmap_destroy(bitmap);
145 return rc;
146 }
147
148 pmap.width = params.rect.p1.x;
149 pmap.height = 1;
150 pmap.data = alloc.pixels;
151
152 off = 0;
153 for (x = 0; x < params.rect.p1.x; x++) {
154 c = str_decode(str, &off, STR_NO_LIMIT);
155 pixel = PIXEL(attr,
156 (c >> 16) & 0xff,
157 (c >> 8) & 0xff,
158 c & 0xff);
159 pixelmap_put_pixel(&pmap, x, 0, pixel);
160 }
161
162 rc = gfx_bitmap_render(bitmap, NULL, pos);
163
164 gfx_bitmap_destroy(bitmap);
165 return rc;
166}
167
168/** Get text starting position.
169 *
170 * @param font Font
171 * @param pos Anchor position
172 * @param fmt Text formatting
173 * @param str String
174 * @param spos Place to store starting position
175 */
176void gfx_text_start_pos(gfx_font_t *font, gfx_coord2_t *pos,
177 gfx_text_fmt_t *fmt, const char *str, gfx_coord2_t *spos)
178{
179 gfx_font_metrics_t fmetrics;
180 gfx_coord_t width;
181
182 *spos = *pos;
183
184 /* Adjust position for horizontal alignment */
185 if (fmt->halign != gfx_halign_left) {
186 width = gfx_text_width(font, str);
187 switch (fmt->halign) {
188 case gfx_halign_center:
189 spos->x -= width / 2;
190 break;
191 case gfx_halign_right:
192 spos->x -= width;
193 break;
194 default:
195 break;
196 }
197 }
198
199 /* Adjust position for vertical alignment */
200 gfx_font_get_metrics(font, &fmetrics);
201
202 if (fmt->valign != gfx_valign_baseline) {
203 switch (fmt->valign) {
204 case gfx_valign_top:
205 spos->y += fmetrics.ascent;
206 break;
207 case gfx_valign_center:
208 spos->y += fmetrics.ascent / 2;
209 break;
210 case gfx_valign_bottom:
211 spos->y -= fmetrics.descent + 1;
212 break;
213 default:
214 break;
215 }
216 }
217}
218
219/** Render text.
220 *
221 * @param font Font
222 * @param pos Anchor position
223 * @param fmt Text formatting
224 * @param str String
225 * @return EOK on success or an error code
226 */
227errno_t gfx_puttext(gfx_font_t *font, gfx_coord2_t *pos,
228 gfx_text_fmt_t *fmt, const char *str)
229{
230 gfx_glyph_metrics_t gmetrics;
231 size_t stradv;
232 const char *cp;
233 gfx_glyph_t *glyph;
234 gfx_coord2_t cpos;
235 errno_t rc;
236
237 gfx_text_start_pos(font, pos, fmt, str, &cpos);
238
239 /* Text mode */
240 if ((font->finfo->props.flags & gff_text_mode) != 0)
241 return gfx_puttext_textmode(font, &cpos, fmt->color, str);
242
243 rc = gfx_set_color(font->typeface->gc, fmt->color);
244 if (rc != EOK)
245 return rc;
246
247 cp = str;
248 while (*cp != '\0') {
249 rc = gfx_font_search_glyph(font, cp, &glyph, &stradv);
250 if (rc != EOK) {
251 ++cp;
252 continue;
253 }
254
255 gfx_glyph_get_metrics(glyph, &gmetrics);
256
257 rc = gfx_glyph_render(glyph, &cpos);
258 if (rc != EOK)
259 return rc;
260
261 cp += stradv;
262 cpos.x += gmetrics.advance;
263 }
264
265 return EOK;
266}
267
268/** Find character position in string by X coordinate.
269 *
270 * @param font Font
271 * @param pos Anchor position
272 * @param fmt Text formatting
273 * @param str String
274 * @param fpos Position for which we need to find offset
275 *
276 * @return Byte offset in @a str of character corresponding to position
277 * @a fpos. Note that the position is rounded, that is,
278 * if it is before the center of character A, it will return
279 * offset of A, if it is after the center of A, it will return
280 * offset of the following character.
281 */
282size_t gfx_text_find_pos(gfx_font_t *font, gfx_coord2_t *pos,
283 gfx_text_fmt_t *fmt, const char *str, gfx_coord2_t *fpos)
284{
285 gfx_glyph_metrics_t gmetrics;
286 size_t stradv;
287 const char *cp;
288 gfx_glyph_t *glyph;
289 gfx_coord2_t cpos;
290 size_t off;
291 size_t strsize;
292 errno_t rc;
293
294 gfx_text_start_pos(font, pos, fmt, str, &cpos);
295
296 /* Text mode */
297 if ((font->finfo->props.flags & gff_text_mode) != 0) {
298 off = 0;
299 strsize = str_size(str);
300 while (off < strsize) {
301 if (fpos->x <= cpos.x)
302 return off;
303 (void) str_decode(str, &off, strsize);
304 cpos.x++;
305 }
306
307 return off;
308 }
309
310 cp = str;
311 off = 0;
312 while (*cp != '\0') {
313 rc = gfx_font_search_glyph(font, cp, &glyph, &stradv);
314 if (rc != EOK) {
315 ++cp;
316 continue;
317 }
318
319 gfx_glyph_get_metrics(glyph, &gmetrics);
320
321 if (fpos->x < cpos.x + gmetrics.advance / 2)
322 return off;
323
324 cp += stradv;
325 off += stradv;
326 cpos.x += gmetrics.advance;
327 }
328
329 return off;
330}
331
332/** Get text continuation parameters.
333 *
334 * Return the anchor position and format needed to continue printing
335 * text after the specified string. It is allowed for the sources
336 * (@a pos, @a fmt) and destinations (@a cpos, @a cfmt) to point
337 * to the same objects, respectively.
338 *
339 * @param font Font
340 * @param pos Anchor position
341 * @param fmt Text formatting
342 * @param str String
343 * @param cpos Place to store anchor position for continuation
344 * @param cfmt Place to store format for continuation
345 */
346void gfx_text_cont(gfx_font_t *font, gfx_coord2_t *pos,
347 gfx_text_fmt_t *fmt, const char *str, gfx_coord2_t *cpos,
348 gfx_text_fmt_t *cfmt)
349{
350 gfx_coord2_t spos;
351 gfx_text_fmt_t tfmt;
352
353 /* Continuation should start where the current string ends */
354 gfx_text_start_pos(font, pos, fmt, str, &spos);
355 cpos->x = spos.x + gfx_text_width(font, str);
356 cpos->y = spos.y;
357
358 /*
359 * Formatting is the same, except the text should be aligned
360 * so that it starts at the anchor point.
361 */
362 tfmt = *fmt;
363 tfmt.halign = gfx_halign_left;
364 tfmt.valign = gfx_valign_baseline;
365
366 *cfmt = tfmt;
367}
368
369/** Get text bounding rectangle.
370 *
371 * @param font Font
372 * @param pos Anchor position
373 * @param fmt Text formatting
374 * @param str String
375 * @param rect Place to store bounding rectangle
376 */
377void gfx_text_rect(gfx_font_t *font, gfx_coord2_t *pos,
378 gfx_text_fmt_t *fmt, const char *str, gfx_rect_t *rect)
379{
380 gfx_coord2_t spos;
381
382 gfx_text_start_pos(font, pos, fmt, str, &spos);
383
384 rect->p0.x = spos.x;
385 rect->p0.y = spos.y - font->metrics.ascent;
386 rect->p1.x = spos.x + gfx_text_width(font, str);
387 rect->p1.y = spos.y + font->metrics.descent + 1;
388}
389
390/** @}
391 */
Note: See TracBrowser for help on using the repository browser.