source: mainline/uspace/lib/gfxfont/test/text.c@ ab3bfc1

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

Entry text selection (using keyboard)

Text can be selected with movement keys while holding down Shift.
Selection can be deleted by pressing Backspace, Delete or typing
in replacement text.

  • Property mode set to 100644
File size: 12.6 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#include <gfx/color.h>
30#include <gfx/context.h>
31#include <gfx/font.h>
32#include <gfx/glyph.h>
33#include <gfx/text.h>
34#include <gfx/typeface.h>
35#include <pcut/pcut.h>
36#include "../private/font.h"
37#include "../private/typeface.h"
38
39PCUT_INIT;
40
41PCUT_TEST_SUITE(text);
42
43static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
44static errno_t testgc_set_color(void *, gfx_color_t *);
45static errno_t testgc_fill_rect(void *, gfx_rect_t *);
46static errno_t testgc_bitmap_create(void *, gfx_bitmap_params_t *,
47 gfx_bitmap_alloc_t *, void **);
48static errno_t testgc_bitmap_destroy(void *);
49static errno_t testgc_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
50static errno_t testgc_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
51
52static gfx_context_ops_t test_ops = {
53 .set_clip_rect = testgc_set_clip_rect,
54 .set_color = testgc_set_color,
55 .fill_rect = testgc_fill_rect,
56 .bitmap_create = testgc_bitmap_create,
57 .bitmap_destroy = testgc_bitmap_destroy,
58 .bitmap_render = testgc_bitmap_render,
59 .bitmap_get_alloc = testgc_bitmap_get_alloc
60};
61
62typedef struct {
63 gfx_bitmap_params_t bm_params;
64 void *bm_pixels;
65 gfx_rect_t bm_srect;
66 gfx_coord2_t bm_offs;
67} test_gc_t;
68
69typedef struct {
70 test_gc_t *tgc;
71 gfx_bitmap_alloc_t alloc;
72 bool myalloc;
73} testgc_bitmap_t;
74
75/** Test text width computation with a dummy font */
76PCUT_TEST(dummy_text_width)
77{
78 gfx_font_props_t props;
79 gfx_font_metrics_t metrics;
80 gfx_typeface_t *tface;
81 gfx_font_t *font;
82 gfx_context_t *gc;
83 gfx_coord_t width;
84 test_gc_t tgc;
85 errno_t rc;
86
87 rc = gfx_context_new(&test_ops, (void *)&tgc, &gc);
88 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
89
90 rc = gfx_typeface_create(gc, &tface);
91 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
92
93 gfx_font_props_init(&props);
94 gfx_font_metrics_init(&metrics);
95 rc = gfx_font_create(tface, &props, &metrics, &font);
96 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
97
98 width = gfx_text_width(font, "Hello world!");
99 PCUT_ASSERT_INT_EQUALS(0, width);
100
101 gfx_font_close(font);
102 gfx_typeface_destroy(tface);
103
104 rc = gfx_context_delete(gc);
105 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
106}
107
108/** Test text rendering with a dummy font */
109PCUT_TEST(dummy_puttext)
110{
111 gfx_font_props_t props;
112 gfx_font_metrics_t metrics;
113 gfx_typeface_t *tface;
114 gfx_font_t *font;
115 gfx_context_t *gc;
116 gfx_color_t *color;
117 gfx_text_fmt_t fmt;
118 gfx_coord2_t pos;
119 test_gc_t tgc;
120 errno_t rc;
121
122 rc = gfx_context_new(&test_ops, (void *)&tgc, &gc);
123 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
124
125 rc = gfx_color_new_rgb_i16(0, 0, 0, &color);
126 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
127
128 rc = gfx_typeface_create(gc, &tface);
129 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
130
131 gfx_font_props_init(&props);
132 gfx_font_metrics_init(&metrics);
133 rc = gfx_font_create(tface, &props, &metrics, &font);
134 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
135
136 gfx_text_fmt_init(&fmt);
137 fmt.color = color;
138 pos.x = 0;
139 pos.y = 0;
140
141 rc = gfx_puttext(font, &pos, &fmt, "Hello world!");
142 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
143
144 gfx_font_close(font);
145 gfx_typeface_destroy(tface);
146 gfx_color_delete(color);
147
148 rc = gfx_context_delete(gc);
149 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
150}
151
152/** gfx_text_start_pos() correctly computes text start position */
153PCUT_TEST(text_start_pos)
154{
155 gfx_font_props_t props;
156 gfx_font_metrics_t metrics;
157 gfx_typeface_t *tface;
158 gfx_font_t *font;
159 gfx_context_t *gc;
160 gfx_color_t *color;
161 gfx_text_fmt_t fmt;
162 gfx_coord2_t pos;
163 test_gc_t tgc;
164 errno_t rc;
165
166 rc = gfx_context_new(&test_ops, (void *)&tgc, &gc);
167 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
168
169 rc = gfx_color_new_rgb_i16(0, 0, 0, &color);
170 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
171
172 rc = gfx_typeface_create(gc, &tface);
173 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
174
175 gfx_font_props_init(&props);
176 gfx_font_metrics_init(&metrics);
177 metrics.ascent = 10; // XXX
178 metrics.descent = 10; // XXX
179 rc = gfx_font_create(tface, &props, &metrics, &font);
180 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
181
182 gfx_text_fmt_init(&fmt);
183 fmt.color = color;
184 pos.x = 0;
185 pos.y = 0;
186
187 rc = gfx_puttext(font, &pos, &fmt, "Hello world!");
188 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
189
190 gfx_font_close(font);
191 gfx_typeface_destroy(tface);
192 gfx_color_delete(color);
193
194 rc = gfx_context_delete(gc);
195 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
196}
197
198/** gfx_text_find_pos() finds position in text */
199PCUT_TEST(text_find_pos)
200{
201 gfx_font_props_t props;
202 gfx_font_metrics_t metrics;
203 gfx_typeface_t *tface;
204 gfx_font_t *font;
205 gfx_glyph_metrics_t gmetrics;
206 gfx_glyph_t *glyph1;
207 gfx_glyph_t *glyph2;
208 gfx_context_t *gc;
209 gfx_text_fmt_t fmt;
210 gfx_coord2_t anchor;
211 gfx_coord2_t fpos;
212 size_t off;
213 test_gc_t tgc;
214 errno_t rc;
215
216 rc = gfx_context_new(&test_ops, (void *)&tgc, &gc);
217 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
218
219 rc = gfx_typeface_create(gc, &tface);
220 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
221
222 gfx_font_props_init(&props);
223 gfx_font_metrics_init(&metrics);
224 rc = gfx_font_create(tface, &props, &metrics, &font);
225 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
226
227 /* Need to create some glyphs with metrics */
228 gfx_glyph_metrics_init(&gmetrics);
229 gmetrics.advance = 10;
230
231 rc = gfx_glyph_create(font, &gmetrics, &glyph1);
232 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
233
234 rc = gfx_glyph_set_pattern(glyph1, "A");
235 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
236
237 gfx_glyph_metrics_init(&gmetrics);
238 gmetrics.advance = 1;
239
240 rc = gfx_glyph_create(font, &gmetrics, &glyph2);
241 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
242
243 rc = gfx_glyph_set_pattern(glyph2, "i");
244 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
245
246 gfx_text_fmt_init(&fmt);
247 anchor.x = 10;
248 anchor.y = 0;
249
250 fpos.x = 9;
251 fpos.y = 0;
252 off = gfx_text_find_pos(font, &anchor, &fmt, "Aii", &fpos);
253 PCUT_ASSERT_INT_EQUALS(0, off);
254
255 fpos.x = 10;
256 fpos.y = 0;
257 off = gfx_text_find_pos(font, &anchor, &fmt, "Aii", &fpos);
258 PCUT_ASSERT_INT_EQUALS(0, off);
259
260 fpos.x = 11;
261 fpos.y = 0;
262 off = gfx_text_find_pos(font, &anchor, &fmt, "Aii", &fpos);
263 PCUT_ASSERT_INT_EQUALS(0, off);
264
265 fpos.x = 19;
266 fpos.y = 0;
267 off = gfx_text_find_pos(font, &anchor, &fmt, "Aii", &fpos);
268 PCUT_ASSERT_INT_EQUALS(1, off);
269
270 fpos.x = 20;
271 fpos.y = 0;
272 off = gfx_text_find_pos(font, &anchor, &fmt, "Aii", &fpos);
273 PCUT_ASSERT_INT_EQUALS(2, off);
274
275 fpos.x = 21;
276 fpos.y = 0;
277 off = gfx_text_find_pos(font, &anchor, &fmt, "Aii", &fpos);
278 PCUT_ASSERT_INT_EQUALS(3, off);
279
280 fpos.x = 22;
281 fpos.y = 0;
282 off = gfx_text_find_pos(font, &anchor, &fmt, "Aii", &fpos);
283 PCUT_ASSERT_INT_EQUALS(3, off);
284
285 gfx_glyph_destroy(glyph1);
286 gfx_glyph_destroy(glyph2);
287
288 gfx_font_close(font);
289 gfx_typeface_destroy(tface);
290
291 rc = gfx_context_delete(gc);
292 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
293}
294
295/** gfx_text_find_pos() finds position in text in text mode */
296PCUT_TEST(text_find_pos_text)
297{
298 gfx_typeface_t *tface;
299 gfx_font_t *font;
300 gfx_context_t *gc;
301 test_gc_t tgc;
302 size_t off;
303 gfx_text_fmt_t fmt;
304 gfx_coord2_t anchor;
305 gfx_coord2_t fpos;
306 errno_t rc;
307
308 rc = gfx_context_new(&test_ops, (void *)&tgc, &gc);
309 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
310
311 rc = gfx_typeface_create(gc, &tface);
312 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
313
314 rc = gfx_font_create_textmode(tface, &font);
315 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
316
317 anchor.x = 10;
318 anchor.y = 0;
319 gfx_text_fmt_init(&fmt);
320
321 fpos.x = 9;
322 fpos.y = 0;
323 off = gfx_text_find_pos(font, &anchor, &fmt, "Abc", &fpos);
324 PCUT_ASSERT_INT_EQUALS(0, off);
325
326 fpos.x = 10;
327 fpos.y = 0;
328 off = gfx_text_find_pos(font, &anchor, &fmt, "Abc", &fpos);
329 PCUT_ASSERT_INT_EQUALS(0, off);
330
331 fpos.x = 11;
332 fpos.y = 0;
333 off = gfx_text_find_pos(font, &anchor, &fmt, "Abc", &fpos);
334 PCUT_ASSERT_INT_EQUALS(1, off);
335
336 fpos.x = 12;
337 fpos.y = 0;
338 off = gfx_text_find_pos(font, &anchor, &fmt, "Abc", &fpos);
339 PCUT_ASSERT_INT_EQUALS(2, off);
340
341 fpos.x = 13;
342 fpos.y = 0;
343 off = gfx_text_find_pos(font, &anchor, &fmt, "Abc", &fpos);
344 PCUT_ASSERT_INT_EQUALS(3, off);
345
346 fpos.x = 14;
347 fpos.y = 0;
348 off = gfx_text_find_pos(font, &anchor, &fmt, "Abc", &fpos);
349 PCUT_ASSERT_INT_EQUALS(3, off);
350
351 gfx_font_close(font);
352 gfx_typeface_destroy(tface);
353
354 rc = gfx_context_delete(gc);
355 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
356}
357
358/** gfx_text_cont() produces correct continuation parameters */
359PCUT_TEST(text_cont)
360{
361 gfx_typeface_t *tface;
362 gfx_font_t *font;
363 gfx_context_t *gc;
364 gfx_color_t *color;
365 test_gc_t tgc;
366 gfx_text_fmt_t fmt;
367 gfx_coord2_t anchor;
368 gfx_coord2_t cpos;
369 gfx_text_fmt_t cfmt;
370 errno_t rc;
371
372 rc = gfx_context_new(&test_ops, (void *)&tgc, &gc);
373 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
374
375 rc = gfx_typeface_create(gc, &tface);
376 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
377
378 rc = gfx_font_create_textmode(tface, &font);
379 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
380
381 rc = gfx_color_new_rgb_i16(0, 0, 0, &color);
382 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
383
384 anchor.x = 10;
385 anchor.y = 20;
386 gfx_text_fmt_init(&fmt);
387 fmt.color = color;
388
389 gfx_text_cont(font, &anchor, &fmt, "Abc", &cpos, &cfmt);
390
391 PCUT_ASSERT_INT_EQUALS(13, cpos.x);
392 PCUT_ASSERT_INT_EQUALS(20, cpos.y);
393 PCUT_ASSERT_EQUALS(fmt.color, cfmt.color);
394 PCUT_ASSERT_EQUALS(gfx_halign_left, cfmt.halign);
395 PCUT_ASSERT_EQUALS(gfx_valign_baseline, cfmt.valign);
396
397 gfx_font_close(font);
398 gfx_typeface_destroy(tface);
399 gfx_color_delete(color);
400
401 rc = gfx_context_delete(gc);
402 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
403}
404
405/** gfx_text_rect() computes bounding rectangle */
406PCUT_TEST(text_rect)
407{
408 gfx_typeface_t *tface;
409 gfx_font_t *font;
410 gfx_context_t *gc;
411 gfx_color_t *color;
412 test_gc_t tgc;
413 gfx_text_fmt_t fmt;
414 gfx_coord2_t anchor;
415 gfx_rect_t rect;
416 errno_t rc;
417
418 rc = gfx_context_new(&test_ops, (void *)&tgc, &gc);
419 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
420
421 rc = gfx_typeface_create(gc, &tface);
422 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
423
424 rc = gfx_font_create_textmode(tface, &font);
425 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
426
427 rc = gfx_color_new_rgb_i16(0, 0, 0, &color);
428 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
429
430 anchor.x = 10;
431 anchor.y = 20;
432 gfx_text_fmt_init(&fmt);
433 fmt.color = color;
434
435 gfx_text_rect(font, &anchor, &fmt, "Abc", &rect);
436
437 PCUT_ASSERT_INT_EQUALS(10, rect.p0.x);
438 PCUT_ASSERT_INT_EQUALS(20, rect.p0.y);
439 PCUT_ASSERT_INT_EQUALS(13, rect.p1.x);
440 PCUT_ASSERT_INT_EQUALS(21, rect.p1.y);
441
442 gfx_font_close(font);
443 gfx_typeface_destroy(tface);
444 gfx_color_delete(color);
445
446 rc = gfx_context_delete(gc);
447 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
448}
449
450static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
451{
452 return EOK;
453}
454
455static errno_t testgc_set_color(void *arg, gfx_color_t *color)
456{
457 return EOK;
458}
459
460static errno_t testgc_fill_rect(void *arg, gfx_rect_t *rect)
461{
462 return EOK;
463}
464
465static errno_t testgc_bitmap_create(void *arg, gfx_bitmap_params_t *params,
466 gfx_bitmap_alloc_t *alloc, void **rbm)
467{
468 test_gc_t *tgc = (test_gc_t *) arg;
469 testgc_bitmap_t *tbm;
470
471 tbm = calloc(1, sizeof(testgc_bitmap_t));
472 if (tbm == NULL)
473 return ENOMEM;
474
475 if (alloc == NULL) {
476 tbm->alloc.pitch = (params->rect.p1.x - params->rect.p0.x) *
477 sizeof(uint32_t);
478 tbm->alloc.off0 = 0;
479 tbm->alloc.pixels = calloc(sizeof(uint32_t),
480 tbm->alloc.pitch * (params->rect.p1.y - params->rect.p0.y));
481 tbm->myalloc = true;
482 if (tbm->alloc.pixels == NULL) {
483 free(tbm);
484 return ENOMEM;
485 }
486 } else {
487 tbm->alloc = *alloc;
488 }
489
490 tbm->tgc = tgc;
491 tgc->bm_params = *params;
492 tgc->bm_pixels = tbm->alloc.pixels;
493 *rbm = (void *)tbm;
494 return EOK;
495}
496
497static errno_t testgc_bitmap_destroy(void *bm)
498{
499 testgc_bitmap_t *tbm = (testgc_bitmap_t *)bm;
500 if (tbm->myalloc)
501 free(tbm->alloc.pixels);
502 free(tbm);
503 return EOK;
504}
505
506static errno_t testgc_bitmap_render(void *bm, gfx_rect_t *srect,
507 gfx_coord2_t *offs)
508{
509 testgc_bitmap_t *tbm = (testgc_bitmap_t *)bm;
510 tbm->tgc->bm_srect = *srect;
511 tbm->tgc->bm_offs = *offs;
512 return EOK;
513}
514
515static errno_t testgc_bitmap_get_alloc(void *bm, gfx_bitmap_alloc_t *alloc)
516{
517 testgc_bitmap_t *tbm = (testgc_bitmap_t *)bm;
518 *alloc = tbm->alloc;
519 return EOK;
520}
521
522PCUT_EXPORT(text);
Note: See TracBrowser for help on using the repository browser.