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

71e4f2
71e4f2
#include <cstring></cstring>
71e4f2
71e4f2
#include <freetype2 ft2build.h=""></freetype2>
71e4f2
#include FT_BITMAP_H
71e4f2
71e4f2
#include <pango pangoft2.h=""></pango>
71e4f2
71e4f2
71e4f2
#include "surface.h"
71e4f2
#include "matrix.h"
71e4f2
71e4f2
#include "labpangorenderer.h"
71e4f2
71e4f2
71e4f2
71e4f2
struct _LabPangoRenderer {
71e4f2
	PangoRenderer parent_instance;
71e4f2
	Surface *surface;
71e4f2
	Color color;
71e4f2
	Matrix matrix;
71e4f2
};
71e4f2
71e4f2
struct _LabPangoRendererClass {
71e4f2
  PangoRendererClass parent_class;
71e4f2
};
71e4f2
71e4f2
G_DEFINE_TYPE(LabPangoRenderer, lab_pango_renderer, PANGO_TYPE_RENDERER)
71e4f2
71e4f2
71e4f2
71e4f2
static void
71e4f2
put_ft_bitmap(Surface &surface, FT_Bitmap &bitmap, int x, int y, const Color &color) {
71e4f2
	if (x >= surface.width() || y >= surface.height())
71e4f2
		return;
71e4f2
	if (x + (int)bitmap.width <= 0 || y + (int)bitmap.rows <= 0)
71e4f2
		return;
71e4f2
	
71e4f2
	const int bx = std::max(0, -x);
71e4f2
	const int by = std::max(0, -y);
71e4f2
	x = std::max(0, x);
71e4f2
	y = std::max(0, y);
71e4f2
	const int w = std::min(surface.width() - x, (int)bitmap.width - bx);
71e4f2
	const int h = std::min(surface.height() - y, (int)bitmap.rows - by);
71e4f2
	const int pitch = surface.pitch();
71e4f2
71e4f2
	Color *dst_pixel = &surface[y][x];
71e4f2
	const int dst_row_step = pitch - w;
71e4f2
	
71e4f2
	const unsigned char *src_pixel = bitmap.buffer + by*bitmap.pitch + bx;
71e4f2
	const int src_row_step = bitmap.pitch - w;
71e4f2
	
71e4f2
	for(const Color *end = dst_pixel + pitch*h; dst_pixel != end; dst_pixel += dst_row_step, src_pixel += src_row_step) {
71e4f2
		for(const Color *row_end = dst_pixel + w; dst_pixel != row_end; ++dst_pixel, ++src_pixel) {
71e4f2
			Real a = *src_pixel * (1/255.0);
71e4f2
			*dst_pixel = *dst_pixel*(1-a) + color*a;
71e4f2
		}
71e4f2
	}
71e4f2
}
71e4f2
71e4f2
71e4f2
static void
71e4f2
lab_pango_renderer_draw_glyph(
71e4f2
	PangoRenderer *renderer,
71e4f2
	PangoFont     *font,
71e4f2
	PangoGlyph     glyph,
71e4f2
	double         x,
71e4f2
	double         y )
71e4f2
{
71e4f2
	LabPangoRenderer *lab_renderer = (LabPangoRenderer*)renderer;
71e4f2
	if (!lab_renderer->surface)
71e4f2
		return;
71e4f2
	
71e4f2
	Vector3 pos = lab_renderer->matrix*Vector3(x, y, 1);
71e4f2
	
71e4f2
	const int fx = (int)round(pos.x*64);
71e4f2
	const int fy = (int)round(pos.y*64);
71e4f2
	const int ix = fx / 64;
71e4f2
	const int iy = fy / 64;
71e4f2
	FT_Vector vec = {};
71e4f2
	vec.x = fx % 64;
71e4f2
	vec.y = fy % 64;
71e4f2
	
71e4f2
	FT_Face face = pango_fc_font_lock_face((PangoFcFont*)font);
71e4f2
	FT_Set_Transform(face, nullptr, &vec);
71e4f2
	if (!FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING)) {
71e4f2
		if (!FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL)) {
71e4f2
			put_ft_bitmap(
71e4f2
				*lab_renderer->surface,
71e4f2
				face->glyph->bitmap,
71e4f2
				face->glyph->bitmap_left + ix,
71e4f2
				iy - face->glyph->bitmap_top,
71e4f2
				lab_renderer->color );
71e4f2
		}
