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;
f77c6c
	LabPangoRendererParams params;
71e4f2
};
71e4f2
71e4f2
struct _LabPangoRendererClass {
71e4f2
  PangoRendererClass parent_class;
71e4f2
};
71e4f2
71e4f2
G_DEFINE_TYPE(LabPangoRenderer, lab_pango_renderer, PANGO_TYPE_RENDERER)
71e4f2
71e4f2
1d72c2
static inline int floor_ft_int(int x) { return (x & -64)/64; }
1d72c2
static inline int ceil_ft_int(int x) { return ((x-1) & -64)/64 + 1; }
1d72c2
71e4f2
71e4f2
static void
1d72c2
put_ft_bitmap(
1d72c2
	Surface &surface,
1d72c2
	const IntPair2 &bounds,
1d72c2
	const FT_Bitmap &bitmap,
1d72c2
	int x,
1d72c2
	int y,
1d72c2
	const Color &color )
1d72c2
{
1d72c2
	const IntPair2 b = bounds
1d72c2
					 & IntPair2( IntVector2(0, 0), IntVector2(surface.width(), surface.height()) )
1d72c2
					 & IntPair2( IntVector2(x, y), IntVector2(x + bitmap.width, y + bitmap.rows) );
1d72c2
	if (b.empty())
71e4f2
		return;
71e4f2
	
1d72c2
	const IntVector2 size = b.size();
1d72c2
	const IntVector2 sp0 = b.p0 - IntVector2(x, y);
71e4f2
	const int pitch = surface.pitch();
71e4f2
1d72c2
	Color *dp = &surface[b.p0.y][b.p0.x];
1d72c2
	const int dstep = pitch - size.x;
71e4f2
	
1d72c2
	const unsigned char *sp = bitmap.buffer + sp0.y*bitmap.pitch + sp0.x;
1d72c2
	const int sstep = bitmap.pitch - size.x;
71e4f2
	
1d72c2
	for(const Color *end = dp + pitch*size.y; dp != end; dp += dstep, sp += sstep) {
1d72c2
		for(const Color *row_end = dp + size.x; dp < row_end; ++dp, ++sp) {
1d72c2
			const Real a = *sp * (1/255.0);
1d72c2
			*dp = *dp*(1-a) + color*a;
71e4f2
		}
71e4f2
	}
71e4f2
}
71e4f2
71e4f2
71e4f2
static void
1d72c2
put_ft_bitmap_mono(
1d72c2
	Surface &surface,
1d72c2
	const IntPair2 &bounds,
1d72c2
	const FT_Bitmap &bitmap,
1d72c2
	int x,
1d72c2
	int y,
1d72c2
	const Color &color )
1d72c2
{
1d72c2
	const IntPair2 b = bounds
1d72c2
					 & IntPair2( IntVector2(0, 0), IntVector2(surface.width(), surface.height()) )
1d72c2
					 & IntPair2( IntVector2(x, y), IntVector2(bitmap.width, bitmap.rows) );
1d72c2
	if (b.empty())
f77c6c
		return;
f77c6c
	
1d72c2
	const IntVector2 size = b.size();
1d72c2
	const IntVector2 sp0 = b.p0 - IntVector2(x, y);
f77c6c
	const int pitch = surface.pitch();
f77c6c
1d72c2
	Color *dp = &surface[b.p0.y][b.p0.x];
1d72c2
	const int dstep = pitch - size.x;
f77c6c
	
1d72c2
	const unsigned char *sp = bitmap.buffer + sp0.y*bitmap.pitch;
1d72c2
	const int sstep = bitmap.pitch;
1d72c2
	const int sp1x = sp0.x + size.x;
f77c6c
	
1d72c2
	for(const Color *end = dp + pitch*size.y; dp != end; dp += dstep, sp += sstep)
1d72c2
		for(int bit = sp0.x; bit < sp1x; ++dp, ++bit)
1d72c2
			if (sp[bit/8] & (128 >> (bit%8)))
1d72c2
				*dp = color;
f77c6c
}
f77c6c
f77c6c
f77c6c
static void
71e4f2
lab_pango_renderer_draw_glyph(
71e4f2
	PangoRenderer *renderer,
71e4f2
	PangoFont     *font,
71e4f2
	PangoGlyph     glyph,
71e4f2
	double         x,
71e4f2
	double         y )
71e4f2
{
f77c6c
	const LabPangoRendererParams ¶ms = ((LabPangoRenderer*)renderer)->params;
f77c6c
	if (!params.surface)
71e4f2
		return;
1d72c2
1d72c2
	const IntPair2 surface_bounds(
1d72c2
		IntVector2(0, 0),
1d72c2
		IntVector2(params.surface->width(), params.surface->height()) );
5a8eb1
5a8eb1
	FT_Face face = pango_fc_font_lock_face((PangoFcFont*)font);
5a8eb1
	
5a8eb1
	// find glyph center for proper scaling
5a8eb1
	Vector2 origin;
5a8eb1
	FT_Set_Transform(face, nullptr, nullptr);
5a8eb1
	if (!FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING)) {
5a8eb1
		const FT_Glyph_Metrics &metrics = face->glyph->metrics;
5a8eb1
		origin = Vector2(metrics.horiBearingX - metrics.vertBearingX, 0)/64;
5a8eb1
	}
71e4f2
	
5a8eb1
	// prepare transformation
5a8eb1
	const Vector2 pos = (params.matrix*Vector3(x + origin.x, y + origin.y, 1)).vec2()
5a8eb1
					  - params.glyph_matrix*origin;
