ewol/ewol/resource/FontFreeType.cpp

399 lines
14 KiB
C++

/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <etk/types.hpp>
#include <etk/Vector.hpp>
#include <etk/os/FSNode.hpp>
#include <gale/renderer/openGL/openGL.hpp>
#include <ewol/resource/Texture.hpp>
#include <ewol/resource/FontFreeType.hpp>
#include <ewol/resource/font/FontBase.hpp>
#include <gale/resource/Manager.hpp>
// free Font hnadle of librairies ... entry for acces ...
static int32_t l_countLoaded=0;
static FT_Library library;
void ewol::resource::freeTypeInit() {
EWOL_DEBUG(" == > init Font-Manager");
l_countLoaded++;
if (l_countLoaded>1) {
// already loaded ...
return;
}
int32_t error = FT_Init_FreeType( &library );
if(0 != error) {
EWOL_CRITICAL(" when loading FreeType Librairy ...");
}
}
void ewol::resource::freeTypeUnInit() {
EWOL_DEBUG(" == > Un-Init Font-Manager");
l_countLoaded--;
if (l_countLoaded>0) {
// already needed ...
return;
}
int32_t error = FT_Done_FreeType( library );
library = nullptr;
if(0 != error) {
EWOL_CRITICAL(" when Un-loading FreeType Librairy ...");
}
}
ewol::resource::FontFreeType::FontFreeType() {
addResourceType("ewol::FontFreeType");
m_init = false;
m_FileBuffer = nullptr;
m_FileSize = 0;
}
void ewol::resource::FontFreeType::init(const etk::String& _fontName) {
ethread::RecursiveLock lock(m_mutex);
ewol::resource::FontBase::init(_fontName);
etk::FSNode myfile(_fontName);
if (myfile.exist() == false) {
EWOL_ERROR("File Does not exist : " << myfile);
return;
}
m_FileSize = myfile.fileSize();
if (m_FileSize == 0) {
EWOL_ERROR("This file is empty : " << myfile);
return;
}
if (myfile.fileOpenRead() == false) {
EWOL_ERROR("Can not open the file : " << myfile);
return;
}
// allocate data
m_FileBuffer = new FT_Byte[m_FileSize];
if (m_FileBuffer == nullptr) {
EWOL_ERROR("Error Memory allocation size=" << _fontName);
return;
}
// load data from the file :
myfile.fileRead(m_FileBuffer, 1, m_FileSize);
// close the file:
myfile.fileClose();
// load Face ...
int32_t error = FT_New_Memory_Face( library, m_FileBuffer, m_FileSize, 0, &m_fftFace );
if( FT_Err_Unknown_File_Format == error) {
EWOL_ERROR("... the font file could be opened and read, but it appears ... that its font format is unsupported");
} else if (0 != error) {
EWOL_ERROR("... another error code means that the font file could not ... be opened or read, or simply that it is broken...");
} else {
// all OK
EWOL_INFO("load font : \"" << _fontName << "\" glyph count = " << (int)m_fftFace->num_glyphs);
m_init = true;
//display();
}
}
ewol::resource::FontFreeType::~FontFreeType() {
ethread::RecursiveLock lock(m_mutex);
// clean the tmp memory
if (nullptr != m_FileBuffer) {
delete[] m_FileBuffer;
m_FileBuffer = nullptr;
}
// must be deleted fftFace
FT_Done_Face( m_fftFace );
}
vec2 ewol::resource::FontFreeType::getSize(int32_t _fontSize, const etk::String& _unicodeString) {
ethread::RecursiveLock lock(m_mutex);
if(false == m_init) {
return vec2(0,0);
}
// TODO : ...
vec2 outputSize(0,0);
return outputSize;
}
int32_t ewol::resource::FontFreeType::getHeight(int32_t _fontSize) {
ethread::RecursiveLock lock(m_mutex);
return _fontSize*1.43f; // this is a really "magic" number ...
}
float ewol::resource::FontFreeType::getSizeWithHeight(float _fontHeight) {
ethread::RecursiveLock lock(m_mutex);
return _fontHeight*0.6993f; // this is a really "magic" number ...
}
bool ewol::resource::FontFreeType::getGlyphProperty(int32_t _fontSize, ewol::GlyphProperty& _property) {
ethread::RecursiveLock lock(m_mutex);
if(false == m_init) {
return false;
}
// 300dpi (hight quality) 96 dpi (normal quality)
int32_t fontQuality = 96;
// Select size ...
// note tha <<6 == *64 corespond with the 1/64th of points calculation of freetype
int32_t error = FT_Set_Char_Size(m_fftFace, _fontSize<<6, _fontSize<<6, fontQuality, fontQuality);
if (0!=error ) {
EWOL_ERROR("FT_Set_Char_Size == > error in settings ...");
return false;
}
// a small shortcut
FT_GlyphSlot slot = m_fftFace->glyph;
// retrieve glyph index from character code
int32_t glyph_index = FT_Get_Char_Index(m_fftFace, _property.m_UVal);
// load glyph image into the slot (erase previous one)
error = FT_Load_Glyph(m_fftFace, // handle to face object
glyph_index, // glyph index
FT_LOAD_DEFAULT );
if (0!=error ) {
EWOL_ERROR("FT_Load_Glyph specify Glyph");
return false;
}
// convert to an anti-aliased bitmap
error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL );
if (0!=error) {
EWOL_ERROR("FT_Render_Glyph");
return false;
}
// set properties :
_property.m_glyphIndex = glyph_index;
_property.m_sizeTexture.setValue(slot->bitmap.width, slot->bitmap.rows);
_property.m_bearing.setValue( slot->metrics.horiBearingX>>6 , slot->metrics.horiBearingY>>6 );
_property.m_advance.setValue( slot->metrics.horiAdvance>>6 , slot->metrics.vertAdvance>>6 );
return true;
}
bool ewol::resource::FontFreeType::drawGlyph(egami::Image& _imageOut,
int32_t _fontSize,
ivec2 _glyphPosition,
ewol::GlyphProperty& _property,
int8_t _posInImage) {
ethread::RecursiveLock lock(m_mutex);
if(false == m_init) {
return false;
}
// 300dpi (hight quality) 96 dpi (normal quality)
int32_t fontQuality = 96;
// Select size ...
// note tha <<6 == *64 corespond with the 1/64th of points calculation of freetype
int32_t error = FT_Set_Char_Size(m_fftFace, _fontSize<<6, _fontSize<<6, fontQuality, fontQuality);
if (0!=error ) {
EWOL_ERROR("FT_Set_Char_Size == > error in settings ...");
return false;
}
// a small shortcut
FT_GlyphSlot slot = m_fftFace->glyph;
// load glyph image into the slot (erase previous one)
error = FT_Load_Glyph(m_fftFace, // handle to face object
_property.m_glyphIndex, // glyph index
FT_LOAD_DEFAULT );
if (0!=error ) {
EWOL_ERROR("FT_Load_Glyph specify Glyph");
return false;
}
// convert to an anti-aliased bitmap
error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL );
if (0!=error) {
EWOL_ERROR("FT_Render_Glyph");
return false;
}
// draw it on the output Image :
etk::Color<> tlpppp(0xFF, 0xFF, 0xFF, 0x00);
for(size_t jjj=0; jjj < slot->bitmap.rows;jjj++) {
for(size_t iii=0; iii < slot->bitmap.width; iii++){
tlpppp = _imageOut.get(ivec2(_glyphPosition.x()+iii, _glyphPosition.y()+jjj));
uint8_t valueColor = slot->bitmap.buffer[iii + slot->bitmap.width*jjj];
// set only alpha :
switch(_posInImage) {
default:
case 0:
tlpppp.setA(valueColor);
break;
case 1:
tlpppp.setR(valueColor);
break;
case 2:
tlpppp.setG(valueColor);
break;
case 3:
tlpppp.setB(valueColor);
break;
}
// real set of color
_imageOut.set(ivec2(_glyphPosition.x()+iii, _glyphPosition.y()+jjj), tlpppp );
}
}
return true;
}
bool ewol::resource::FontFreeType::drawGlyph(egami::ImageMono& _imageOut,
int32_t _fontSize,
ewol::GlyphProperty& _property,
int32_t _borderSize) {
ethread::RecursiveLock lock(m_mutex);
if(false == m_init) {
return false;
}
// 300dpi (hight quality) 96 dpi (normal quality)
int32_t fontQuality = 96;
// Select size ...
// note tha <<6 == *64 corespond with the 1/64th of points calculation of freetype
int32_t error = FT_Set_Char_Size(m_fftFace, _fontSize<<6, _fontSize<<6, fontQuality, fontQuality);
if (0!=error ) {
EWOL_ERROR("FT_Set_Char_Size == > error in settings ...");
return false;
}
// a small shortcut
FT_GlyphSlot slot = m_fftFace->glyph;
// load glyph image into the slot (erase previous one)
error = FT_Load_Glyph(m_fftFace, // handle to face object
_property.m_glyphIndex, // glyph index
FT_LOAD_DEFAULT );
if (0!=error ) {
EWOL_ERROR("FT_Load_Glyph specify Glyph");
return false;
}
// convert to an anti-aliased bitmap
error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL ); // TODO : set FT_RENDER_MODE_MONO ==> 1 bit value ==> faster generation ...
if (0!=error) {
EWOL_ERROR("FT_Render_Glyph");
return false;
}
// resize output image :
_imageOut.resize(ivec2(slot->bitmap.width+2*_borderSize, slot->bitmap.rows+2*_borderSize), 0);
for(size_t jjj=0; jjj < slot->bitmap.rows;jjj++) {
for(size_t iii=0; iii < slot->bitmap.width; iii++){
uint8_t valueColor = slot->bitmap.buffer[iii + slot->bitmap.width*jjj];
// real set of color
_imageOut.set(ivec2(_borderSize+iii, _borderSize+jjj), valueColor );
}
}
return true;
}
void ewol::resource::FontFreeType::generateKerning(int32_t fontSize, etk::Vector<ewol::GlyphProperty>& listGlyph) {
ethread::RecursiveLock lock(m_mutex);
if(m_init == false) {
return;
}
if ((FT_FACE_FLAG_KERNING & m_fftFace->face_flags) == 0) {
EWOL_INFO("No kerning generation (disable) in the font");
}
// 300dpi (hight quality) 96 dpi (normal quality)
int32_t fontQuality = 96;
// Select size ...
// note tha <<6 == *64 corespond with the 1/64th of points calculation of freetype
int32_t error = FT_Set_Char_Size(m_fftFace, fontSize<<6, fontSize<<6, fontQuality, fontQuality);
if (0!=error ) {
EWOL_ERROR("FT_Set_Char_Size == > error in settings ...");
return;
}
// For all the kerning element we get the kerning value :
for(size_t iii=0; iii<listGlyph.size(); iii++) {
listGlyph[iii].kerningClear();
for(size_t kkk=0; kkk<listGlyph.size(); kkk++) {
FT_Vector kerning;
FT_Get_Kerning(m_fftFace, listGlyph[kkk].m_glyphIndex, listGlyph[iii].m_glyphIndex, FT_KERNING_UNFITTED, &kerning );
// add the kerning only if != 0 ...
if (kerning.x != 0) {
listGlyph[iii].kerningAdd(listGlyph[kkk].m_UVal,
kerning.x/32.0f );
//EWOL_DEBUG("Kerning between : '" << (char)listGlyph[iii].m_UVal << "'&'" << (char)listGlyph[kkk].m_UVal << "' value : " << kerning.x << " => " << (kerning.x/64.0f));
}
}
}
}
void ewol::resource::FontFreeType::display() {
ethread::RecursiveLock lock(m_mutex);
if(m_init == false) {
return;
}
EWOL_INFO(" number of glyph = " << (int)m_fftFace->num_glyphs);
if ((FT_FACE_FLAG_SCALABLE & m_fftFace->face_flags) != 0) {
EWOL_INFO(" flags = FT_FACE_FLAG_SCALABLE (enable)");
} else {
EWOL_DEBUG(" flags = FT_FACE_FLAG_SCALABLE (disable)");
}
if ((FT_FACE_FLAG_FIXED_SIZES & m_fftFace->face_flags) != 0) {
EWOL_INFO(" flags = FT_FACE_FLAG_FIXED_SIZES (enable)");
} else {
EWOL_DEBUG(" flags = FT_FACE_FLAG_FIXED_SIZES (disable)");
}
if ((FT_FACE_FLAG_FIXED_WIDTH & m_fftFace->face_flags) != 0) {
EWOL_INFO(" flags = FT_FACE_FLAG_FIXED_WIDTH (enable)");
} else {
EWOL_DEBUG(" flags = FT_FACE_FLAG_FIXED_WIDTH (disable)");
}
if ((FT_FACE_FLAG_SFNT & m_fftFace->face_flags) != 0) {
EWOL_INFO(" flags = FT_FACE_FLAG_SFNT (enable)");
} else {
EWOL_DEBUG(" flags = FT_FACE_FLAG_SFNT (disable)");
}
if ((FT_FACE_FLAG_HORIZONTAL & m_fftFace->face_flags) != 0) {
EWOL_INFO(" flags = FT_FACE_FLAG_HORIZONTAL (enable)");
} else {
EWOL_DEBUG(" flags = FT_FACE_FLAG_HORIZONTAL (disable)");
}
if ((FT_FACE_FLAG_VERTICAL & m_fftFace->face_flags) != 0) {
EWOL_INFO(" flags = FT_FACE_FLAG_VERTICAL (enable)");
} else {
EWOL_DEBUG(" flags = FT_FACE_FLAG_VERTICAL (disable)");
}
if ((FT_FACE_FLAG_KERNING & m_fftFace->face_flags) != 0) {
EWOL_INFO(" flags = FT_FACE_FLAG_KERNING (enable)");
} else {
EWOL_DEBUG(" flags = FT_FACE_FLAG_KERNING (disable)");
}
/* Deprecated flag
if ((FT_FACE_FLAG_FAST_GLYPHS & face->face_flags) != 0) {
EWOL_INFO(" flags = FT_FACE_FLAG_FAST_GLYPHS (enable)");
} else {
EWOL_DEBUG(" flags = FT_FACE_FLAG_FAST_GLYPHS (disable)");
}
*/
if ((FT_FACE_FLAG_MULTIPLE_MASTERS & m_fftFace->face_flags) != 0) {
EWOL_INFO(" flags = FT_FACE_FLAG_MULTIPLE_MASTERS (enable)");
} else {
EWOL_DEBUG(" flags = FT_FACE_FLAG_MULTIPLE_MASTERS (disable)");
}
if ((FT_FACE_FLAG_GLYPH_NAMES & m_fftFace->face_flags) != 0) {
EWOL_INFO(" flags = FT_FACE_FLAG_GLYPH_NAMES (enable)");
} else {
EWOL_DEBUG(" flags = FT_FACE_FLAG_GLYPH_NAMES (disable)");
}
if ((FT_FACE_FLAG_EXTERNAL_STREAM & m_fftFace->face_flags) != 0) {
EWOL_INFO(" flags = FT_FACE_FLAG_EXTERNAL_STREAM (enable)");
} else {
EWOL_DEBUG(" flags = FT_FACE_FLAG_EXTERNAL_STREAM (disable)");
}
if ((FT_FACE_FLAG_HINTER & m_fftFace->face_flags) != 0) {
EWOL_INFO(" flags = FT_FACE_FLAG_HINTER (enable)");
} else {
EWOL_DEBUG(" flags = FT_FACE_FLAG_HINTER (disable)");
}
if ((FT_FACE_FLAG_CID_KEYED & m_fftFace->face_flags) != 0) {
EWOL_INFO(" flags = FT_FACE_FLAG_CID_KEYED (enable)");
} else {
EWOL_DEBUG(" flags = FT_FACE_FLAG_CID_KEYED (disable)");
}
/*
if ((FT_FACE_FLAG_TRICKY & m_fftFace->face_flags) != 0) {
EWOL_INFO(" flags = FT_FACE_FLAG_TRICKY (enable)");
} else {
EWOL_DEBUG(" flags = FT_FACE_FLAG_TRICKY (disable)");
}
*/
EWOL_INFO(" unit per EM = " << m_fftFace->units_per_EM);
EWOL_INFO(" num of fixed sizes = " << m_fftFace->num_fixed_sizes);
//EWOL_INFO(" Availlable sizes = " << (int)m_fftFace->available_sizes);
//EWOL_INFO(" Current size = " << (int)m_fftFace->size);
}