<commit_before>
#include "canvas.h"
#include <draw/shaders.h>
#include <gl/check.h>

////////////////////////////////////////

namespace
{
	inline uint8_t clampColorByte( double c )
	{
		c = std::max( 0.0, std::min( 255.0, std::floor( c * 256.0 ) ) );
		return uint8_t( c );
	}
}

////////////////////////////////////////

namespace draw
{

////////////////////////////////////////

canvas::canvas( void )
{
}

////////////////////////////////////////

canvas::~canvas( void )
{
}

////////////////////////////////////////

std::shared_ptr<gl::texture> canvas::gradient( const core::gradient &g, size_t n )
{
	std::vector<uint8_t> bytes( n * 4 );
	for ( size_t i = 0; i < n; ++i )
	{
		double stop = double(i)/double(n);
		core::color c = g.sample( stop );
		bytes[i*4+0] = clampColorByte( c.red() );
		bytes[i*4+1] = clampColorByte( c.green() );
		bytes[i*4+2] = clampColorByte( c.blue() );
		bytes[i*4+3] = clampColorByte( c.alpha() );
	}

	auto ret = new_texture();
	{
		auto txt = ret->bind( gl::texture::target::TEXTURE_RECTANGLE );
		txt.image_2d( gl::format::RGBA, bytes.size(), 1, gl::image_type::UNSIGNED_BYTE, bytes.data() );
	}
	return ret;
}

////////////////////////////////////////

std::shared_ptr<gl::program> canvas::program( const std::string &vert, const std::string &frag )
{
	auto vshader = new_shader( gl::shader::type::VERTEX, draw::shaders( vert ) );
	auto fshader = new_shader( gl::shader::type::FRAGMENT, draw::shaders( frag ) );
	return new_program( vshader, fshader );
}

////////////////////////////////////////

core::point
canvas::align_text( const std::shared_ptr<font> &font, const std::string &utf8, const core::rect &rect, alignment a )
{
	if ( ! font || utf8.empty() )
		return { 0.0, 0.0 };

	// TODO: add multi-line support?

	font_extents fex = font->extents();
	text_extents tex = font->extents( utf8 );

	double y = 0.0, x = 0.0;
	double textHeight = fex.ascent - fex.descent;

	switch ( a )<commit_msg>Align text exactly on grid.<commit_after>
#include "canvas.h"
#include <draw/shaders.h>
#include <gl/check.h>

////////////////////////////////////////

namespace
{
	inline uint8_t clampColorByte( double c )
	{
		c = std::max( 0.0, std::min( 255.0, std::floor( c * 256.0 ) ) );
		return uint8_t( c );
	}
}

////////////////////////////////////////

namespace draw
{

////////////////////////////////////////

canvas::canvas( void )
{
}

////////////////////////////////////////

canvas::~canvas( void )
{
}

////////////////////////////////////////

std::shared_ptr<gl::texture> canvas::gradient( const core::gradient &g, size_t n )
{
	std::vector<uint8_t> bytes( n * 4 );
	for ( size_t i = 0; i < n; ++i )
	{
		double stop = double(i)/double(n);
		core::color c = g.sample( stop );
		bytes[i*4+0] = clampColorByte( c.red() );
		bytes[i*4+1] = clampColorByte( c.green() );
		bytes[i*4+2] = clampColorByte( c.blue() );
		bytes[i*4+3] = clampColorByte( c.alpha() );
	}

	auto ret = new_texture();
	{
		auto txt = ret->bind( gl::texture::target::TEXTURE_RECTANGLE );
		txt.image_2d( gl::format::RGBA, bytes.size(), 1, gl::image_type::UNSIGNED_BYTE, bytes.data() );
	}
	return ret;
}

////////////////////////////////////////

std::shared_ptr<gl::program> canvas::program( const std::string &vert, const std::string &frag )
{
	auto vshader = new_shader( gl::shader::type::VERTEX, draw::shaders( vert ) );
	auto fshader = new_shader( gl::shader::type::FRAGMENT, draw::shaders( frag ) );
	return new_program( vshader, fshader );
}

////////////////////////////////////////

core::point
canvas::align_text( const std::shared_ptr<font> &font, const std::string &utf8, const core::rect &r, alignment a )
{
	core::rect rect;
	rect.set_x1( std::ceil( r.x1() ) );
	rect.set_y1( std::ceil( r.y1() ) );
	rect.set_x2( std::floor( r.x2() ) );
	rect.set_y2( std::floor( r.y2() ) );

	if ( ! font || utf8.empty() )
		return { 0.0, 0.0 };

	// TODO: add multi-line support?

	font_extents fex = font->extents();
	text_extents tex = font->extents( utf8 );

	double y = 0.0, x = 0.0;
	double textHeight = fex.ascent - fex.descent;

	switch ( a )
{'fraction_non_alphanumeric': 0.3023598820058997, 'fraction_numerical': 0.01966568338249754, 'mean_word_length': 2.2761674718196456, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2305494', 'n_tokens_mistral': 1503, 'n_tokens_neox': 1443, 'n_words': 312}