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

b8976b
b8976b
#include <algorithm></algorithm>
b8976b
#include <iostream></iostream>
b8976b
b8976b
#include <glib.h></glib.h>
b8976b
#include <glibmm.h></glibmm.h>
b8976b
b8976b
#include <freetype2 ft2build.h=""></freetype2>
b8976b
#include FT_BITMAP_H
b8976b
#include <pango pango.h=""></pango>
b8976b
#include <pango pango-renderer.h=""></pango>
b8976b
#include <pango pangoft2.h=""></pango>
b8976b
b8976b
#include "surface.h"
b8976b
#include "log.h"
b8976b
b8976b
#include "freetypeview.h"
b8976b
b8976b
b8976b
static void put_bitmap(Surface &surface, FT_Bitmap &bitmap, int x, int y, const Color &color);
b8976b
b8976b
b8976b
// my pango renderer
b8976b
b8976b
#define MY_TYPE_PANGO_RENDERER (my_pango_renderer_get_type ())
b8976b
b8976b
struct _MyPangoRenderer {
b8976b
	PangoRenderer parent_instance;
b8976b
	Surface *surface;
b8976b
	ColorReal color[4];
b8976b
};
b8976b
b8976b
struct _MyPangoRendererClass {
b8976b
  PangoRendererClass parent_class;
b8976b
};
b8976b
b8976b
typedef _MyPangoRenderer MyPangoRenderer;
b8976b
typedef _PangoRendererClass MyPangoRendererClass;
b8976b
b8976b
#define PANGO_FT2_RENDERER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_FT2_RENDERER, PangoFT2RendererClass))
b8976b
#define PANGO_IS_FT2_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_FT2_RENDERER))
b8976b
#define PANGO_FT2_RENDERER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_FT2_RENDERER, PangoFT2RendererClass))
b8976b
b8976b
G_DEFINE_TYPE(MyPangoRenderer, my_pango_renderer, PANGO_TYPE_RENDERER)
b8976b
b8976b
static void
b8976b
my_pango_renderer_draw_glyph(
b8976b
	PangoRenderer *renderer,
b8976b
	PangoFont     *font,
b8976b
	PangoGlyph     glyph,
b8976b
	double         x,
b8976b
	double         y )
b8976b
{
b8976b
	MyPangoRenderer *my_renderer = (MyPangoRenderer*)renderer;
b8976b
	if (!my_renderer->surface)
b8976b
		return;
b8976b
	const Color &color = *(const Color*)my_renderer->color;
b8976b
b8976b
	const int fx = (int)round(x*64);
b8976b
	const int fy = (int)round(y*64);
b8976b
	const int ix = fx / 64;
b8976b
	const int iy = fy / 64;
b8976b
	FT_Vector vec = {};
b8976b
	vec.x = fx % 64;
b8976b
	vec.y = fy % 64;
b8976b
	
b8976b
	FT_Face face = pango_fc_font_lock_face((PangoFcFont*)font);
b8976b
	FT_Set_Transform(face, nullptr, &vec);
b8976b
	if (!FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING)) {
b8976b
		if (!FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL)) {
b8976b
			put_bitmap(
b8976b
				*my_renderer->surface,
b8976b
				face->glyph->bitmap,
b8976b
				face->glyph->bitmap_left + ix,
b8976b
				iy - face->glyph->bitmap_top,
b8976b
				color );
b8976b
		}
b8976b
	}
b8976b
	pango_fc_font_unlock_face((PangoFcFont*)font);
b8976b
}
b8976b
b8976b
static void
b8976b
my_pango_renderer_draw_trapezoid(
b8976b
	PangoRenderer  *renderer,
b8976b
	PangoRenderPart part,
b8976b
	double          y1,
b8976b
	double          x11,
b8976b
	double          x21,
b8976b
	double          y2,
b8976b
	double          x12,
b8976b
	double          x22 )
