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

b8976b
a1935d
#include <cctype></cctype>
a1935d
b8976b
#include <algorithm></algorithm>
b8976b
#include <iostream></iostream>
b8976b
b8976b
#include <glibmm.h></glibmm.h>
b8976b
f4d7d6
#include "layout.h"
f4d7d6
#include "layoutdraw.h"
b8976b
b8976b
#include "surface.h"
b8976b
#include "log.h"
b8976b
b8976b
#include "freetypeview.h"
b8976b
b8976b
822827
static void
822827
fill_rect(
822827
	Surface &surface,
822827
	const IntPair2 &rect,
822827
	const Color &color )
822827
{
822827
	const IntPair2 b = rect
822827
					 & IntPair2( IntVector2(0, 0), IntVector2(surface.width(), surface.height()) );
822827
	if (b.empty())
822827
		return;
822827
	const IntVector2 size = b.size();
822827
	const int pitch = surface.pitch();
822827
	const int step = pitch - size.x;
822827
	for(Color *p = &surface[b.p0.y][b.p0.x], *end = p + pitch*size.y; p != end; p += step)
822827
		for(Color *row_end = p + size.x; p < row_end; ++p)
822827
			*p = color;
822827
}
822827
a1935d
static bool
a1935d
is_font_file(const std::string &name) {
a1935d
	static const char *ext[] = { ".otf", ".otc", ".ttf", ".ttc" };
a1935d
	static const int count = (int)(sizeof(ext)/sizeof(*ext));
a1935d
a1935d
	bool found = false;
a1935d
	for(int i = 0; i < count; ++i) {
a1935d
		const char *e = ext[i];
a1935d
		int len = 0; while(e[len]) ++len;
a1935d
		if ((int)name.size() < len) continue;
a1935d
		found = true;
a1935d
		for(int j = 0, k = name.size() - len; j < len; ++j, ++k)
a1935d
			if (tolower(name[k]) != e[j]) { found = false; break; }
a1935d
		if (found) break;
a1935d
	}
a1935d
	return found;
a1935d
}
a1935d
a1935d
822827
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
	
a1935d
	//params.family = "Chancery Uralic";
a1935d
	//params.family = "DejaVu";
a1935d
	params.family = "data/font/Bradley Gratis/Bradley Gratis.ttf";
b8976b
	params.bold = false;
b8976b
	params.italic = false;
a1935d
	params.size = 24;
b8976b
06d46a
	params.spacing = Vector2(3, 2);
f77c6c
	
f77c6c
	params.hinting = false;
f77c6c
	params.antialiasing = true;
f4d7d6
	params.invert = false;
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
	
f4d7d6
	// prepare matrix
1d72c2
	Matrix to_pixels = transform_to_pixels();
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;
f4d7d6
	if (fabs(params.matrix.det()) <= real_precision_cub)
f4d7d6
		return;
f4d7d6
f4d7d6
	// calc bounds
f4d7d6
	const int width = get_allocated_width();
f4d7d6
	const int height = get_allocated_height();
1d72c2
	Pair2 bounds = to_pixels.transform_bounds(
1d72c2
		  Pair2(bounds_p0->position)
1d72c2
		.expand(bounds_p1->position) );
1d72c2
	bounds &= Pair2(Vector2(), Vector2(width, height));
1d72c2
	if (bounds.empty())
1d72c2
		return;
1d72c2
	IntPair2 int_bounds = IntPair2( IntVector2( (int)floor(bounds.p0.x + real_precision),
1d72c2
												(int)floor(bounds.p0.y + real_precision) ),
f4d7d6
									IntVector2( (int)ceil (bounds.p1.x - real_precision),
f4d7d6
												(int)ceil (bounds.p1.y - real_precision) ))
1d72c2
						& IntPair2( IntVector2(),
1d72c2
									IntVector2(width, height) );
1d72c2
	if (int_bounds.empty())
b8976b
		return;
822827
f4d7d6
	// calc some measures
06d46a
	const Vector2 origin(
06d46a
		clamp(params.origin.x, 0, 1),
06d46a
		clamp(params.origin.y, 0, 1) );