71e4f2
	const int fx = (int)round(pos.x*64);
71e4f2
	const int fy = (int)round(pos.y*64);
f77c6c
	int ix = fx / 64;
f77c6c
	int iy = fy / 64;
71e4f2
	FT_Vector vec = {};
71e4f2
	vec.x = fx % 64;
71e4f2
	vec.y = fy % 64;
f77c6c
	if (params.hinting) {
f77c6c
		if (vec.x >= 32) ++ix;
f77c6c
		if (vec.y >= 32) ++iy;
f77c6c
		vec.x = 0;
f77c6c
		vec.y = 0;
f77c6c
	}
f77c6c
	vec.y = -vec.y;
f77c6c
f77c6c
	FT_Matrix mat = {};
f77c6c
	mat.xx = (int)round( params.glyph_matrix.m00*65536);
f77c6c
	mat.xy = (int)round(-params.glyph_matrix.m10*65536);
f77c6c
	mat.yx = (int)round(-params.glyph_matrix.m01*65536);
f77c6c
	mat.yy = (int)round( params.glyph_matrix.m11*65536);
f77c6c
	
5a8eb1
	// draw
f77c6c
	FT_Set_Transform(face, &mat, &vec);
f77c6c
	if (!FT_Load_Glyph(face, glyph, params.hinting ? FT_LOAD_DEFAULT : FT_LOAD_NO_HINTING)) {
1d72c2
		const FT_Glyph_Metrics &metrics = face->glyph->metrics;
1d72c2
		IntPair2 glyph_bounds(
1d72c2
			IntVector2(
1d72c2
				floor_ft_int( metrics.horiBearingX) + ix,
1d72c2
				floor_ft_int(-metrics.horiBearingY) + iy ),
1d72c2
			IntVector2(
1d72c2
				ceil_ft_int( metrics.horiBearingX + metrics.width ) + ix,
1d72c2
				ceil_ft_int(-metrics.horiBearingY + metrics.height) + iy ));
1d72c2
		if (!(params.bounds & glyph_bounds).empty()) {
1d72c2
			if (!FT_Render_Glyph(face->glyph, params.antialiasing ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO)) {
1d72c2
				if (params.antialiasing) {
1d72c2
					put_ft_bitmap(
1d72c2
						*params.surface,
1d72c2
						surface_bounds,
1d72c2
						face->glyph->bitmap,
1d72c2
						face->glyph->bitmap_left + ix,
1d72c2
						iy - face->glyph->bitmap_top,
1d72c2
						params.color );
1d72c2
				} else {
1d72c2
					put_ft_bitmap_mono(
1d72c2
						*params.surface,
1d72c2
						surface_bounds,
1d72c2
						face->glyph->bitmap,
1d72c2
						face->glyph->bitmap_left + ix,
1d72c2
						iy - face->glyph->bitmap_top,
1d72c2
						params.color );
1d72c2
				}
f77c6c
			}
71e4f2
		}
71e4f2
	}
5a8eb1
71e4f2
	pango_fc_font_unlock_face((PangoFcFont*)font);
71e4f2
}
71e4f2
71e4f2
71e4f2
static void
71e4f2
lab_pango_renderer_init(LabPangoRenderer *renderer) {
f77c6c
	memset(&renderer->params, 0, sizeof(renderer->params));
f77c6c
	renderer->params = LabPangoRendererParams();
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
f77c6c
lab_pango_fc_pattern_set_substitute(FcPattern *pattern, gpointer data) {
f77c6c
	const int &args = *(const int*)data;
71e4f2
	FcPatternDel(pattern, FC_HINTING);
f77c6c
	FcPatternDel(pattern, FC_ANTIALIAS);
f77c6c
	FcPatternAddBool(pattern, FC_HINTING, (args & 1) ? FcTrue : FcFalse);
f77c6c
	FcPatternAddBool(pattern, FC_ANTIALIAS, (args & 2) ? FcTrue : FcFalse);
71e4f2
}
71e4f2
71e4f2
71e4f2
PangoRenderer*
f77c6c
lab_pango_renderer_new(LabPangoRendererParams *params) {
f77c6c
	PangoRenderer *renderer = (PangoRenderer*)g_object_new(LAB_TYPE_PANGO_RENDERER, nullptr);
f77c6c
	lab_pango_renderer_set_params((LabPangoRenderer*)renderer, params);
f77c6c
	return renderer;
f77c6c
}
71e4f2
71e4f2
void
f77c6c
lab_pango_renderer_set_params(LabPangoRenderer *renderer, LabPangoRendererParams *params)
f77c6c
	{ if (params) renderer->params = *params; }
71e4f2
71e4f2
void
f77c6c
lab_pango_renderer_get_params(LabPangoRenderer *renderer, LabPangoRendererParams *params)
f77c6c
	{ if (params) *params = renderer->params; }
71e4f2
71e4f2
71e4f2
PangoFontMap*
f77c6c
lab_pango_font_map_new(bool hinting, bool antialiasing) {
f77c6c
	static int args[4] { 0, 1, 2, 3 }; // to avoid encoding of int into pointer
f77c6c
	
71e4f2
	PangoFontMap *font_map = pango_ft2_font_map_new();
71e4f2
	pango_ft2_font_map_set_default_substitute(
71e4f2
		(PangoFT2FontMap*)font_map,
f77c6c
		lab_pango_fc_pattern_set_substitute,
f77c6c
		args + (hinting ? 1 : 0) + (antialiasing ? 2 : 0),
71e4f2
		nullptr );
71e4f2
	return font_map;
71e4f2
}
71e4f2