当前位置: 首页 > 工具软件 > Cairo > 使用案例 >

cairo显示多行文本

夔桐
2023-12-01

在使用 cairo  绘制文本时,发现它不能绘制多行文本,搜索到官网 [cairo] automatic multi-line text?,它说需要使用 Pango库,这就痛苦了。

于是研究了一下cairo源码,自己实现了一下。附上函数:

#define HAVE_STDINT_H 1
#define HAVE_CONFIG_H 1
#include "cairo/cairo-private.h"
#include "cairo/cairo-compiler-private.h"
#include "cairo/cairo-error-private.h"
#include "cairo/cairo-fontconfig-private.h"
#include "cairo/cairo-scaled-font-private.h"
#include "cairo/cairoint.h"
#include "cairo/cairo-backend-private.h"


void CCairo::show_multiline_utf8(const char* utf8, int utf8_len, LPRECT lprc, const char* szFontname, int nFontSize, DWORD dtFormat, bool bold)
{
	cairo_text_extents_t extents;
	cairo_status_t status;
	cairo_glyph_t* glyphs = NULL, * last_glyph = NULL;
	cairo_text_cluster_t* clusters = NULL;
	int num_glyphs, num_clusters;
	cairo_text_cluster_flags_t cluster_flags;
	
	cairo_bool_t has_show_text_glyphs;
	cairo_glyph_t stack_glyphs[CAIRO_STACK_ARRAY_LENGTH(cairo_glyph_t)];
	cairo_text_cluster_t stack_clusters[CAIRO_STACK_ARRAY_LENGTH(cairo_text_cluster_t)];
	cairo_scaled_font_t* scaled_font;
	cairo_glyph_text_info_t info, * i;


	cairo_select_font_face(cr, szFontname, CAIRO_FONT_SLANT_NORMAL,bold? CAIRO_FONT_WEIGHT_BOLD : CAIRO_FONT_WEIGHT_NORMAL);
	cairo_set_font_size(cr, nFontSize);

	RECT rc;
	CopyRect(&rc, lprc);
	double y = rc.top;
	double x = rc.left;

	if (unlikely(cr->status))
		return;

	if (utf8 == NULL)
		return;

	if (utf8_len <= 0)
	{
		utf8_len = strlen(utf8);
	}
	if (utf8_len <= 0)
		return;

	double x1, x2, y1, y2, font_height, x_offset;	
	x1 = rc.left;
	y1 = rc.top;
	x2 = rc.right;
	y2 = rc.bottom;

	scaled_font = cairo_get_scaled_font(cr);
	if (unlikely(scaled_font->status)) {		
		return;
	}

	cairo_scaled_font_text_extents(scaled_font, utf8, &extents);
	y += extents.height;
	cairo_move_to(cr, x, y);
	font_height = extents.height;


	has_show_text_glyphs =
		cairo_surface_has_show_text_glyphs(cairo_get_target(cr));

	glyphs = stack_glyphs;
	num_glyphs = ARRAY_LENGTH(stack_glyphs);

	if (has_show_text_glyphs) {
		clusters = stack_clusters;
		num_clusters = ARRAY_LENGTH(stack_clusters);
	}
	else {
		clusters = NULL;
		num_clusters = 0;
	}

	cairo_get_current_point(cr, &x, &y);
	status = cairo_scaled_font_text_to_glyphs(scaled_font,
		x, y,
		utf8, utf8_len,
		&glyphs, &num_glyphs,
		has_show_text_glyphs ? &clusters : NULL, &num_clusters,
		&cluster_flags);
	if (unlikely(status))
	{
		if (glyphs && glyphs != stack_glyphs)
			cairo_glyph_free(glyphs);
		if (clusters && clusters != stack_clusters)
			cairo_text_cluster_free(clusters);

		if (unlikely(status))
			_cairo_status_set_error(&cr->status, _cairo_error(status));
		return;
	}

	if (num_glyphs == 0)
		return;


	i = NULL;
	if (has_show_text_glyphs) {
		info.utf8 = utf8;
		info.utf8_len = utf8_len;
		info.clusters = clusters;
		info.num_clusters = num_clusters;
		info.cluster_flags = cluster_flags;
		i = &info;
	}

	int line_head = 0;
	int line_no = 0;
	for (int n = 0; n < num_glyphs; n++)
	{
		last_glyph = &glyphs[n];
		status = cr->backend->glyph_extents(cr, last_glyph, 1, &extents);
		if (unlikely(status))
		{
			if (glyphs && glyphs != stack_glyphs)
				cairo_glyph_free(glyphs);
			if (clusters && clusters != stack_clusters)
				cairo_text_cluster_free(clusters);

			if (unlikely(status))
				_cairo_status_set_error(&cr->status, _cairo_error(status));
			return;
		}
		if (last_glyph->x + extents.x_advance >= x2)
		{
			//本行需要计算右对齐
			double dj = 0.0;
			if (n > line_head) //2个字以上,分散对齐
			{
				cairo_text_extents_t exts;
				cr->backend->glyph_extents(cr, &glyphs[n - 1], 1, &exts);
				dj = (x2 - (glyphs[n - 1].x + exts.width)) / (n - line_head);

				cr->backend->glyph_extents(cr, &glyphs[line_head], n - line_head, &exts);
				double dj2 = ((x2 - x1) - exts.width) / (n - line_head);

				for (int m = line_head; m < n; m++)
				{
					glyphs[m].x += dj * (m - line_head);
				}
			}
			//换行,并调整后续行位置
			x_offset = last_glyph->x - x;
			y += font_height + 2;
			for (int m = n; m < num_glyphs; m++)
			{
				glyphs[m].x -= x_offset;
				glyphs[m].y = y;
			}
			if (y - extents.height >= y2)
			{
				num_glyphs = n;
				break;
			}
			line_no++;
			line_head = n;
		}
	}

	//cairo_show_glyphs
	status = cr->backend->glyphs(cr, glyphs, num_glyphs, i);
	
	if (unlikely(status))
	{
		if (glyphs && glyphs != stack_glyphs)
			cairo_glyph_free(glyphs);
		if (clusters && clusters != stack_clusters)
			cairo_text_cluster_free(clusters);

		if (unlikely(status))
			_cairo_status_set_error(&cr->status, _cairo_error(status));
		return;
	}

	last_glyph = &glyphs[num_glyphs - 1];
	//cairo_glyph_extents
	status = cr->backend->glyph_extents(cr, last_glyph, 1, &extents);
	if (unlikely(status))
	{
		if (glyphs && glyphs != stack_glyphs)
			cairo_glyph_free(glyphs);
		if (clusters && clusters != stack_clusters)
			cairo_text_cluster_free(clusters);

		if (unlikely(status))
			_cairo_status_set_error(&cr->status, _cairo_error(status));
		return;
	}

	x = last_glyph->x + extents.x_advance;
	y = last_glyph->y + extents.y_advance;
	cr->backend->move_to(cr, x, y);


	if (glyphs && glyphs != stack_glyphs)
		cairo_glyph_free(glyphs);
	if (clusters && clusters != stack_clusters)
		cairo_text_cluster_free(clusters);

	if (unlikely(status))
		_cairo_status_set_error(&cr->status, _cairo_error(status));
}

 类似资料: