| /* |
| * Copyright 2012 Google, Inc. All Rights Reserved. |
| * Copyright 2026 Behdad Esfahbod. All Rights Reserved. |
| */ |
| |
| #include "demo-buffer.h" |
| |
| struct demo_buffer_t { |
| demo_point_t cursor; |
| std::vector<glyph_vertex_t> *vertices; |
| demo_extents_t ink_extents; |
| demo_extents_t logical_extents; |
| }; |
| |
| demo_buffer_t * |
| demo_buffer_create (void) |
| { |
| demo_buffer_t *buffer = (demo_buffer_t *) calloc (1, sizeof (demo_buffer_t)); |
| |
| buffer->vertices = new std::vector<glyph_vertex_t>; |
| |
| demo_buffer_clear (buffer); |
| |
| return buffer; |
| } |
| |
| void |
| demo_buffer_destroy (demo_buffer_t *buffer) |
| { |
| if (!buffer) |
| return; |
| |
| delete buffer->vertices; |
| free (buffer); |
| } |
| |
| |
| void |
| demo_buffer_clear (demo_buffer_t *buffer) |
| { |
| buffer->vertices->clear (); |
| demo_extents_clear (&buffer->ink_extents); |
| demo_extents_clear (&buffer->logical_extents); |
| } |
| |
| void |
| demo_buffer_extents (demo_buffer_t *buffer, |
| demo_extents_t *ink_extents, |
| demo_extents_t *logical_extents) |
| { |
| if (ink_extents) |
| *ink_extents = buffer->ink_extents; |
| if (logical_extents) |
| *logical_extents = buffer->logical_extents; |
| } |
| |
| void |
| demo_buffer_move_to (demo_buffer_t *buffer, |
| const demo_point_t *p) |
| { |
| buffer->cursor = *p; |
| } |
| |
| void |
| demo_buffer_add_text (demo_buffer_t *buffer, |
| const char *utf8, |
| demo_font_t *font, |
| double font_size) |
| { |
| hb_face_t *hb_face = demo_font_get_face (font); |
| hb_font_t *hb_font = demo_font_get_font (font); |
| hb_buffer_t *hb_buffer = hb_buffer_create (); |
| |
| demo_point_t top_left = buffer->cursor; |
| buffer->cursor.y += font_size; |
| double scale = font_size / hb_face_get_upem (hb_face); |
| |
| while (utf8) |
| { |
| const char *end = strchr (utf8, '\n'); |
| |
| hb_buffer_clear_contents (hb_buffer); |
| hb_buffer_add_utf8 (hb_buffer, utf8, end ? end - utf8 : -1, 0, -1); |
| hb_buffer_guess_segment_properties (hb_buffer); |
| hb_shape (hb_font, hb_buffer, NULL, 0); |
| |
| unsigned count; |
| hb_glyph_info_t *infos = hb_buffer_get_glyph_infos (hb_buffer, &count); |
| hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (hb_buffer, NULL); |
| for (unsigned i = 0; i < count; i++) |
| { |
| unsigned int glyph_index = infos[i].codepoint; |
| glyph_info_t gi; |
| demo_font_lookup_glyph (font, glyph_index, &gi); |
| |
| demo_extents_t ink_extents; |
| demo_point_t position = buffer->cursor; |
| position.x += scale * pos[i].x_offset; |
| position.y -= scale * pos[i].y_offset; |
| demo_shader_add_glyph_vertices (position, font_size, &gi, buffer->vertices, &ink_extents); |
| demo_extents_extend (&buffer->ink_extents, &ink_extents); |
| |
| demo_point_t corner; |
| corner.x = buffer->cursor.x; |
| corner.y = buffer->cursor.y - font_size; |
| demo_extents_add (&buffer->logical_extents, &corner); |
| corner.x = buffer->cursor.x + scale * gi.advance; |
| corner.y = buffer->cursor.y; |
| demo_extents_add (&buffer->logical_extents, &corner); |
| |
| buffer->cursor.x += scale * pos[i].x_advance; |
| } |
| |
| if (end) { |
| buffer->cursor.y += font_size; |
| buffer->cursor.x = top_left.x; |
| utf8 = end + 1; |
| } |
| else |
| utf8 = NULL; |
| } |
| |
| hb_buffer_destroy (hb_buffer); |
| } |
| |
| void |
| demo_buffer_current_line (demo_buffer_t *buffer, |
| double font_size) |
| { |
| buffer->cursor.x = 0; |
| buffer->cursor.y += font_size; |
| } |
| |
| void |
| demo_buffer_add_glyph (demo_buffer_t *buffer, |
| demo_font_t *font, |
| double font_size, |
| unsigned int glyph_index, |
| double x_offset, |
| double y_offset, |
| double x_advance) |
| { |
| glyph_info_t gi; |
| demo_font_lookup_glyph (font, glyph_index, &gi); |
| |
| double scale = font_size / gi.upem; |
| |
| demo_extents_t ink_extents; |
| demo_point_t position = buffer->cursor; |
| position.x += scale * x_offset; |
| position.y -= scale * y_offset; |
| demo_shader_add_glyph_vertices (position, font_size, &gi, buffer->vertices, &ink_extents); |
| demo_extents_extend (&buffer->ink_extents, &ink_extents); |
| |
| demo_point_t corner; |
| corner.x = buffer->cursor.x; |
| corner.y = buffer->cursor.y - font_size; |
| demo_extents_add (&buffer->logical_extents, &corner); |
| corner.x = buffer->cursor.x + scale * gi.advance; |
| corner.y = buffer->cursor.y; |
| demo_extents_add (&buffer->logical_extents, &corner); |
| |
| buffer->cursor.x += scale * x_advance; |
| } |
| |
| glyph_vertex_t * |
| demo_buffer_get_vertices (demo_buffer_t *buffer, |
| unsigned int *count) |
| { |
| if (count) |
| *count = buffer->vertices->size (); |
| if (buffer->vertices->empty ()) |
| return nullptr; |
| return &(*buffer->vertices)[0]; |
| } |