Blame c++/freetype/src/freetypeview.cpp

b8976b
b8976b
#include <algorithm></algorithm>
b8976b
#include <iostream></iostream>
b8976b
b8976b
#include <glibmm.h></glibmm.h>
b8976b
71e4f2
#include "labpangorenderer.h"
b8976b
b8976b
#include "surface.h"
b8976b
#include "log.h"
b8976b
b8976b
#include "freetypeview.h"
b8976b
b8976b
f77c6c
FreeTypeView::FreeTypeView():
1d72c2
	p0(new View::Point( Vector2(0, 0) )),
1d72c2
	px(new View::Point( Vector2(1, 0) )),
1d72c2
	py(new View::Point( Vector2(0, 1) )),
1d72c2
	bounds_p0(new View::Point( Vector2(-2, -2) )),
1d72c2
	bounds_p1(new View::Point( Vector2( 2,  2) ))
f77c6c
{
f77c6c
	prev_p0 = p0->position;
f77c6c
	transform *= Matrix().scaling(Vector2(50, 50));
f77c6c
	points.push_back(p0);
f77c6c
	points.push_back(px);
f77c6c
	points.push_back(py);
1d72c2
	points.push_back(bounds_p0);
1d72c2
	points.push_back(bounds_p1);
1d72c2
	
1d72c2
	set_size_request(400, 400);
f77c6c
	
5a8eb1
	params.family = "DjVu";
b8976b
	params.bold = false;
b8976b
	params.italic = false;
b8976b
	params.size = 12;
b8976b
06d46a
	params.spacing = Vector2(3, 2);
f77c6c
	
f77c6c
	params.hinting = false;
f77c6c
	params.antialiasing = true;
f77c6c
	
71e4f2
	params.matrix = Matrix().translation(Vector2(15.5, 18.4));
b8976b
	params.color = Color(1, 1, 0, 1);
b8976b
f77c6c
	params.text =
f77c6c
		"Lorem ipsum dolor sit amet, consectetur adipisici elit,"
f77c6c
		"sed eiusmod tempor incidunt ut labore et dolore magna aliqua."
f77c6c
		"Ut enim ad minim veniam, quis nostrud exercitation ullamco "
f77c6c
		"laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure"
f77c6c
		"reprehenderit in voluptate velit esse cillum dolore eu fugiat "
f77c6c
		"nulla pariatur. Excepteur sint obcaecat cupiditat non proident, "
f77c6c
		"sunt in culpa qui officia deserunt mollit anim id est laborum.";
f77c6c
	//params.text = "1\n2\n3\n";
f77c6c
	
06d46a
	params.alignment = -1;
5a8eb1
	params.justify = false;
f77c6c
	params.wrap_width = 600;
06d46a
	params.alignment_by_origin = true;
06d46a
	
06d46a
	params.origin = Vector2(0.25, 0.8);
b8976b
	
b8976b
	Glib::signal_timeout().connect(
b8976b
		sigc::mem_fun(*this, &FreeTypeView::on_timeout),
f77c6c
		50,
b8976b
		Glib::PRIORITY_DEFAULT_IDLE );
b8976b
}
b8976b
b8976b
FreeTypeView::~FreeTypeView()
b8976b
	{ }
b8976b
b8976b
bool
b8976b
FreeTypeView::on_timeout() {
b8976b
	if (!is_visible()) return false;
f77c6c
	p0->position.x += 0.001;
f77c6c
	point_motion(p0);
b8976b
	return true;
b8976b
}
b8976b
	