b8976b
{
b8976b
	std::cout << "my_pango_renderer_draw_trapezoid" << std::endl;
b8976b
}
b8976b
b8976b
static void
b8976b
my_pango_renderer_init(MyPangoRenderer *renderer) {
b8976b
	renderer->surface = nullptr;
b8976b
	*(Color*)renderer->color = Color();
b8976b
}
b8976b
b8976b
static void
b8976b
my_pango_renderer_class_init(MyPangoRendererClass *klass)
b8976b
{
b8976b
  PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS(klass);
b8976b
  renderer_class->draw_glyph = my_pango_renderer_draw_glyph;
b8976b
  renderer_class->draw_trapezoid = my_pango_renderer_draw_trapezoid;
b8976b
}
b8976b
b8976b
PangoRenderer*
b8976b
my_pango_renderer_new(Surface &surface, const Color &color) {
b8976b
  MyPangoRenderer *renderer = (MyPangoRenderer*)g_object_new(MY_TYPE_PANGO_RENDERER, nullptr);
b8976b
  renderer->surface = &surface;
b8976b
  *(Color*)renderer->color = color;
b8976b
  return (PangoRenderer*)renderer;
b8976b
}
b8976b
b8976b
b8976b
b8976b
static void set_substitute(FcPattern *pattern, gpointer) {
b8976b
	FcPatternDel(pattern, FC_HINTING);
b8976b
	FcPatternAddBool(pattern, FC_HINTING, FcFalse);
b8976b
}
b8976b
b8976b
static void put_bitmap(Surface &surface, FT_Bitmap &bitmap, int x, int y, const Color &color) {
b8976b
	if (x >= surface.width() || y >= surface.height())
b8976b
		return;
b8976b
	if (x + (int)bitmap.width <= 0 || y + (int)bitmap.rows <= 0)
b8976b
		return;
b8976b
	
b8976b
	const int bx = std::max(0, -x);
b8976b
	const int by = std::max(0, -y);
b8976b
	x = std::max(0, x);
b8976b
	y = std::max(0, y);
b8976b
	const int w = std::min(surface.width() - x, (int)bitmap.width - bx);
b8976b
	const int h = std::min(surface.height() - y, (int)bitmap.rows - by);
b8976b
	const int pitch = surface.pitch();
b8976b
b8976b
	Color *dst_pixel = &surface[y][x];
b8976b
	const int dst_row_step = pitch - w;
b8976b
	
b8976b
	const unsigned char *src_pixel = bitmap.buffer + by*bitmap.pitch + bx;
b8976b
	const int src_row_step = bitmap.pitch - w;
b8976b
	
b8976b
	for(const Color *end = dst_pixel + pitch*h; dst_pixel != end; dst_pixel += dst_row_step, src_pixel += src_row_step) {
b8976b
		for(const Color *row_end = dst_pixel + w; dst_pixel != row_end; ++dst_pixel, ++src_pixel) {
b8976b
			Real a = *src_pixel * (1/255.0);
b8976b
			*dst_pixel = *dst_pixel*(1-a) + color*a;
b8976b
		}
b8976b
	}
b8976b
}
b8976b
b8976b
b8976b
FreeTypeView::FreeTypeView() {
b8976b
	params.family = "Ani";
b8976b
	params.bold = false;
b8976b
	params.italic = false;
b8976b
	params.size = 12;
b8976b
b8976b
	params.position = Vector2(15.5, 18.4);
b8976b
	params.color = Color(1, 1, 0, 1);
b8976b
b8976b
	params.text = "Hello World! 123456";
b8976b
	
b8976b
	Glib::signal_timeout().connect(
b8976b
		sigc::mem_fun(*this, &FreeTypeView::on_timeout),
b8976b
		20,
b8976b
		Glib::PRIORITY_DEFAULT_IDLE );
b8976b
}
b8976b
b8976b
FreeTypeView::~FreeTypeView()
b8976b
	{ }
b8976b
b8976b
bool
b8976b
FreeTypeView::on_timeout() {
b8976b
	if (!is_visible()) return false;
b8976b
	params.position.x += 0.01;
b8976b
	update_surface();
b8976b
	return true;
b8976b
}
b8976b
	
b8976b
void
b8976b
FreeTypeView::update_surface() {
b8976b
	this->surface.clear();
b8976b
	const int width = get_allocated_width();
b8976b
	const int height = get_allocated_height();
b8976b
	if (width <= 0 || height <= 0)
b8976b
		return;
b8976b
	
b8976b
	// init
b8976b
	PangoFontMap *font_map = pango_ft2_font_map_new();
b8976b
	pango_ft2_font_map_set_default_substitute(
b8976b
		(PangoFT2FontMap*)font_map,
b8976b
		&set_substitute,
b8976b
		nullptr,
b8976b
		nullptr );
b8976b
	PangoContext *context = pango_font_map_create_context(font_map);
b8976b
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);
b8976b
	pango_font_description_set_absolute_size(font_desc, params.size * PANGO_SCALE);
b8976b
	
b8976b
	PangoFont *font = pango_font_map_load_font(font_map, context, font_desc);	
b8976b
b8976b
	// create layout
b8976b
	PangoLayout *layout = pango_layout_new(context);
b8976b
	pango_layout_set_font_description(layout, font_desc);
b8976b
	pango_layout_set_text(layout, params.text.c_str(), (int)params.text.size());
b8976b
	
b8976b
	// reneder
b8976b
	DataSurface surface(width, height);
b8976b
	PangoRenderer *renderer = my_pango_renderer_new(surface, params.color);
b8976b
	pango_renderer_draw_layout(
b8976b
		renderer,
b8976b
		layout,
b8976b
		(int)round(params.position.x*PANGO_SCALE),
b8976b
		(int)round(params.position.y*PANGO_SCALE) );
b8976b
b8976b
	// free pango
b8976b
	g_object_unref(renderer);
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
	this->surface = surface.to_cairo_surface(true);
b8976b
	
b8976b
	queue_draw();
b8976b
}
b8976b
b8976b
void
b8976b
FreeTypeView::on_draw_view(const Cairo::RefPtr<cairo::context> &context) {</cairo::context>
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
	}
b8976b
}
b8976b