14 #ifdef MYGUI_USE_FREETYPE
17 # include FT_TRUETYPE_TABLES_H
19 # include FT_WINFONTS_H
21 #endif // MYGUI_USE_FREETYPE
26 #ifndef MYGUI_USE_FREETYPE
38 MYGUI_LOG(Error,
"ResourceTrueTypeFont: TrueType font '" <<
getResourceName() <<
"' disabled. Define MYGUI_USE_FREETYE if you need TrueType fonts.");
62 return std::vector<std::pair<Char, Char> >();
118 #else // MYGUI_USE_FREETYPE
123 void setMax(T& _var,
const T& _newValue)
125 if (_var < _newValue)
129 std::pair<const Char, const uint8> charMaskData[] =
137 const std::map<const Char, const uint8> charMask(charMaskData, charMaskData +
sizeof charMaskData /
sizeof(*charMaskData));
139 const uint8 charMaskBlack = (
const uint8)
'\x00';
140 const uint8 charMaskWhite = (
const uint8)
'\xFF';
142 template<
bool LAMode>
149 static size_t getNumBytes();
158 struct PixelBase<false>
160 static size_t getNumBytes()
173 *_dest++ = _luminance;
174 *_dest++ = _luminance;
175 *_dest++ = _luminance;
181 struct PixelBase<true>
183 static size_t getNumBytes()
196 *_dest++ = _luminance;
201 template<
bool LAMode,
bool FromSource = false,
bool Antialias = false>
202 struct Pixel : PixelBase<LAMode>
212 template<
bool LAMode,
bool Antialias>
213 struct Pixel<LAMode, false, Antialias> : PixelBase<LAMode>
218 PixelBase<LAMode>::set(_dest, _luminance, _alpha);
222 template<
bool LAMode>
223 struct Pixel<LAMode, true, false> : PixelBase<LAMode>
228 PixelBase<LAMode>::set(_dest, _luminance, *_source++);
232 template<
bool LAMode>
233 struct Pixel<LAMode, true, true> : PixelBase<LAMode>
238 PixelBase<LAMode>::set(_dest, *_source, *_source);
245 const int ResourceTrueTypeFont::mDefaultGlyphSpacing = 1;
246 const float ResourceTrueTypeFont::mDefaultTabWidth = 8.0f;
247 const float ResourceTrueTypeFont::mSelectedWidth = 1.0f;
248 const float ResourceTrueTypeFont::mCursorWidth = 2.0f;
253 mHinting(HintingUseNative),
259 mSubstituteCodePoint(static_cast<
Char>(FontCodeType::
NotDefined)),
261 mSubstituteGlyphInfo(nullptr),
268 if (mTexture !=
nullptr)
279 xml::ElementEnumerator node = _node->getElementEnumerator();
282 if (node->getName() ==
"Property")
284 const std::string& key = node->findAttribute(
"key");
285 const std::string& value = node->findAttribute(
"value");
288 else if (key ==
"Size")
290 else if (key ==
"Resolution")
292 else if (key ==
"Antialias")
294 else if (key ==
"TabWidth")
296 else if (key ==
"OffsetHeight")
298 else if (key ==
"SubstituteCode")
300 else if (key ==
"Distance")
302 else if (key ==
"Hinting")
304 else if (key ==
"SpaceWidth")
307 MYGUI_LOG(Warning, _node->findAttribute(
"type") <<
": Property '" << key <<
"' in font '" << _node->findAttribute(
"name") <<
"' is deprecated; remove it to use automatic calculation.");
309 else if (key ==
"CursorWidth")
311 MYGUI_LOG(Warning, _node->findAttribute(
"type") <<
": Property '" << key <<
"' in font '" << _node->findAttribute(
"name") <<
"' is deprecated; value ignored.");
314 else if (node->getName() ==
"Codes")
317 xml::ElementEnumerator range = node->getElementEnumerator();
318 while (range.next(
"Code"))
320 std::string range_value;
321 if (range->findAttribute(
"range", range_value))
323 std::vector<std::string> parse_range =
utility::split(range_value);
324 if (!parse_range.empty())
335 if (mCharMap.empty())
339 range = node->getElementEnumerator();
340 while (range.next(
"Code"))
342 std::string range_value;
343 if (range->findAttribute(
"hide", range_value))
345 std::vector<std::string> parse_range =
utility::split(range_value);
346 if (!parse_range.empty())
362 GlyphMap::iterator glyphIter = mGlyphMap.find(_id);
364 if (glyphIter != mGlyphMap.end())
366 return &glyphIter->second;
369 return mSubstituteGlyphInfo;
379 return mDefaultHeight;
390 std::vector<std::pair<Char, Char> > result;
392 if (!mCharMap.empty())
394 CharMap::const_iterator iter = mCharMap.begin(), endIter = mCharMap.end();
397 Char rangeBegin = iter->first, rangeEnd = rangeBegin;
400 for (++iter; iter != endIter; ++iter)
402 if (iter->first == rangeEnd + 1)
410 result.push_back(std::make_pair(rangeBegin, rangeEnd));
413 rangeBegin = rangeEnd = iter->first;
418 result.push_back(std::make_pair(rangeBegin, rangeEnd));
426 return mSubstituteCodePoint;
429 void ResourceTrueTypeFont::addCodePoint(
Char _codePoint)
431 mCharMap.insert(CharMap::value_type(_codePoint, 0));
434 void ResourceTrueTypeFont::removeCodePoint(
Char _codePoint)
436 mCharMap.erase(_codePoint);
441 CharMap::iterator positionHint = mCharMap.lower_bound(_first);
443 if (positionHint != mCharMap.begin())
446 for (
Char i = _first; i <= _second; ++i)
447 positionHint = mCharMap.insert(positionHint, CharMap::value_type(i, 0));
452 mCharMap.erase(mCharMap.lower_bound(_first), mCharMap.upper_bound(_second));
455 void ResourceTrueTypeFont::clearCodePoints()
462 if (mGlyphSpacing == -1)
463 mGlyphSpacing = mDefaultGlyphSpacing;
471 int init = (laMode ? 2 : 0) | (mAntialias ? 1 : 0);
476 ResourceTrueTypeFont::initialiseFreeType<false, false>();
479 ResourceTrueTypeFont::initialiseFreeType<false, true>();
482 ResourceTrueTypeFont::initialiseFreeType<true, false>();
485 ResourceTrueTypeFont::initialiseFreeType<true, true>();
490 template<
bool LAMode,
bool Antialias>
491 void ResourceTrueTypeFont::initialiseFreeType()
497 FT_Library ftLibrary;
499 if (FT_Init_FreeType(&ftLibrary) != 0)
500 MYGUI_EXCEPT(
"ResourceTrueTypeFont: Could not init the FreeType library!");
502 uint8* fontBuffer =
nullptr;
504 FT_Face ftFace = loadFace(ftLibrary, fontBuffer);
506 if (ftFace ==
nullptr)
520 int fontAscent = ftFace->size->metrics.ascender >> 6;
521 int fontDescent = -ftFace->size->metrics.descender >> 6;
523 TT_OS2* os2 = (TT_OS2*)FT_Get_Sfnt_Table(ftFace, ft_sfnt_os2);
527 setMax(fontAscent, os2->usWinAscent * ftFace->size->metrics.y_ppem / ftFace->units_per_EM);
528 setMax(fontDescent, os2->usWinDescent * ftFace->size->metrics.y_ppem / ftFace->units_per_EM);
530 setMax(fontAscent, os2->sTypoAscender * ftFace->size->metrics.y_ppem / ftFace->units_per_EM);
531 setMax(fontDescent, -os2->sTypoDescender * ftFace->size->metrics.y_ppem / ftFace->units_per_EM);
538 mDefaultHeight = fontAscent + fontDescent;
541 FT_Int32 ftLoadFlags;
545 case HintingForceAuto:
546 ftLoadFlags = FT_LOAD_FORCE_AUTOHINT;
548 case HintingDisableAuto:
549 ftLoadFlags = FT_LOAD_NO_AUTOHINT;
551 case HintingDisableAll:
554 ftLoadFlags = FT_LOAD_NO_HINTING | FT_LOAD_RENDER;
556 case HintingUseNative:
557 ftLoadFlags = FT_LOAD_DEFAULT;
565 GlyphHeightMap glyphHeightMap;
573 for (CharMap::iterator iter = mCharMap.begin(); iter != mCharMap.end(); )
575 const Char& codePoint = iter->first;
576 FT_UInt glyphIndex = FT_Get_Char_Index(ftFace, codePoint);
578 texWidth += createFaceGlyph(glyphIndex, codePoint, fontAscent, ftFace, ftLoadFlags, glyphHeightMap);
582 if (iter->second != 0)
585 mCharMap.erase(iter++);
594 if (mSpaceWidth != 0.0f)
596 texWidth += (int)std::ceil(mSpaceWidth) - (int)std::ceil(spaceGlyphInfo->width);
597 spaceGlyphInfo->width = mSpaceWidth;
598 spaceGlyphInfo->advance = mSpaceWidth;
602 if (mTabWidth == 0.0f)
603 mTabWidth = mDefaultTabWidth * spaceGlyphInfo->advance;
609 FT_UInt nextGlyphIndex = (FT_UInt)ftFace->num_glyphs;
611 float height = (
float)mDefaultHeight;
613 texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(
static_cast<Char>(
FontCodeType::Tab), 0.0f, 0.0f, mTabWidth, 0.0f, 0.0f), glyphHeightMap);
614 texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(
static_cast<Char>(
FontCodeType::Selected), mSelectedWidth, height, 0.0f, 0.0f, 0.0f), glyphHeightMap);
615 texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(
static_cast<Char>(
FontCodeType::SelectedBack), mSelectedWidth, height, 0.0f, 0.0f, 0.0f), glyphHeightMap);
616 texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(
static_cast<Char>(
FontCodeType::Cursor), mCursorWidth, height, 0.0f, 0.0f, 0.0f), glyphHeightMap);
629 mSubstituteGlyphInfo = &mGlyphMap.find(mSubstituteCodePoint)->second;
633 double averageGlyphHeight = 0.0;
635 for (GlyphHeightMap::const_iterator j = glyphHeightMap.begin(); j != glyphHeightMap.end(); ++j)
636 averageGlyphHeight += j->first * j->second.size();
638 averageGlyphHeight /= mGlyphMap.size();
651 while (texWidth > texHeight)
664 if (texHeight > texWidth * 2)
667 int texX = mGlyphSpacing;
668 int texY = mGlyphSpacing;
670 for (GlyphHeightMap::const_iterator j = glyphHeightMap.begin(); j != glyphHeightMap.end(); ++j)
672 for (GlyphHeightMap::mapped_type::const_iterator i = j->second.begin(); i != j->second.end(); ++i)
674 GlyphInfo& info = *i->second;
676 int glyphWidth = (int)std::ceil(info.width);
677 int glyphHeight = (int)std::ceil(info.height);
679 autoWrapGlyphPos(glyphWidth, texWidth, glyphHeight, texX, texY);
682 texX += mGlyphSpacing + glyphWidth;
688 while (texHeight > texWidth * 2);
703 mTexture->setInvalidateListener(
this);
707 if (texBuffer !=
nullptr)
710 for (
uint8* dest = texBuffer, * endDest = dest + texWidth * texHeight * Pixel<LAMode>::getNumBytes(); dest != endDest; )
711 Pixel<LAMode, false, false>::set(dest, charMaskWhite, charMaskBlack);
713 renderGlyphs<LAMode, Antialias>(glyphHeightMap, ftLibrary, ftFace, ftLoadFlags, texBuffer, texWidth, texHeight);
717 MYGUI_LOG(Info,
"ResourceTrueTypeFont: Font '" <<
getResourceName() <<
"' using texture size " << texWidth <<
" x " << texHeight <<
".");
718 MYGUI_LOG(Info,
"ResourceTrueTypeFont: Font '" <<
getResourceName() <<
"' using real height " << mDefaultHeight <<
" pixels.");
722 MYGUI_LOG(Error,
"ResourceTrueTypeFont: Error locking texture; pointer is nullptr.");
725 FT_Done_Face(ftFace);
726 FT_Done_FreeType(ftLibrary);
728 delete [] fontBuffer;
731 FT_Face ResourceTrueTypeFont::loadFace(
const FT_Library& _ftLibrary,
uint8*& _fontBuffer)
733 FT_Face result =
nullptr;
738 if (datastream ==
nullptr)
741 size_t fontBufferSize = datastream->
size();
742 _fontBuffer =
new uint8[fontBufferSize];
743 datastream->read(_fontBuffer, fontBufferSize);
746 datastream =
nullptr;
749 if (FT_New_Memory_Face(_ftLibrary, _fontBuffer, (FT_Long)fontBufferSize, -1, &result) != 0)
752 FT_Long numFaces = result->num_faces;
753 FT_Long faceIndex = 0;
756 if (FT_New_Memory_Face(_ftLibrary, _fontBuffer, (FT_Long)fontBufferSize, faceIndex, &result) != 0)
759 if (result->face_flags & FT_FACE_FLAG_SCALABLE)
763 FT_F26Dot6 ftSize = (FT_F26Dot6)(mSize * (1 << 6));
765 if (FT_Set_Char_Size(result, ftSize, 0, mResolution, mResolution) != 0)
769 if (mCharMap.empty())
775 FT_WinFNT_HeaderRec fnt;
779 std::map<float, FT_Long> faceSizes;
783 if (FT_Get_WinFNT_Header(result, &fnt) != 0)
786 faceSizes.insert(std::make_pair((
float)fnt.nominal_point_size * fnt.vertical_resolution / mResolution, faceIndex));
788 FT_Done_Face(result);
790 if (++faceIndex < numFaces)
791 if (FT_New_Memory_Face(_ftLibrary, _fontBuffer, (FT_Long)fontBufferSize, faceIndex, &result) != 0)
794 while (faceIndex < numFaces);
796 std::map<float, FT_Long>::const_iterator iter = faceSizes.lower_bound(mSize);
798 faceIndex = (iter != faceSizes.end()) ? iter->second : faceSizes.rbegin()->second;
800 if (FT_New_Memory_Face(_ftLibrary, _fontBuffer, (FT_Long)fontBufferSize, faceIndex, &result) != 0)
805 if (FT_Select_Size(result, 0) != 0)
810 if (mCharMap.empty())
817 if (fnt.charset == FT_WinFNT_ID_CP1252)
829 if (fnt.charset == FT_WinFNT_ID_CP1252)
839 void ResourceTrueTypeFont::autoWrapGlyphPos(
int _glyphWidth,
int _texWidth,
int _lineHeight,
int& _texX,
int& _texY)
841 if (_glyphWidth > 0 && _texX + mGlyphSpacing + _glyphWidth > _texWidth)
843 _texX = mGlyphSpacing;
844 _texY += mGlyphSpacing + _lineHeight;
848 GlyphInfo ResourceTrueTypeFont::createFaceGlyphInfo(
Char _codePoint,
int _fontAscent, FT_GlyphSlot _glyph)
850 float bearingX = _glyph->metrics.horiBearingX / 64.0f;
858 std::max((
float)_glyph->bitmap.width, _glyph->metrics.width / 64.0f),
859 std::max((
float)_glyph->bitmap.rows, _glyph->metrics.height / 64.0f),
860 (_glyph->advance.x / 64.0f) - bearingX,
862 std::floor(_fontAscent - (_glyph->metrics.horiBearingY / 64.0f) - mOffsetHeight));
865 int ResourceTrueTypeFont::createGlyph(FT_UInt _glyphIndex,
const GlyphInfo& _glyphInfo, GlyphHeightMap& _glyphHeightMap)
867 int width = (int)std::ceil(_glyphInfo.width);
868 int height = (int)std::ceil(_glyphInfo.height);
870 mCharMap[_glyphInfo.codePoint] = _glyphIndex;
871 GlyphInfo& info = mGlyphMap.insert(GlyphMap::value_type(_glyphInfo.codePoint, _glyphInfo)).first->second;
872 _glyphHeightMap[(FT_Pos)height].insert(std::make_pair(_glyphIndex, &info));
874 return (width > 0) ? mGlyphSpacing + width : 0;
877 int ResourceTrueTypeFont::createFaceGlyph(FT_UInt _glyphIndex,
Char _codePoint,
int _fontAscent,
const FT_Face& _ftFace, FT_Int32 _ftLoadFlags, GlyphHeightMap& _glyphHeightMap)
879 if (mGlyphMap.find(_codePoint) == mGlyphMap.end())
881 if (FT_Load_Glyph(_ftFace, _glyphIndex, _ftLoadFlags) == 0)
882 return createGlyph(_glyphIndex, createFaceGlyphInfo(_codePoint, _fontAscent, _ftFace->glyph), _glyphHeightMap);
884 MYGUI_LOG(Warning,
"ResourceTrueTypeFont: Cannot load glyph " << _glyphIndex <<
" for character " << _codePoint <<
" in font '" <<
getResourceName() <<
"'.");
888 mCharMap[_codePoint] = _glyphIndex;
894 template<
bool LAMode,
bool Antialias>
895 void ResourceTrueTypeFont::renderGlyphs(
const GlyphHeightMap& _glyphHeightMap,
const FT_Library& _ftLibrary,
const FT_Face& _ftFace, FT_Int32 _ftLoadFlags,
uint8* _texBuffer,
int _texWidth,
int _texHeight)
898 FT_Bitmap_New(&ftBitmap);
900 int texX = mGlyphSpacing, texY = mGlyphSpacing;
902 for (GlyphHeightMap::const_iterator j = _glyphHeightMap.begin(); j != _glyphHeightMap.end(); ++j)
904 for (GlyphHeightMap::mapped_type::const_iterator i = j->second.begin(); i != j->second.end(); ++i)
906 GlyphInfo& info = *i->second;
908 switch (info.codePoint)
913 renderGlyph<LAMode, false, false>(info, charMaskWhite, charMaskBlack, charMask.find(info.codePoint)->second, j->first, _texBuffer, _texWidth, _texHeight, texX, texY);
918 glyphInfo->width = 0.0f;
919 glyphInfo->uvRect.right = glyphInfo->uvRect.left;
925 renderGlyph<LAMode, false, false>(info, charMaskWhite, charMaskBlack, charMask.find(info.codePoint)->second, j->first, _texBuffer, _texWidth, _texHeight, texX, texY);
929 if (FT_Load_Glyph(_ftFace, i->first, _ftLoadFlags | FT_LOAD_RENDER) == 0)
931 if (_ftFace->glyph->bitmap.buffer !=
nullptr)
933 uint8* glyphBuffer =
nullptr;
935 switch (_ftFace->glyph->bitmap.pixel_mode)
937 case FT_PIXEL_MODE_GRAY:
938 glyphBuffer = _ftFace->glyph->bitmap.buffer;
941 case FT_PIXEL_MODE_MONO:
943 if (FT_Bitmap_Convert(_ftLibrary, &_ftFace->glyph->bitmap, &ftBitmap, 1) == 0)
946 for (
uint8* p = ftBitmap.buffer, * endP = p + ftBitmap.width * ftBitmap.rows; p != endP; ++p)
949 glyphBuffer = ftBitmap.buffer;
954 if (glyphBuffer !=
nullptr)
955 renderGlyph<LAMode, true, Antialias>(info, charMaskWhite, charMaskWhite, charMaskWhite, j->first, _texBuffer, _texWidth, _texHeight, texX, texY, glyphBuffer);
960 MYGUI_LOG(Warning,
"ResourceTrueTypeFont: Cannot render glyph " << i->first <<
" for character " << info.codePoint <<
" in font '" <<
getResourceName() <<
"'.");
967 FT_Bitmap_Done(_ftLibrary, &ftBitmap);
970 template<
bool LAMode,
bool UseBuffer,
bool Antialias>
971 void ResourceTrueTypeFont::renderGlyph(GlyphInfo& _info,
uint8 _luminance0,
uint8 _luminance1,
uint8 _alpha,
int _lineHeight,
uint8* _texBuffer,
int _texWidth,
int _texHeight,
int& _texX,
int& _texY,
uint8* _glyphBuffer)
973 int width = (int)std::ceil(_info.width);
974 int height = (int)std::ceil(_info.height);
976 autoWrapGlyphPos(width, _texWidth, _lineHeight, _texX, _texY);
978 uint8* dest = _texBuffer + (_texY * _texWidth + _texX) * Pixel<LAMode>::getNumBytes();
981 ptrdiff_t destNextRow = (_texWidth - width) * Pixel<LAMode>::getNumBytes();
983 for (
int j = height; j > 0; --j)
986 for (i = width; i > 1; i -= 2)
988 Pixel<LAMode, UseBuffer, Antialias>::set(dest, _luminance0, _alpha, _glyphBuffer);
989 Pixel<LAMode, UseBuffer, Antialias>::set(dest, _luminance1, _alpha, _glyphBuffer);
993 Pixel<LAMode, UseBuffer, Antialias>::set(dest, _luminance0, _alpha, _glyphBuffer);
999 _info.uvRect.left = (float)_texX / _texWidth;
1000 _info.uvRect.top = (float)_texY / _texHeight;
1001 _info.uvRect.right = (float)(_texX + _info.width) / _texWidth;
1002 _info.uvRect.bottom = (float)(_texY + _info.height) / _texHeight;
1005 _texX += mGlyphSpacing + width;
1020 mResolution = _value;
1025 if (_value ==
"use_native")
1026 mHinting = HintingUseNative;
1027 else if (_value ==
"force_auto")
1028 mHinting = HintingForceAuto;
1029 else if (_value ==
"disable_auto")
1030 mHinting = HintingDisableAuto;
1031 else if (_value ==
"disable_all")
1032 mHinting = HintingDisableAll;
1034 mHinting = HintingUseNative;
1039 mAntialias = _value;
1049 mOffsetHeight = _value;
1054 mSubstituteCodePoint = _value;
1059 mGlyphSpacing = _value;
1062 #endif // MYGUI_USE_FREETYPE