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

f4d7d6
f4d7d6
#include <freetype2 ft2build.h=""></freetype2>
f4d7d6
#include FT_BITMAP_H
f4d7d6
f4d7d6
#include <pango pangoft2.h=""></pango>
f4d7d6
f4d7d6
#include "layoutdraw.h"
f4d7d6
f4d7d6
f4d7d6
template<bool antialiasing,="" bool="" eraze=""></bool>
f4d7d6
static void
f4d7d6
put_ft_bitmap(
f4d7d6
	Surface &surface,
f4d7d6
	const IntPair2 &/*bounds*/,
f4d7d6
	const FT_Bitmap &bitmap,
f4d7d6
	const IntVector2 &offset,
f4d7d6
	const Color &color )
f4d7d6
{
f4d7d6
	const IntPair2 b = /*bounds
f4d7d6
					 & */IntPair2( IntVector2(0, 0), IntVector2(surface.width(), surface.height()) )
f4d7d6
					 & IntPair2( offset, IntVector2(offset.x + bitmap.width, offset.y + bitmap.rows) );
f4d7d6
	if (b.empty())
f4d7d6
		return;
f4d7d6
	
f4d7d6
	const IntVector2 size = b.size();
f4d7d6
	const IntVector2 sp0 = b.p0 - offset;
f4d7d6
	const int pitch = surface.pitch();
f4d7d6
f4d7d6
	Color *dp = &surface[b.p0.y][b.p0.x];
f4d7d6
	const int dstep = pitch - size.x;
f4d7d6
	
f4d7d6
	if (antialiasing) {
f4d7d6
		const unsigned char *sp = bitmap.buffer + sp0.y*bitmap.pitch + sp0.x;
f4d7d6
		const int sstep = bitmap.pitch - size.x;
f4d7d6
		for(const Color *end = dp + pitch*size.y; dp != end; dp += dstep, sp += sstep) {
f4d7d6
			for(const Color *row_end = dp + size.x; dp < row_end; ++dp, ++sp) {
f4d7d6
				const Real a = *sp*(1/255.0);
f4d7d6
				if (eraze) *dp *= 1-a;
f4d7d6
					  else *dp = *dp*(1-a) + color*a;
f4d7d6
			}
f4d7d6
		}
f4d7d6
	} else {
f4d7d6
		const unsigned char *sp = bitmap.buffer + sp0.y*bitmap.pitch;
f4d7d6
		const int sstep = bitmap.pitch;
f4d7d6
		const int sp1x = sp0.x + size.x;
f4d7d6
		for(const Color *end = dp + pitch*size.y; dp != end; dp += dstep, sp += sstep)
f4d7d6
			for(int bit = sp0.x; bit < sp1x; ++dp, ++bit)
f4d7d6
				if (sp[bit/8] & (128 >> (bit%8)))
f4d7d6
					*dp = eraze ? Color() : color;
f4d7d6
	}
f4d7d6
}
f4d7d6
f4d7d6
f4d7d6
void
f4d7d6
LayoutDraw::draw(
f4d7d6
	Surface &surface,
f4d7d6
	const IntPair2 &bounds,
f4d7d6
	const RefPtr<transformedlayout> &layout,</transformedlayout>
f4d7d6
	const Matrix &matrix,
f4d7d6
	const Color &color,
f4d7d6
	bool eraze,
f4d7d6
	const Vector2 &position,
f4d7d6
	const Real *realign )
