<commit_before>// Copyright (C) 2014 <NAME> - 2009 Cruden BV
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Utility/Loaders/FreeType.hpp>
#include <freetype/ft2build.h>
#include FT_FREETYPE_H
#include FT_BITMAP_H
#include FT_OUTLINE_H
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/InputStream.hpp>
#include <Nazara/Utility/Font.hpp>
#include <Nazara/Utility/FontData.hpp>
#include <Nazara/Utility/FontGlyph.hpp>
#include <memory>
#include <set>
#include <Nazara/Utility/Debug.hpp>

namespace
{
	FT_Library s_library = nullptr;
	float s_invScaleFactor = 1.f / (1 << 6); // 1/64

	extern "C"
	unsigned long FT_StreamRead(FT_Stream stream, unsigned long offset, unsigned char* buffer, unsigned long count)
	{
		// http://www.freetype.org/freetype2/docs/reference/ft2-system_interface.html#FT_Stream_IoFunc
		NzInputStream& inputStream = *static_cast<NzInputStream*>(stream->descriptor.pointer);

		// La valeur de count indique une opération de lecture ou de positionnement
		if (count > 0)
		{
			// Dans le premier cas, une erreur est symbolisée par un retour nul
			if (inputStream.SetCursorPos(offset))
				return static_cast<unsigned long>(inputStream.Read(buffer, count));
			else
				return 0;
		}
		else
		{
			// Dans le second cas, une erreur est symbolisée par un retour non-nul
			if (inputStream.SetCursorPos(offset))
				return 0;
			else
				return 42; // La réponse à la grande question
		}
	}

	extern "C"
	void FT_StreamClose(FT_Stream stream)
	{
		// http://www.freetype.org/freetype2/docs/reference/ft2-system_interface.html#FT_Stream_CloseFunc
		// Les streams dans Nazara ne se ferment pas explicitement
		NazaraUnused(stream);
	}

	class FreeTypeStream : public NzFontData
	{
		public:
			FreeTypeStream() :
			m_face(nullptr),
			m_characterSize(0)
			{
			}

			~FreeTypeStream()
			{
				if (m_face)
					FT_Done_Face(m_face);
			}

			bool Check()
			{
				// Test d'ouverture (http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Open_Face)
				return FT_Open_Face(s_library, &m_args, -1, nullptr) == 0;
			}

			bool ExtractGlyph(unsigned int characterSize, char32_t character, bool bold, NzFontGlyph* dst)
			{
				#ifdef NAZARA_DEBUG
				if (!dst)
				{
					NazaraError("Glyph destination cannot be null");
					return false;
				}
				#endif

				SetCharacterSize(characterSize);

			    if (FT_Load_Char(m_face, character, FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL) != 0)
				{
					NazaraError("Failed to load character");
					return false;
				}

				FT_GlyphSlot& glyph = m_face->glyph;

				const FT_Pos boldStrength = 1 << 6;

				bool outlineFormat = (glyph->format == FT_GLYPH_FORMAT_OUTLINE);
				if (outlineFormat && bold)
					// http://www.freetype.org/freetype2/docs/reference/ft2-outline_processing.html#FT_Outline_Embolden
					FT_Outline_Embolden(&glyph->outline, boldStrength);

				// http://www.freetype.org/freetype2/docs/reference/ft2-glyph_management.html#FT_Glyph_To_Bitmap
				// Conversion du glyphe vers le format bitmap
				// Cette fonction ne fait rien dans le cas où le glyphe est déjà un bitmap
				if (FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL) != 0)
				{
					NazaraError("Failed to convert glyph to bitmap");
					return false;
				}