b8976b
void
b8976b
FreeTypeView::update_surface() {
b8976b
	this->surface.clear();
f77c6c
	
1d72c2
	Matrix to_pixels = transform_to_pixels();
1d72c2
	
f77c6c
	Matrix in_matrix(
f77c6c
		Vector3(px->position - p0->position)/50,
f77c6c
		Vector3(py->position - p0->position)/50,
f77c6c
		Vector3(p0->position, 1) );
f77c6c
	params.matrix = transform_to_pixels() * in_matrix;
f77c6c
	
1d72c2
	Pair2 bounds = to_pixels.transform_bounds(
1d72c2
		  Pair2(bounds_p0->position)
1d72c2
		.expand(bounds_p1->position) );
1d72c2
	
b8976b
	const int width = get_allocated_width();
b8976b
	const int height = get_allocated_height();
1d72c2
	bounds &= Pair2(Vector2(), Vector2(width, height));
1d72c2
	if (bounds.empty())
1d72c2
		return;
1d72c2
1d72c2
	IntPair2 int_bounds = IntPair2( IntVector2( (int)floor(bounds.p0.x + real_precision),
1d72c2
												(int)floor(bounds.p0.y + real_precision) ),
1d72c2
									IntVector2( (int)ceil(bounds.p1.x - real_precision),
1d72c2
												(int)ceil(bounds.p1.y - real_precision) ))
1d72c2
						& IntPair2( IntVector2(),
1d72c2
									IntVector2(width, height) );
1d72c2
	if (int_bounds.empty())
b8976b
		return;
b8976b
	
06d46a
	const Vector2 spacing(
06d46a
		params.spacing.x > real_precision ? params.spacing.x : 1,
06d46a
		params.spacing.y > real_precision ? params.spacing.y : 1 );
f77c6c
06d46a
	const Vector2 origin(
06d46a
		clamp(params.origin.x, 0, 1),
06d46a
		clamp(params.origin.y, 0, 1) );
06d46a
	
71e4f2
	Matrix matrix = params.matrix;
f77c6c
	Matrix2 glyph_matrix(
f77c6c
		matrix.row_x().vec2(),
f77c6c
		matrix.row_y().vec2() );
06d46a
	matrix *= Matrix().scaling(spacing);
1d72c2
	Matrix bbox_check_matrix =
1d72c2
		  params.matrix
1d72c2
		* Matrix().scaling(
1d72c2
			Vector2( std::max(Real(1), spacing.x),
1d72c2
					 std::max(Real(1), spacing.y) ));
f77c6c
f77c6c
	if (fabs(glyph_matrix.det()) <= real_precision_sqr)
71e4f2
		return;
f77c6c
f77c6c
	const Real size = params.size;
06d46a
	const Real wrap_width = params.wrap_width;
71e4f2
	
b8976b
	// init
f77c6c
	PangoFontMap *font_map = lab_pango_font_map_new(params.hinting, params.antialiasing);
b8976b
	PangoContext *context = pango_font_map_create_context(font_map);
71e4f2
	
b8976b
	// load font
b8976b
	PangoFontDescription *font_desc = pango_font_description_new();
b8976b
	pango_font_description_set_family(font_desc, params.family.c_str());
b8976b
	pango_font_description_set_weight(font_desc, params.bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL);
b8976b
	pango_font_description_set_style(font_desc, params.italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
71e4f2
	pango_font_description_set_absolute_size(font_desc, size * PANGO_SCALE);
71e4f2
	PangoFont *font = pango_context_load_font(context, font_desc);
b8976b
	
b8976b
	// create layout
b8976b
	PangoLayout *layout = pango_layout_new(context);
b8976b
	pango_layout_set_font_description(layout, font_desc);
f77c6c
	pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
f77c6c
	pango_layout_set_width(layout, wrap_width  > real_precision ? (int)round(wrap_width *PANGO_SCALE) : -1);
f77c6c
	pango_layout_set_alignment(layout,
f77c6c
		params.alignment < 0 ? PANGO_ALIGN_LEFT :
f77c6c
		params.alignment > 0 ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_CENTER );
f77c6c
	pango_layout_set_justify(layout, params.justify);
b8976b
	pango_layout_set_text(layout, params.text.c_str(), (int)params.text.size());
b8976b
	
f77c6c
	// move origin
1d72c2
	PangoRectangle ink_rect, rect;
1d72c2
	pango_layout_get_extents(layout, &ink_rect, &rect);
f77c6c
	const Vector2 offset_to_origin(
06d46a
		(rect.x + rect.width)/Real(PANGO_SCALE) * origin.x,
06d46a
		(rect.y + rect.height)/Real(PANGO_SCALE) * origin.y );
f77c6c
	matrix *= Matrix().translation(-offset_to_origin);
1d72c2
1d72c2
	bbox_check_matrix *= Matrix().translation(-offset_to_origin)
1d72c2
					   * Matrix().scaling(Vector2(Real(1)/PANGO_SCALE, Real(1)/PANGO_SCALE));
1d72c2
	const Pair2 dst_rect = bbox_check_matrix.transform_bounds(
1d72c2
		Pair2( Vector2( ink_rect.x, ink_rect.y),
1d72c2
			   Vector2( ink_rect.x + ink_rect.width,
1d72c2
					    ink_rect.y + ink_rect.height) ).inflate(Vector2(2, 2)) );
f77c6c
	
1d72c2
	if (!(bounds & dst_rect).empty()) {
1d72c2
		// create renderer
1d72c2
		DataSurface surface(width, height);
1d72c2
		LabPangoRendererParams rp;
1d72c2
		rp.surface      = &surface;
1d72c2
		rp.bounds       = IntPair2( IntVector2( (int)floor(bounds.p0.x + real_precision),
1d72c2
												(int)floor(bounds.p0.y + real_precision) ),
1d72c2
									IntVector2( (int)ceil(bounds.p1.x - real_precision),
1d72c2
												(int)ceil(bounds.p1.y - real_precision) ))
1d72c2
						& IntPair2( IntVector2(),
1d72c2
									IntVector2(width, height) );
1d72c2
		rp.matrix       = matrix;
1d72c2
		rp.glyph_matrix = glyph_matrix;
1d72c2
		rp.color        = params.color;
1d72c2
		rp.hinting      = params.hinting;
1d72c2
		rp.antialiasing = params.antialiasing;
1d72c2
		PangoRenderer *renderer = lab_pango_renderer_new(&rp);
1d72c2
		
1d72c2
		// render line by line
1d72c2
		pango_renderer_activate(renderer);
1d72c2
		PangoLayoutIter *iter = pango_layout_get_iter(layout);
1d72c2
		do {
1d72c2
			PangoRectangle line_ink_rect, line_rect;
1d72c2
			pango_layout_iter_get_line_extents(iter, &line_ink_rect, &line_rect);
1d72c2
			int x = params.alignment_by_origin
1d72c2
				? (int)round((rect.x + rect.width - line_rect.width)*origin.x)
1d72c2
				: line_rect.x;
1d72c2
			int dx = x - line_rect.x;
1d72c2
				
1d72c2
			const Pair2 dst_line_rect = bbox_check_matrix.transform_bounds(
1d72c2
				Pair2( Vector2( line_ink_rect.x + dx,
1d72c2
							    line_ink_rect.y ),
1d72c2
					   Vector2( line_ink_rect.x + dx + line_ink_rect.width,
1d72c2
								line_ink_rect.y + line_ink_rect.height) ).inflate(Vector2(2, 2)) );
1d72c2
1d72c2
			if (!(bounds & dst_line_rect).empty()) {
1d72c2
				int baseline = pango_layout_iter_get_baseline(iter);
1d72c2
				PangoLayoutLine *line = pango_layout_iter_get_line_readonly(iter);
1d72c2
				pango_renderer_draw_layout_line(renderer, line, x, baseline);
1d72c2
			}
1d72c2
		} while(pango_layout_iter_next_line(iter));
1d72c2
		pango_layout_iter_free(iter);
1d72c2
		pango_renderer_deactivate(renderer);
1d72c2
1d72c2
		g_object_unref(renderer);
1d72c2
1d72c2
		this->surface = surface.to_cairo_surface(true);
1d72c2
	}
71e4f2
	
b8976b
	// free pango
b8976b
	pango_font_description_free(font_desc);
b8976b
	g_object_unref(layout);
b8976b
	g_object_unref(font);
b8976b
	g_object_unref(context);
b8976b
	g_object_unref(font_map);
b8976b
}
b8976b
b8976b
void
f77c6c
FreeTypeView::on_point_motion(const View::PointPtr &point) {
f77c6c
	if (point == p0) {
f77c6c
		px->position += p0->position - prev_p0;
f77c6c
		py->position += p0->position - prev_p0;
f77c6c
		prev_p0 = p0->position;
f77c6c
	}
1d72c2
	queue_draw();
f77c6c
}
f77c6c
f77c6c
void
b8976b
FreeTypeView::on_draw_view(const Cairo::RefPtr<cairo::context> &context) {</cairo::context>
1d72c2
	update_surface();
1d72c2
f77c6c
	const Real ps = get_pixel_size();
f77c6c
f77c6c
	context->save();
f77c6c
	context->set_line_width(ps);
f77c6c
1d72c2
	// draw transform
f77c6c
	context->set_source_rgba(0, 0, 1, 1);
f77c6c
	context->move_to(px->position.x, px->position.y);
f77c6c
	context->line_to(p0->position.x, p0->position.y);
f77c6c
	context->line_to(py->position.x, py->position.y);
f77c6c
	context->stroke();
f77c6c
1d72c2
	// draw bounds
1d72c2
	context->set_source_rgba(0, 0, 1, 1);
1d72c2
	context->move_to(bounds_p0->position.x, bounds_p0->position.y);
1d72c2
	context->line_to(bounds_p1->position.x, bounds_p0->position.y);
1d72c2
	context->line_to(bounds_p1->position.x, bounds_p1->position.y);
1d72c2
	context->line_to(bounds_p0->position.x, bounds_p1->position.y);
1d72c2
	context->close_path();
1d72c2
	context->stroke();
1d72c2
b8976b
	if (surface) {
b8976b
		context->save();
b8976b
		context->transform(transform_from_pixels().to_cairo());
b8976b
		context->set_source(surface, 0, 0);
b8976b
		context->paint();
b8976b
		context->restore();
b8976b
	}
f77c6c
	context->restore();
b8976b
}
b8976b