f4d7d6
{
f4d7d6
	if (!layout)
f4d7d6
		return;
f4d7d6
	
f4d7d6
	IntPair2 b = bounds & IntPair2(IntVector2(), IntVector2(surface.width(), surface.height()));
f4d7d6
	if (b.empty())
f4d7d6
		return;
f4d7d6
f4d7d6
	const Matrix2 &spacing_matrix = layout->get_spacing_matrix();
f4d7d6
	const Matrix2 &glyph_matrix = layout->get_glyph_matrix();
f4d7d6
f4d7d6
	const Pair2 fb(Vector2(b.p0.x, b.p0.y), Vector2(b.p1.x, b.p1.y));
f4d7d6
	const Pair2 flb = matrix.transform_bounds(layout->get_bounds() + spacing_matrix*position);
f4d7d6
	if ((fb & flb).empty())
f4d7d6
		return;
f4d7d6
f4d7d6
	const Matrix3 full_spacing_matrix = matrix * Matrix3(
f4d7d6
		Vector3(spacing_matrix.row_x()),
f4d7d6
		Vector3(spacing_matrix.row_y()) );
f4d7d6
	const Matrix2 full_glyph_matrix = Matrix2(
f4d7d6
		matrix.row_x().vec2(),
f4d7d6
		matrix.row_y().vec2() )*glyph_matrix;
f4d7d6
f4d7d6
	FT_Matrix mat = {};
f4d7d6
	mat.xx = (int)round( full_glyph_matrix.m00*65536);
f4d7d6
	mat.xy = (int)round(-full_glyph_matrix.m10*65536);
f4d7d6
	mat.yx = (int)round(-full_glyph_matrix.m01*65536);
f4d7d6
	mat.yy = (int)round( full_glyph_matrix.m11*65536);
f4d7d6
	FT_Vector vec = {};
f4d7d6
	
f4d7d6
	const bool hinting = layout->get_layout()->get_hinting();
f4d7d6
	const bool antialiasing = layout->get_layout()->get_antialiasing();
f4d7d6
	const FT_Int32 load_flags = hinting ? FT_LOAD_DEFAULT : FT_LOAD_NO_HINTING;
f4d7d6
	const FT_Render_Mode render_mode = antialiasing ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO;
f4d7d6
f4d7d6
	const Pair2 &logical_bounds = layout->get_layout()->get_logical_bounds();
f4d7d6
	const Layout::LineList &lines = layout->get_layout()->get_lines();
f4d7d6
	const TransformedLayout::LineBoundsList &line_bounds = layout->get_line_bounds();
f4d7d6
f4d7d6
	PangoFont *font = nullptr;
f4d7d6
	
f4d7d6
	assert(lines.size() == line_bounds.size());
f4d7d6
	TransformedLayout::LineBoundsList::const_iterator lbi = line_bounds.begin();
f4d7d6
	for(Layout::LineList::const_iterator li = lines.begin(); li != lines.end(); ++li, ++lbi) {
f4d7d6
		Vector2 linepos = li->position;
f4d7d6
		if (realign)
f4d7d6
			linepos.x = (logical_bounds.p1.x - li->logical_bounds.p1.x)*clamp(*realign, 0, 1);
f4d7d6
		linepos += position;
f4d7d6
		
f4d7d6
		const Vector2 lb_offset = spacing_matrix*linepos;
f4d7d6
		const Pair2 lb = matrix.transform_bounds(*lbi + lb_offset);
f4d7d6
		if ((fb & lb).empty())
f4d7d6
			continue;
f4d7d6
		
f4d7d6
		for(Layout::RunList::const_iterator ri = li->runs.begin(); ri != li->runs.end(); ++ri) {
f4d7d6
			assert(ri->font);
f4d7d6
			PangoFont *next_font = ri->font->gobj();
f4d7d6
			if (!next_font) continue;
f4d7d6
			if (font != next_font) {
f4d7d6
				if (font) pango_fc_font_unlock_face((PangoFcFont*)font);
f4d7d6
				font = next_font;
f4d7d6
			}
f4d7d6
			
f4d7d6
			assert(PANGO_IS_FC_FONT(font));
f4d7d6
			FT_Face face = pango_fc_font_lock_face((PangoFcFont*)font);
f4d7d6
			for(Layout::GlyphList::const_iterator gi = ri->glyphs.begin(); gi != ri->glyphs.end(); ++gi) {
f4d7d6
				const Vector2 gb_offset = (full_spacing_matrix*Vector3(linepos + gi->position, 1)).vec2();
f4d7d6
				const Pair2 gb = full_glyph_matrix.transform_bounds(gi->bounds) + gb_offset;
f4d7d6
				if ((fb & gb).empty())
f4d7d6
					continue;
f4d7d6
				
f4d7d6
				const Vector2 gp = gb_offset + full_glyph_matrix*gi->origin;
f4d7d6
				const int fx = (int)round(gp.x*64);
f4d7d6
				const int fy = (int)round(gp.y*64);
f4d7d6
				int ix = fx / 64;
f4d7d6
				int iy = fy / 64;
f4d7d6
				vec.x = fx % 64;
f4d7d6
				vec.y = fy % 64;
f4d7d6
				if (hinting) {
f4d7d6
					if (vec.x >= 32) ++ix;
f4d7d6
					if (vec.y >= 32) ++iy;
f4d7d6
					vec.x = 0;
f4d7d6
					vec.y = 0;
f4d7d6
				}
f4d7d6
				vec.y = -vec.y;
f4d7d6
				
f4d7d6
				FT_Set_Transform(face, &mat, &vec);
f4d7d6
				if ( !FT_Load_Glyph(face, gi->glyph_index, load_flags)
f4d7d6
				  && !FT_Render_Glyph(face->glyph, render_mode) )
f4d7d6
				{
f4d7d6
					const FT_Bitmap &bitmap = face->glyph->bitmap;
f4d7d6
					const IntVector2 offset( ix + face->glyph->bitmap_left,
f4d7d6
											 iy - face->glyph->bitmap_top );
f4d7d6
					if (antialiasing) {
f4d7d6
						if (eraze) put_ft_bitmap<true ,="" true="">(surface, bounds, bitmap, offset, color);</true>
f4d7d6
							  else put_ft_bitmap<true ,="" false="">(surface, bounds, bitmap, offset, color);</true>
f4d7d6
					} else {
f4d7d6
						if (eraze) put_ft_bitmap<false, true="">(surface, bounds, bitmap, offset, color);</false,>
f4d7d6
							  else put_ft_bitmap<false, false="">(surface, bounds, bitmap, offset, color);</false,>
f4d7d6
					}
f4d7d6
				}
f4d7d6
			}
f4d7d6
		}
f4d7d6
	}
f4d7d6
	
f4d7d6
	if (font) pango_fc_font_unlock_face((PangoFcFont*)font);
f4d7d6
}
f4d7d6