				// Dans le cas où nous voulons des caractères gras mais que nous n'avons pas pu agir plus tôt
				// nous demandons à FreeType d'agir directement sur le bitmap généré
				if (!outlineFormat && bold)
				{
					// http://www.freetype.org/freetype2/docs/reference/ft2-bitmap_handling.html#FT_Bitmap_Embolden<commit_msg>(FreeType) Made Bold more strong<commit_after>// Copyright (C) 2014 <NAME> - 2009 Cruden BV
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Utility/Loaders/FreeType.hpp>
#include <freetype/ft2build.h>
#include FT_FREETYPE_H
#include FT_BITMAP_H
#include FT_OUTLINE_H
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/InputStream.hpp>
#include <Nazara/Utility/Font.hpp>
#include <Nazara/Utility/FontData.hpp>
#include <Nazara/Utility/FontGlyph.hpp>
#include <memory>
#include <set>
#include <Nazara/Utility/Debug.hpp>

namespace
{
	FT_Library s_library = nullptr;
	float s_invScaleFactor = 1.f / (1 << 6); // 1/64

	extern "C"
	unsigned long FT_StreamRead(FT_Stream stream, unsigned long offset, unsigned char* buffer, unsigned long count)
	{
		// http://www.freetype.org/freetype2/docs/reference/ft2-system_interface.html#FT_Stream_IoFunc
		NzInputStream& inputStream = *static_cast<NzInputStream*>(stream->descriptor.pointer);

		// La valeur de count indique une opération de lecture ou de positionnement
		if (count > 0)
		{
			// Dans le premier cas, une erreur est symbolisée par un retour nul
			if (inputStream.SetCursorPos(offset))
				return static_cast<unsigned long>(inputStream.Read(buffer, count));
			else
				return 0;
		}
		else
		{
			// Dans le second cas, une erreur est symbolisée par un retour non-nul
			if (inputStream.SetCursorPos(offset))
				return 0;
			else
				return 42; // La réponse à la grande question
		}
	}

	extern "C"
	void FT_StreamClose(FT_Stream stream)
	{
		// http://www.freetype.org/freetype2/docs/reference/ft2-system_interface.html#FT_Stream_CloseFunc
		// Les streams dans Nazara ne se ferment pas explicitement
		NazaraUnused(stream);
	}

	class FreeTypeStream : public NzFontData
	{
		public:
			FreeTypeStream() :
			m_face(nullptr),
			m_characterSize(0)
			{
			}

			~FreeTypeStream()
			{
				if (m_face)
					FT_Done_Face(m_face);
			}

			bool Check()
			{
				// Test d'ouverture (http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Open_Face)
				return FT_Open_Face(s_library, &m_args, -1, nullptr) == 0;
			}

			bool ExtractGlyph(unsigned int characterSize, char32_t character, bool bold, NzFontGlyph* dst)
			{
				#ifdef NAZARA_DEBUG
				if (!dst)
				{
					NazaraError("Glyph destination cannot be null");
					return false;
				}
				#endif

				SetCharacterSize(characterSize);

			    if (FT_Load_Char(m_face, character, FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL) != 0)
				{
					NazaraError("Failed to load character");
					return false;
				}

				FT_GlyphSlot& glyph = m_face->glyph;

				const FT_Pos boldStrength = 2 << 6;

				bool outlineFormat = (glyph->format == FT_GLYPH_FORMAT_OUTLINE);
				if (outlineFormat && bold)
					// http://www.freetype.org/freetype2/docs/reference/ft2-outline_processing.html#FT_Outline_Embolden
					FT_Outline_Embolden(&glyph->outline, boldStrength);

				// http://www.freetype.org/freetype2/docs/reference/ft2-glyph_management.html#FT_Glyph_To_Bitmap
				// Conversion du glyphe vers le format bitmap
				// Cette fonction ne fait rien dans le cas où le glyphe est déjà un bitmap
				if (FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL) != 0)
				{
					NazaraError("Failed to convert glyph to bitmap");
					return false;
				}

				// Dans le cas où nous voulons des caractères gras mais que nous n'avons pas pu agir plus tôt
				// nous demandons à FreeType d'agir directement sur le bitmap généré
				if (!outlineFormat && bold)
				{
					// http://www.freetype.org/freetype2/docs/reference/ft2-bitmap_handling.html#FT_Bitmap_Embolden
{'fraction_non_alphanumeric': 0.10512019557245687, 'fraction_numerical': 0.011136764905609126, 'mean_word_length': 3.651926721415035, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 12, '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': '6532410', 'n_tokens_mistral': 2988, 'n_tokens_neox': 2542, 'n_words': 615}