Esempio n. 1
0
    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;
    }
Esempio n. 2
0
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;
}
Esempio n. 3
0
File: glyphs.c Progetto: AZed/cairo
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 */
}
Esempio n. 4
0
static cairo_status_t
test_scaled_font_text_to_glyphs (cairo_scaled_font_t        *scaled_font,
				 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_scaled_font_t *fallback_scaled_font;

  fallback_scaled_font = cairo_scaled_font_get_user_data (scaled_font,
							  &fallback_font_key);

  return cairo_scaled_font_text_to_glyphs (fallback_scaled_font, 0, 0,
					   utf8, utf8_len,
					   glyphs, num_glyphs,
					   clusters, num_clusters, cluster_flags);
}
Esempio n. 5
0
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);
}
Esempio n. 6
0
File: glyphs.c Progetto: AZed/cairo
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 ();
}
/**
 * layout a text with provided parameters
 *
 * @param cr:			the cairo instance
 * @param text:			the text to layout
 * @param font:			the font to use to layout to
 * @param size:			the font size size of each char to layout
 * @param bounds:		the bounds of layouting
 * @param alignment:	the text alignment on cairo's buffer
 * @param layout:		the returned layouted text instance
 * @param-opt breakOnOverflow:	break the layouting if size overflow the provided bounds
 */
void TextLayouter::layout(cairo_t *cr, const char *text, Font_t *font, int32_t size, Rectangle bounds, const TextAlignment &alignment, LayoutedText *layout, bool breakOnOverflow)
{
	// check font validity
	if (!font) return;

	// get text length
	size_t textLen = strlen(text);

	// starting coordinates
	int x = bounds.x;
	int y = bounds.y;
	int lineStartX = x;

	// created the scaled font face
	cairo_set_font_face(cr, font->getFace());
	cairo_set_font_size(cr, size);
	cairo_scaled_font_t *scaledFace = cairo_get_scaled_font(cr);

	int line = 0;
	int lineHeight = size;

	// create glyphs for the text
	cairo_glyph_t *previousGlyphBuffer = layout->glyphBuffer;
	cairo_text_cluster_t *previousClusterBuffer = layout->clusterBuffer;

	cairo_text_cluster_flags_t clusterFlags;
	cairo_status_t stat = cairo_scaled_font_text_to_glyphs(scaledFace, 0, 0, text, textLen, &layout->glyphBuffer, &layout->glyphCount, &layout->clusterBuffer, &layout->clusterCount, &clusterFlags);

	// free old buffer
	if (previousGlyphBuffer != nullptr && layout->glyphBuffer != previousGlyphBuffer) free(previousGlyphBuffer);
	if (previousClusterBuffer != nullptr && layout->clusterBuffer != previousClusterBuffer) free(previousClusterBuffer);

	// clear layout entries
	layout->positions.clear();

	// perform layouting
	if (stat == CAIRO_STATUS_SUCCESS)
	{
		// positions in bytes and glyphs
		size_t bytePos = 0;
		size_t glyphPos = 0;

		// text extents
		cairo_text_extents_t extents;
		for (int i = 0; i < layout->clusterCount; i++)
		{
			cairo_text_cluster_t *cluster = &layout->clusterBuffer[i];
			cairo_glyph_t *glyphs = &layout->glyphBuffer[glyphPos];

			// create new position
			PositionedGlyph positioned;
			positioned.glyph = glyphs;
			positioned.glyphCount = cluster->num_glyphs;
			cairo_scaled_font_glyph_extents(scaledFace, positioned.glyph, positioned.glyphCount, &extents);

			positioned.advance.x = extents.x_advance;
			positioned.advance.y = extents.y_advance;
			positioned.size.width = extents.width;
			positioned.size.height = extents.height;

			// check if newline
			bool isNewline = false;
			if (cluster->num_bytes == 1 && text[bytePos] == '\n') isNewline = true;
			bool invisible = false;

			// Wouldn't match in line or is break character? Start next line
			if (isNewline || (breakOnOverflow && (x + positioned.size.width > bounds.width)))
			{
				if (isNewline) invisible = true;
				if (alignment == TextAlignment::RIGHT) rightAlign(layout, line, x - lineStartX, bounds);
				else if (alignment == TextAlignment::CENTER) centerAlign(layout, line, x - lineStartX, bounds);

				++line;
				x = bounds.x;
				lineStartX = x;
				y += lineHeight;
			}

			if (!invisible)
			{
				// Position
				positioned.line = line;
				positioned.position.x = x;
				positioned.position.y = y + lineHeight;

				// Add position
				layout->positions.push_back(positioned);

				// Jump to next
				x += positioned.advance.x;
			}

			// increase positions
			glyphPos += cluster->num_glyphs;
			bytePos += cluster->num_bytes;
		}
	}

	if (alignment == TextAlignment::RIGHT) rightAlign(layout, line, x - lineStartX, bounds);
	else if (alignment == TextAlignment::CENTER) centerAlign(layout, line, x - lineStartX, bounds);

	// Set text bounds
	#define BOUNDS_EMPTY 0xFFFFFF
	int tbTop = BOUNDS_EMPTY;
	int tbLeft = BOUNDS_EMPTY;
	int tbRight = 0;
	int tbBottom = 0;

	for (PositionedGlyph &p : layout->positions)
	{
		if (p.position.x < tbLeft) tbLeft = p.position.x;
		if (p.position.y < tbTop) tbTop = p.position.y;

		// get extents again
		int r = p.position.x + p.size.width;
		if (r > tbRight) tbRight = r;

		int b = p.position.y + p.size.height;
		if (b > tbBottom) tbBottom = b;
	}

	if (tbTop != BOUNDS_EMPTY && tbLeft != BOUNDS_EMPTY)
	{
		layout->textBounds.x = tbLeft;
		layout->textBounds.y = tbTop;
		layout->textBounds.width = tbRight - tbLeft;
		layout->textBounds.height = tbBottom - tbTop;
	}
}
Esempio n. 8
0
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 ();
}