f4d7d6
	const Vector2 spacing(
f4d7d6
		params.spacing.x > real_precision ? params.spacing.x : 1,
f4d7d6
		params.spacing.y > real_precision ? params.spacing.y : 1 );
f4d7d6
	const Matrix2 spacing_matrix(
f4d7d6
		Vector2(spacing.x, 0),
f4d7d6
		Vector2(0, spacing.y) );
f4d7d6
	if (fabs(spacing_matrix.det()) <= real_precision_sqr)
71e4f2
		return;
71e4f2
	
b8976b
	// init
f4d7d6
	Glib::RefPtr<pango::fontmap> font_map = Layout::create_fontmap(params.hinting, params.antialiasing);</pango::fontmap>
f4d7d6
	Glib::RefPtr<pango::context> context = font_map->create_context();</pango::context>
71e4f2
	
b8976b
	// load font
a1935d
	Glib::RefPtr<pango::font> font;</pango::font>
f4d7d6
	Pango::FontDescription font_desc;
f4d7d6
	font_desc.set_family(params.family);
f4d7d6
	font_desc.set_weight(params.bold ? Pango::WEIGHT_BOLD : Pango::WEIGHT_NORMAL);
f4d7d6
	font_desc.set_style(params.italic ? Pango::STYLE_ITALIC : Pango::STYLE_NORMAL);
f4d7d6
	font_desc.set_absolute_size(params.size * Pango::SCALE);
a1935d
	if (is_font_file(params.family))
a1935d
		font = Layout::load_font_file(context, params.family, font_desc);
a1935d
	if (!font)
a1935d
		font = context->load_font(font_desc);
a1935d
	font_desc = font->describe();
f4d7d6
	
f4d7d6
	// create pango layout
f4d7d6
	Glib::RefPtr<pango::layout> pango_layout = Pango::Layout::create(context);</pango::layout>
f4d7d6
	pango_layout->set_font_description(font_desc);
f4d7d6
	pango_layout->set_wrap(Pango::WRAP_WORD_CHAR);
f4d7d6
	pango_layout->set_width(
f4d7d6
		params.wrap_width > real_precision ? (int)round(params.wrap_width*Pango::SCALE) : -1 );
f4d7d6
	pango_layout->set_alignment(
f4d7d6
		params.alignment < 0 ? Pango::ALIGN_LEFT :
f4d7d6
		params.alignment > 0 ? Pango::ALIGN_RIGHT : Pango::ALIGN_CENTER );
f4d7d6
	pango_layout->set_justify(params.justify);
f4d7d6
	pango_layout->set_text(params.text);
f4d7d6
	
f4d7d6
	// create lab layout
f4d7d6
	RefPtr<layout> layout(new Layout(pango_layout));</layout>
f4d7d6
	const Pair2 &logical_bounds = layout->get_logical_bounds();
f4d7d6
	const Vector2 layout_position(
f4d7d6
		logical_bounds.p1.x * origin.x,
f4d7d6
		logical_bounds.p1.y * origin.y );
f4d7d6
	RefPtr<transformedlayout> transformed_layout(</transformedlayout>
f4d7d6
		new TransformedLayout(layout, spacing_matrix, Matrix2()) );
1d72c2
f4d7d6
	// prepare surface
f4d7d6
	DataSurface surface(width, height);
f4d7d6
	if (params.invert)
f4d7d6
		fill_rect(surface, int_bounds, params.color.get_mult_alpha());
822827
f4d7d6
	// draw
f4d7d6
	LayoutDraw::draw(
f4d7d6
		surface,
f4d7d6
		int_bounds,
f4d7d6
		transformed_layout,
f4d7d6
		params.matrix,
f4d7d6
		params.color,
f4d7d6
		params.invert,
f4d7d6
		-layout_position,
f4d7d6
		params.alignment_by_origin ? &origin.x : nullptr );
f4d7d6
f4d7d6
	// to cairo
822827
	this->surface = surface.to_cairo_surface(true);
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