71e4f2
	}
71e4f2
	pango_fc_font_unlock_face((PangoFcFont*)font);
71e4f2
}
71e4f2
71e4f2
71e4f2
static void
71e4f2
lab_pango_renderer_init(LabPangoRenderer *renderer) {
71e4f2
	memset( renderer + sizeof(renderer->parent_instance), 0,
71e4f2
			sizeof(*renderer) - sizeof(renderer->parent_instance) );
71e4f2
	renderer->matrix = Matrix();
71e4f2
}
71e4f2
71e4f2
static void
71e4f2
lab_pango_renderer_class_init(LabPangoRendererClass *klass)
71e4f2
{
71e4f2
	PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS(klass);
71e4f2
	renderer_class->draw_glyph = lab_pango_renderer_draw_glyph;
71e4f2
}
71e4f2
71e4f2
71e4f2
static void
71e4f2
lab_pango_fc_pattern_unset_hinting(FcPattern *pattern, gpointer)
71e4f2
	{ FcPatternDel(pattern, FC_HINTING); }
71e4f2
71e4f2
static void
71e4f2
lab_pango_fc_pattern_set_hinting(FcPattern *pattern, gpointer) {
71e4f2
	FcPatternDel(pattern, FC_HINTING);
71e4f2
	FcPatternAddBool(pattern, FC_HINTING, FcFalse);
71e4f2
}
71e4f2
71e4f2
71e4f2
PangoRenderer*
71e4f2
lab_pango_renderer_new()
71e4f2
	{ return (PangoRenderer*)g_object_new(LAB_TYPE_PANGO_RENDERER, nullptr); }
71e4f2
71e4f2
void
71e4f2
lab_pango_renderer_set_matrix(LabPangoRenderer *renderer, Matrix *matrix)
71e4f2
	{ renderer->matrix = matrix ? *matrix : Matrix(); }
71e4f2
71e4f2
void
71e4f2
lab_pango_renderer_get_matrix(LabPangoRenderer *renderer, Matrix *matrix)
71e4f2
	{ if (matrix) *matrix = renderer->matrix; }
71e4f2
71e4f2
void
71e4f2
lab_pango_renderer_set_color(LabPangoRenderer *renderer, Color *color)
71e4f2
	{ renderer->color = color ? *color : Color(); }
71e4f2
71e4f2
void
71e4f2
lab_pango_renderer_get_color(LabPangoRenderer *renderer, Color *color)
71e4f2
	{ if (color) *color = renderer->color; }
71e4f2
71e4f2
void
71e4f2
lab_pango_renderer_set_surface(LabPangoRenderer *renderer, Surface *surface)
71e4f2
	{ renderer->surface = surface; }
71e4f2
71e4f2
Surface*
71e4f2
lab_pango_renderer_get_surface(LabPangoRenderer *renderer)
71e4f2
	{ return renderer->surface; }
71e4f2
71e4f2
71e4f2
PangoFontMap*
71e4f2
lab_pango_font_map_new(bool hinting) {
71e4f2
	PangoFontMap *font_map = pango_ft2_font_map_new();
71e4f2
	pango_ft2_font_map_set_default_substitute(
71e4f2
		(PangoFT2FontMap*)font_map,
71e4f2
		hinting ? &lab_pango_fc_pattern_set_hinting
71e4f2
				: &lab_pango_fc_pattern_unset_hinting,
71e4f2
		nullptr,
71e4f2
		nullptr );
71e4f2
	return font_map;
71e4f2
}
71e4f2