370 lines
14 KiB
C++
370 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 <egami/egami.hpp>
|
|
|
|
#include <gale/resource/Manager.hpp>
|
|
|
|
#include <ewol/resource/font/FontBase.hpp>
|
|
#include <ewol/resource/TexturedFont.hpp>
|
|
#include <ewol/resource/FontFreeType.hpp>
|
|
#include <ewol/context/Context.hpp>
|
|
#include <etk/typeInfo.hpp>
|
|
ETK_DECLARE_TYPE(ewol::font::mode);
|
|
ETK_DECLARE_TYPE(ewol::resource::TexturedFont);
|
|
|
|
etk::Stream& ewol::operator <<(etk::Stream& _os, enum ewol::font::mode _obj) {
|
|
switch(_obj) {
|
|
default :
|
|
_os << "error";
|
|
break;
|
|
case ewol::font::Regular:
|
|
_os << "Regular";
|
|
break;
|
|
case ewol::font::Italic:
|
|
_os << "Italic";
|
|
break;
|
|
case ewol::font::Bold:
|
|
_os << "Bold";
|
|
break;
|
|
case ewol::font::BoldItalic:
|
|
_os << "BoldItalic";
|
|
break;
|
|
}
|
|
return _os;
|
|
}
|
|
|
|
ewol::resource::TexturedFont::TexturedFont():
|
|
m_size(10) {
|
|
addResourceType("ewol::resource::TexturedFont");
|
|
}
|
|
|
|
/**
|
|
* @brief Get all the Path contain in the specidy path:
|
|
* @param[in] _path Generic path to parse ...
|
|
* @return The list of path found
|
|
* @example[start]
|
|
* auto out = explodeMultiplePath("DATA:///font?lib=ewol");
|
|
* // out contain: {"DATA:///font", "DATA:///font?lib=ewol"}
|
|
* @example[stop]
|
|
*/
|
|
static etk::Vector<etk::Uri> explodeMultiplePath(const etk::Uri& _uri) {
|
|
etk::Vector<etk::Uri> out;
|
|
out.pushBack(_uri);
|
|
if (_uri.getQuery().exist("lib") == true) {
|
|
etk::Uri tmp = _uri;
|
|
tmp.getQuery().erase("lib");
|
|
out.pushBack(tmp);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
void ewol::resource::TexturedFont::init(const etk::String& _fontName) {
|
|
ethread::RecursiveLock lock(m_mutex);
|
|
ewol::resource::Texture::init(_fontName);
|
|
EWOL_DEBUG("Load font : '" << _fontName << "'" );
|
|
|
|
m_font[0] = null;
|
|
m_font[1] = null;
|
|
m_font[2] = null;
|
|
m_font[3] = null;
|
|
|
|
m_modeWraping[0] = ewol::font::Regular;
|
|
m_modeWraping[1] = ewol::font::Regular;
|
|
m_modeWraping[2] = ewol::font::Regular;
|
|
m_modeWraping[3] = ewol::font::Regular;
|
|
|
|
m_lastGlyphPos[0].setValue(1,1);
|
|
m_lastGlyphPos[1].setValue(1,1);
|
|
m_lastGlyphPos[2].setValue(1,1);
|
|
m_lastGlyphPos[3].setValue(1,1);
|
|
|
|
m_lastRawHeigh[0] = 0;
|
|
m_lastRawHeigh[1] = 0;
|
|
m_lastRawHeigh[2] = 0;
|
|
m_lastRawHeigh[3] = 0;
|
|
|
|
int32_t tmpSize = 0;
|
|
// extarct name and size :
|
|
const char * tmpData = _fontName.c_str();
|
|
const char * tmpPos = strchr(tmpData, ':');
|
|
|
|
if (tmpPos == null) {
|
|
m_size = 1;
|
|
EWOL_CRITICAL("Can not parse the font name: '" << _fontName << "' ??? ':' " );
|
|
return;
|
|
} else {
|
|
if (sscanf(tmpPos+1, "%d", &tmpSize)!=1) {
|
|
m_size = 1;
|
|
EWOL_CRITICAL("Can not parse the font name: '" << _fontName << "' == > size ???");
|
|
return;
|
|
}
|
|
}
|
|
etk::String localName(_fontName, 0, (tmpPos - tmpData));
|
|
if (tmpSize>400) {
|
|
EWOL_ERROR("Font size too big ==> limit at 400 when exxeed ==> error: " << tmpSize << "==>30");
|
|
tmpSize = 30;
|
|
}
|
|
m_size = tmpSize;
|
|
|
|
etk::Vector<etk::Uri> folderList;
|
|
if (ewol::getContext().getFontDefault().getUseExternal() == true) {
|
|
#if defined(__TARGET_OS__Android)
|
|
folderList.pushBack(etk::Path("/system/fonts"));
|
|
#elif defined(__TARGET_OS__Linux)
|
|
folderList.pushBack(etk::Path("/usr/share/fonts"));
|
|
#endif
|
|
}
|
|
etk::Uri applicationBaseFont = ewol::getContext().getFontDefault().getFolder();
|
|
for (auto &it : explodeMultiplePath(applicationBaseFont)) {
|
|
folderList.pushBack(it);
|
|
}
|
|
for (size_t folderID = 0; folderID < folderList.size() ; folderID++) {
|
|
etk::Vector<etk::Uri> output = etk::uri::listRecursive(folderList[folderID]);
|
|
|
|
etk::Vector<etk::String> split = etk::split(localName, ';');
|
|
EWOL_DEBUG("try to find font named : " << split << " in: " << output);
|
|
//EWOL_CRITICAL("parse string : " << split);
|
|
bool hasFindAFont = false;
|
|
for (size_t jjj=0; jjj<split.size(); jjj++) {
|
|
EWOL_DEBUG(" try with : '" << split[jjj] << "'");
|
|
for (size_t iii=0; iii<output.size(); iii++) {
|
|
etk::String nameFolder = output[iii].getPath().getString();
|
|
//EWOL_DEBUG(" file : " << output[iii]);
|
|
if( etk::end_with(nameFolder, split[jjj]+"-"+"bold"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"-"+"b"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"-"+"bd"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"bold"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"bd"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"b"+".ttf", false) == true) {
|
|
EWOL_DEBUG(" find Font [Bold] : " << output[iii]);
|
|
m_fileName[ewol::font::Bold] = output[iii];
|
|
hasFindAFont = true;
|
|
} else if( etk::end_with(nameFolder, split[jjj]+"-"+"oblique"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"-"+"italic"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"-"+"Light"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"-"+"i"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"oblique"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"italic"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"light"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"i"+".ttf", false) == true) {
|
|
EWOL_DEBUG(" find Font [Italic] : " << output[iii]);
|
|
m_fileName[ewol::font::Italic] = output[iii];
|
|
hasFindAFont = true;
|
|
} else if( etk::end_with(nameFolder, split[jjj]+"-"+"bolditalic"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"-"+"boldoblique"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"-"+"bi"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"-"+"z"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"bolditalic"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"boldoblique"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"bi"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"z"+".ttf", false) == true) {
|
|
EWOL_DEBUG(" find Font [Bold-Italic] : " << output[iii]);
|
|
m_fileName[ewol::font::BoldItalic] = output[iii];
|
|
hasFindAFont = true;
|
|
} else if( etk::end_with(nameFolder, split[jjj]+"-"+"regular"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"-"+"r"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"regular"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+"r"+".ttf", false) == true
|
|
|| etk::end_with(nameFolder, split[jjj]+".ttf", false) == true) {
|
|
EWOL_DEBUG(" find Font [Regular] : " << output[iii]);
|
|
m_fileName[ewol::font::Regular] = output[iii];
|
|
hasFindAFont = true;
|
|
}
|
|
}
|
|
if (hasFindAFont == true) {
|
|
EWOL_DEBUG(" find this font : '" << split[jjj] << "'");
|
|
break;
|
|
} else if (jjj == split.size()-1) {
|
|
EWOL_DEBUG("Find NO font in the LIST ... " << split);
|
|
}
|
|
}
|
|
if (hasFindAFont == true) {
|
|
EWOL_DEBUG(" find this font : '" << folderList[folderID] << "'");
|
|
break;
|
|
} else if (folderID == folderList.size()-1) {
|
|
EWOL_ERROR("Find NO font in the LIST ... " << folderList);
|
|
}
|
|
}
|
|
// try to find the reference mode :
|
|
enum ewol::font::mode refMode = ewol::font::Regular;
|
|
for(int32_t iii=3; iii >= 0; iii--) {
|
|
if (m_fileName[iii].isEmpty() == false) {
|
|
refMode = (enum ewol::font::mode)iii;
|
|
}
|
|
}
|
|
EWOL_DEBUG(" set reference mode : " << refMode);
|
|
// generate the wrapping on the preventing error
|
|
for(int32_t iii=3; iii >= 0; iii--) {
|
|
if (m_fileName[iii].isEmpty() == false) {
|
|
m_modeWraping[iii] = (enum ewol::font::mode)iii;
|
|
} else {
|
|
m_modeWraping[iii] = refMode;
|
|
}
|
|
}
|
|
|
|
for (int32_t iiiFontId=0; iiiFontId<4 ; iiiFontId++) {
|
|
if (m_fileName[iiiFontId].isEmpty() == true) {
|
|
EWOL_DEBUG("can not load FONT [" << iiiFontId << "] name : \"" << m_fileName[iiiFontId] << "\" == > size=" << m_size );
|
|
m_font[iiiFontId] = null;
|
|
continue;
|
|
}
|
|
EWOL_DEBUG("Load FONT [" << iiiFontId << "] name : \"" << m_fileName[iiiFontId] << "\" == > size=" << m_size);
|
|
m_font[iiiFontId] = ewol::resource::FontFreeType::create(m_fileName[iiiFontId]);
|
|
if (m_font[iiiFontId] == null) {
|
|
EWOL_DEBUG("error in loading FONT [" << iiiFontId << "] name : \"" << m_fileName[iiiFontId] << "\" == > size=" << m_size );
|
|
}
|
|
}
|
|
for (int32_t iiiFontId=0; iiiFontId<4 ; iiiFontId++) {
|
|
// set the bassic charset:
|
|
m_listElement[iiiFontId].clear();
|
|
if (m_font[iiiFontId] == null) {
|
|
continue;
|
|
}
|
|
m_height[iiiFontId] = m_font[iiiFontId]->getHeight(m_size);
|
|
// TODO : basic font use 512 is better ... == > maybe estimate it with the dpi ???
|
|
setImageSize(ivec2(256,32));
|
|
// now we can acces directly on the image
|
|
m_data.clear(etk::Color<>(0x00000000));
|
|
}
|
|
// add error glyph
|
|
addGlyph(0);
|
|
// by default we set only the first AINSI char availlable
|
|
for (int32_t iii=0x20; iii<0x7F; iii++) {
|
|
EWOL_VERBOSE("Add clyph :" << iii);
|
|
addGlyph(iii);
|
|
}
|
|
flush();
|
|
EWOL_DEBUG("Wrapping properties : ");
|
|
EWOL_DEBUG(" " << ewol::font::Regular << " == >" << getWrappingMode(ewol::font::Regular));
|
|
EWOL_DEBUG(" " << ewol::font::Italic << " == >" << getWrappingMode(ewol::font::Italic));
|
|
EWOL_DEBUG(" " << ewol::font::Bold << " == >" << getWrappingMode(ewol::font::Bold));
|
|
EWOL_DEBUG(" " << ewol::font::BoldItalic << " == >" << getWrappingMode(ewol::font::BoldItalic));
|
|
}
|
|
|
|
ewol::resource::TexturedFont::~TexturedFont() {
|
|
|
|
}
|
|
|
|
bool ewol::resource::TexturedFont::addGlyph(const char32_t& _val) {
|
|
ethread::RecursiveLock lock(m_mutex);
|
|
bool hasChange = false;
|
|
// for each font :
|
|
for (int32_t iii=0; iii<4 ; iii++) {
|
|
if (m_font[iii] == null) {
|
|
continue;
|
|
}
|
|
// add the curent "char"
|
|
GlyphProperty tmpchar;
|
|
tmpchar.m_UVal = _val;
|
|
|
|
if (m_font[iii]->getGlyphProperty(m_size, tmpchar) == true) {
|
|
//EWOL_DEBUG("load char : '" << _val << "'=" << _val.get());
|
|
hasChange = true;
|
|
// change line if needed ...
|
|
if (m_lastGlyphPos[iii].x()+tmpchar.m_sizeTexture.x()+3 > m_data.getSize().x()) {
|
|
m_lastGlyphPos[iii].setX(1);
|
|
m_lastGlyphPos[iii] += ivec2(0, m_lastRawHeigh[iii]);
|
|
m_lastRawHeigh[iii] = 0;
|
|
}
|
|
while(m_lastGlyphPos[iii].y()+tmpchar.m_sizeTexture.y()+3 > m_data.getSize().y()) {
|
|
ivec2 size = m_data.getSize();
|
|
size.setY(size.y()*2);
|
|
m_data.resize(size, etk::Color<>(0));
|
|
// note : need to rework all the lyer due to the fact that the texture is used by the faur type...
|
|
for (size_t kkk=0; kkk<4 ; kkk++) {
|
|
// change the coordonate on the element in the texture
|
|
for (size_t jjj=0 ; jjj<m_listElement[kkk].size() ; ++jjj) {
|
|
m_listElement[kkk][jjj].m_texturePosStart *= vec2(1.0f, 0.5f);
|
|
m_listElement[kkk][jjj].m_texturePosSize *= vec2(1.0f, 0.5f);
|
|
}
|
|
}
|
|
}
|
|
// draw the glyph
|
|
m_font[iii]->drawGlyph(m_data, m_size, m_lastGlyphPos[iii], tmpchar, iii);
|
|
// set video position
|
|
tmpchar.m_texturePosStart.setValue( (float)m_lastGlyphPos[iii].x() / (float)m_data.getSize().x(),
|
|
(float)m_lastGlyphPos[iii].y() / (float)m_data.getSize().y() );
|
|
tmpchar.m_texturePosSize.setValue( (float)tmpchar.m_sizeTexture.x() / (float)m_data.getSize().x(),
|
|
(float)tmpchar.m_sizeTexture.y() / (float)m_data.getSize().y() );
|
|
|
|
// update the maximum of the line hight :
|
|
if (m_lastRawHeigh[iii]<tmpchar.m_sizeTexture.y()) {
|
|
// note : +1 is for the overlapping of the glyph (Part 2)
|
|
m_lastRawHeigh[iii] = tmpchar.m_sizeTexture.y()+1;
|
|
}
|
|
// note : +1 is for the overlapping of the glyph (Part 3)
|
|
// update the Bitmap position drawing :
|
|
m_lastGlyphPos[iii] += ivec2(tmpchar.m_sizeTexture.x()+1, 0);
|
|
} else {
|
|
EWOL_WARNING("Did not find char : '" << _val << "'=" << _val);
|
|
tmpchar.setNotExist();
|
|
}
|
|
m_listElement[iii].pushBack(tmpchar);
|
|
//m_font[iii]->display();
|
|
// generate the kerning for all the characters :
|
|
if (tmpchar.exist() == true) {
|
|
// TODO : set the kerning back ...
|
|
//m_font[iii]->generateKerning(m_size, m_listElement[iii]);
|
|
}
|
|
}
|
|
if (hasChange == true) {
|
|
flush();
|
|
ewol::getContext().forceRedrawAll();
|
|
//egami::store(m_data, "fileFont.bmp"); // ==> for debug test only ...
|
|
}
|
|
return hasChange;
|
|
}
|
|
|
|
int32_t ewol::resource::TexturedFont::getIndex(char32_t _charcode, const enum ewol::font::mode _displayMode) {
|
|
ethread::RecursiveLock lock(m_mutex);
|
|
if (_charcode < 0x20) {
|
|
return 0;
|
|
} else if (_charcode < 0x80) {
|
|
return _charcode - 0x1F;
|
|
} else {
|
|
for (size_t iii=0x80-0x20; iii < m_listElement[_displayMode].size(); iii++) {
|
|
//EWOL_DEBUG("search : '" << charcode << "' =?= '" << (m_listElement[displayMode])[iii].m_UVal << "'");
|
|
if (_charcode == (m_listElement[_displayMode])[iii].m_UVal) {
|
|
//EWOL_DEBUG("search : '" << charcode << "'");
|
|
if ((m_listElement[_displayMode])[iii].exist()) {
|
|
//EWOL_DEBUG("return " << iii);
|
|
return iii;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (addGlyph(_charcode) == true) {
|
|
// TODO : This does not work due to the fact that the update of open GL is not done in the context main cycle !!!
|
|
ewol::getContext().forceRedrawAll();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ewol::GlyphProperty* ewol::resource::TexturedFont::getGlyphPointer(const char32_t& _charcode, const enum ewol::font::mode _displayMode) {
|
|
ethread::RecursiveLock lock(m_mutex);
|
|
//EWOL_DEBUG("Get glyph property for mode: " << _displayMode << " == > wrapping index : " << m_modeWraping[_displayMode]);
|
|
int32_t index = getIndex(_charcode, _displayMode);
|
|
if( index < 0
|
|
|| (size_t)index >= m_listElement[_displayMode].size() ) {
|
|
EWOL_ERROR(" Try to get glyph index inexistant ... == > return the index 0 ... id=" << index);
|
|
if (m_listElement[_displayMode].size() > 0) {
|
|
return &((m_listElement[_displayMode])[0]);
|
|
}
|
|
return &m_emptyGlyph;
|
|
}
|
|
//EWOL_ERROR(" index=" << index);
|
|
//EWOL_ERROR(" m_UVal=" << m_listElement[_displayMode][index].m_UVal);
|
|
//EWOL_ERROR(" m_glyphIndex=" << m_listElement[_displayMode][index].m_glyphIndex);
|
|
//EWOL_ERROR(" m_advance=" << m_listElement[_displayMode][index].m_advance);
|
|
//EWOL_ERROR(" m_bearing=" << m_listElement[_displayMode][index].m_bearing);
|
|
return &((m_listElement[_displayMode])[index]);
|
|
}
|
|
|