size_t render(const string& text, double x = 0.0, double y = 0.0) override { cairo_glyph_t* glyphs{nullptr}; cairo_text_cluster_t* clusters{nullptr}; cairo_text_cluster_flags_t cf{}; int nglyphs = 0, nclusters = 0; string utf8 = string(text); auto status = cairo_scaled_font_text_to_glyphs( m_scaled, x, y, utf8.c_str(), utf8.size(), &glyphs, &nglyphs, &clusters, &nclusters, &cf); if (status != CAIRO_STATUS_SUCCESS) { throw application_error(sstream() << "cairo_scaled_font_text_to_glyphs()" << cairo_status_to_string(status)); } size_t bytes = 0; for (int g = 0; g < nglyphs; g++) { if (glyphs[g].index) { bytes += clusters[g].num_bytes; } else { break; } } if (bytes && bytes < text.size()) { cairo_glyph_free(glyphs); cairo_text_cluster_free(clusters); utf8 = text.substr(0, bytes); auto status = cairo_scaled_font_text_to_glyphs( m_scaled, x, y, utf8.c_str(), utf8.size(), &glyphs, &nglyphs, &clusters, &nclusters, &cf); if (status != CAIRO_STATUS_SUCCESS) { throw application_error(sstream() << "cairo_scaled_font_text_to_glyphs()" << cairo_status_to_string(status)); } } if (bytes) { // auto lock = make_unique<utils::device_lock>(cairo_surface_get_device(cairo_get_target(m_cairo))); // if (lock.get()) { // cairo_glyph_path(m_cairo, glyphs, nglyphs); // } cairo_text_extents_t extents{}; cairo_scaled_font_glyph_extents(m_scaled, glyphs, nglyphs, &extents); cairo_show_text_glyphs(m_cairo, utf8.c_str(), utf8.size(), glyphs, nglyphs, clusters, nclusters, cf); cairo_fill(m_cairo); cairo_move_to(m_cairo, x + extents.x_advance, 0.0); } cairo_glyph_free(glyphs); cairo_text_cluster_free(clusters); return bytes; }
static VALUE cr_show_text_glyphs (VALUE self, VALUE rb_utf8, VALUE rb_glyphs, VALUE rb_clusters, VALUE rb_cluster_flags) { cairo_t *cr; const char *utf8; int utf8_len; cairo_glyph_t *glyphs = NULL; int num_glyphs = 0; cairo_text_cluster_t *clusters = NULL; int num_clusters = 0; cairo_text_cluster_flags_t cluster_flags; cr = _SELF; utf8 = RSTRING_PTR (rb_utf8); utf8_len = RSTRING_LEN (rb_utf8); rb_cairo__glyphs_from_ruby_object (rb_glyphs, &glyphs, &num_glyphs); rb_cairo__text_clusters_from_ruby_object (rb_clusters, &clusters, &num_clusters); cluster_flags = RVAL2CRTEXTCLUSTERFLAGS (rb_cluster_flags); cairo_show_text_glyphs (cr, utf8, utf8_len, glyphs, num_glyphs, clusters, num_clusters, cluster_flags); if (glyphs) cairo_glyph_free (glyphs); if (clusters) cairo_text_cluster_free (clusters); return self; }
static cairo_test_status_t get_glyph (cairo_t *cr, const char *utf8, cairo_glyph_t *glyph) { cairo_glyph_t *text_to_glyphs; cairo_status_t status; int i; text_to_glyphs = glyph; i = 1; status = cairo_scaled_font_text_to_glyphs (cairo_get_scaled_font (cr), 0, 0, utf8, -1, &text_to_glyphs, &i, NULL, NULL, 0); if (status != CAIRO_STATUS_SUCCESS) return cairo_test_status_from_status (cairo_test_get_context (cr), status); if (text_to_glyphs != glyph) { *glyph = text_to_glyphs[0]; cairo_glyph_free (text_to_glyphs); } return CAIRO_TEST_SUCCESS; }
static cairo_int_status_t _cairo_user_text_to_glyphs (void *abstract_font, double x, double y, const char *utf8, int utf8_len, cairo_glyph_t **glyphs, int *num_glyphs, cairo_text_cluster_t **clusters, int *num_clusters, cairo_text_cluster_flags_t *cluster_flags) { cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; cairo_user_scaled_font_t *scaled_font = abstract_font; cairo_user_font_face_t *face = (cairo_user_font_face_t *) scaled_font->base.font_face; if (face->scaled_font_methods.text_to_glyphs) { int i; cairo_glyph_t *orig_glyphs = *glyphs; int orig_num_glyphs = *num_glyphs; status = face->scaled_font_methods.text_to_glyphs (&scaled_font->base, utf8, utf8_len, glyphs, num_glyphs, clusters, num_clusters, cluster_flags); if (status != CAIRO_STATUS_SUCCESS && status != CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED) return status; if (status == CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED || *num_glyphs < 0) { if (orig_glyphs != *glyphs) { cairo_glyph_free (*glyphs); *glyphs = orig_glyphs; } *num_glyphs = orig_num_glyphs; return CAIRO_INT_STATUS_UNSUPPORTED; } /* Convert from font space to user space and add x,y */ for (i = 0; i < *num_glyphs; i++) { double gx = (*glyphs)[i].x; double gy = (*glyphs)[i].y; cairo_matrix_transform_point (&scaled_font->base.font_matrix, &gx, &gy); (*glyphs)[i].x = gx + x; (*glyphs)[i].y = gy + y; } } return status; }
static void text_layout_destroy(struct text_layout *layout) { if (layout->glyphs) cairo_glyph_free(layout->glyphs); if (layout->clusters) cairo_text_cluster_free(layout->clusters); cairo_scaled_font_destroy(layout->font); free(layout); }
static double count_glyphs (double font_size, cairo_antialias_t antialias, cairo_t *cr, int width, int height) { const char text[] = "the jay, pig, fox, zebra and my wolves quack"; cairo_scaled_font_t *scaled_font; cairo_glyph_t *glyphs = NULL; cairo_text_extents_t extents; cairo_font_options_t *options; cairo_status_t status; int num_glyphs; int glyphs_per_line, lines_per_loop; options = cairo_font_options_create (); cairo_font_options_set_antialias (options, antialias); cairo_set_font_options (cr, options); cairo_font_options_destroy (options); cairo_select_font_face (cr, "@cairo:", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size (cr, font_size); scaled_font = cairo_get_scaled_font (cr); status = cairo_scaled_font_text_to_glyphs (scaled_font, 0., 0., text, -1, &glyphs, &num_glyphs, NULL, NULL, NULL); if (status) return 0; cairo_scaled_font_glyph_extents (scaled_font, glyphs, num_glyphs, &extents); cairo_glyph_free (glyphs); glyphs_per_line = num_glyphs * width / extents.width + 1; lines_per_loop = height / extents.height + 1; return glyphs_per_line * lines_per_loop / 1000.; /* kiloglyphs */ }
static void text_layout_set_text(struct text_layout *layout, const char *text) { if (layout->glyphs) cairo_glyph_free(layout->glyphs); if (layout->clusters) cairo_text_cluster_free(layout->clusters); layout->glyphs = NULL; layout->num_glyphs = 0; layout->clusters = NULL; layout->num_clusters = 0; cairo_scaled_font_text_to_glyphs(layout->font, 0, 0, text, -1, &layout->glyphs, &layout->num_glyphs, &layout->clusters, &layout->num_clusters, &layout->cluster_flags); }
static cairo_time_t do_glyphs (double font_size, cairo_antialias_t antialias, cairo_t *cr, int width, int height, int loops) { const char text[] = "the jay, pig, fox, zebra and my wolves quack"; cairo_scaled_font_t *scaled_font; cairo_glyph_t *glyphs = NULL, *glyphs_copy; cairo_text_extents_t extents; cairo_font_options_t *options; cairo_status_t status; double x, y; int num_glyphs, n; options = cairo_font_options_create (); cairo_font_options_set_antialias (options, antialias); cairo_set_font_options (cr, options); cairo_font_options_destroy (options); cairo_select_font_face (cr, "@cairo:", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size (cr, font_size); scaled_font = cairo_get_scaled_font (cr); status = cairo_scaled_font_text_to_glyphs (scaled_font, 0., 0., text, -1, &glyphs, &num_glyphs, NULL, NULL, NULL); if (status) return 0; glyphs_copy = cairo_glyph_allocate (num_glyphs); if (glyphs_copy == NULL) { cairo_glyph_free (glyphs); return 0; } cairo_scaled_font_glyph_extents (scaled_font, glyphs, num_glyphs, &extents); cairo_perf_timer_start (); while (loops--) { y = 0; do { x = 0; do { for (n = 0; n < num_glyphs; n++) { glyphs_copy[n] = glyphs[n]; glyphs_copy[n].x += x; glyphs_copy[n].y += y; } cairo_show_glyphs (cr, glyphs_copy, num_glyphs); x += extents.width; } while (x < width); y += extents.height; } while (y < height); } cairo_perf_timer_stop (); cairo_glyph_free (glyphs); cairo_glyph_free (glyphs_copy); return cairo_perf_timer_elapsed (); }
static cairo_perf_ticks_t do_glyphs (cairo_t *cr, int width, int height, int loops) { const char text[] = "the jay, pig, fox, zebra and my wolves quack"; cairo_scaled_font_t *scaled_font; cairo_glyph_t *glyphs = NULL, *glyphs_copy; cairo_text_extents_t extents; cairo_status_t status; double x, y; int num_glyphs, n; cairo_set_font_size (cr, 9); scaled_font = cairo_get_scaled_font (cr); status = cairo_scaled_font_text_to_glyphs (scaled_font, 0., 0., text, -1, &glyphs, &num_glyphs, NULL, NULL, NULL); if (status) return 0; glyphs_copy = cairo_glyph_allocate (num_glyphs); if (glyphs_copy == NULL) { cairo_glyph_free (glyphs); return 0; } cairo_scaled_font_glyph_extents (scaled_font, glyphs, num_glyphs, &extents); y = 0; cairo_perf_timer_start (); while (loops--) { do { x = 0; do { for (n = 0; n < num_glyphs; n++) { glyphs_copy[n] = glyphs[n]; glyphs_copy[n].x += x; glyphs_copy[n].y += y; } cairo_show_glyphs (cr, glyphs_copy, num_glyphs); if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) goto out; x += extents.width; } while (x < width); y += extents.height; } while (y < height); } out: cairo_perf_timer_stop (); cairo_glyph_free (glyphs); cairo_glyph_free (glyphs_copy); return cairo_perf_timer_elapsed (); }